KitchenChaos/Assets/Scripts/KitchenGameMultiplayer.cs

207 lines
8.5 KiB
C#

using System;
using System.Collections.Generic;
using Unity.Netcode;
using Unity.Services.Authentication;
using UnityEngine;
using UnityEngine.SceneManagement;
using Random = UnityEngine.Random;
public class KitchenGameMultiplayer : NetworkBehaviour {
public const int MaxPlayerAmount = 4;
private const string playerPrefsPlayerNameMultiplayer = "PlayerNameMultiplayer";
[SerializeField] private KitchenObjectListSO KitchenObjectListSO;
[SerializeField] private List<Color> PlayerColorList;
private NetworkList<PlayerData> playerDataNetworkList;
private string playerName;
public static KitchenGameMultiplayer Instance { get; private set; }
public string PlayerName {
get => playerName;
set {
playerName = value;
PlayerPrefs.SetString(playerPrefsPlayerNameMultiplayer, value);
}
}
private void Awake() {
Instance = this;
DontDestroyOnLoad(gameObject);
PlayerName = PlayerPrefs.GetString(playerPrefsPlayerNameMultiplayer, "PlayerName" + Random.Range(100, 1000));
playerDataNetworkList = new();
playerDataNetworkList.OnListChanged += PlayerDataNetworkList_OnListChanged;
}
private void PlayerDataNetworkList_OnListChanged(NetworkListEvent<PlayerData> changeevent) => OnPlayerDataNetworkListChanged?.Invoke(this, EventArgs.Empty);
public event EventHandler OnTryingToJoinGame;
public event EventHandler OnFailToJoinGame;
public event EventHandler OnPlayerDataNetworkListChanged;
public void SpawnKitchenObject(KitchenObjectSO kitchenObjectSO, IKitchenObjectParent kitchenObjectParent)
=> SpawnKitchenObjectServerRpc(GetKitchenObjectSOIndex(kitchenObjectSO), kitchenObjectParent.GetNetworkObject());
public void StartHost() {
NetworkManager.Singleton.ConnectionApprovalCallback += NetworkManager_ConnectionApprovalCallback;
NetworkManager.Singleton.OnClientConnectedCallback += NetworkManager_Client_OnClientConnectedCallback;
NetworkManager.Singleton.OnClientDisconnectCallback += NetworkManager_Server_OnClientDisconnectCallback;
NetworkManager.Singleton.StartHost();
}
private void NetworkManager_Client_OnClientConnectedCallback(ulong clientId) {
playerDataNetworkList.Add(new() { ClientId = clientId, ColorId = GetFirstUnusedColorId() });
SetPlayerNameServerRpc(PlayerName);
SetPlayerIdServerRpc(AuthenticationService.Instance.PlayerId);
}
private void NetworkManager_Server_OnClientDisconnectCallback(ulong clientId) {
for (int i = 0; i < playerDataNetworkList.Count; i++) {
PlayerData playerData = playerDataNetworkList[i];
if (playerData.ClientId == clientId) playerDataNetworkList.RemoveAt(i);
}
}
private int GetFirstUnusedColorId() {
for (int i = 0; i <= playerDataNetworkList.Count; i++)
if (IsColorAvailable(i))
return i;
return -1;
}
private void NetworkManager_ConnectionApprovalCallback(NetworkManager.ConnectionApprovalRequest request, NetworkManager.ConnectionApprovalResponse response) {
if (SceneManager.GetActiveScene().name != Loader.Scene.CharacterSelectScene.ToString()) {
response.Approved = false;
response.Reason = "Game has already started!";
return;
}
if (NetworkManager.Singleton.ConnectedClientsIds.Count >= MaxPlayerAmount) {
response.Approved = false;
response.Reason = "Game is full!";
return;
}
response.Approved = true;
}
public void StartClient() {
OnTryingToJoinGame?.Invoke(this, EventArgs.Empty);
NetworkManager.Singleton.OnClientDisconnectCallback += NetworkManager_Client_OnClientDisconnectCallback;
NetworkManager.Singleton.OnClientConnectedCallback += NetworkManager_Client_OnClientConnectCallback;
NetworkManager.Singleton.StartClient();
}
private void NetworkManager_Client_OnClientConnectCallback(ulong clientId) {
SetPlayerNameServerRpc(PlayerName);
SetPlayerIdServerRpc(AuthenticationService.Instance.PlayerId);
}
[ServerRpc(RequireOwnership = false)]
private void SetPlayerNameServerRpc(string newPlayerName, ServerRpcParams serverRpcParams = default) {
int playerDataIndex = GetPlayerDataIndexFromClientId(serverRpcParams.Receive.SenderClientId);
PlayerData playerData = playerDataNetworkList[playerDataIndex];
playerData.PlayerName = newPlayerName;
playerDataNetworkList[playerDataIndex] = playerData;
}
[ServerRpc(RequireOwnership = false)]
private void SetPlayerIdServerRpc(string newPlayerId, ServerRpcParams serverRpcParams = default) {
int playerDataIndex = GetPlayerDataIndexFromClientId(serverRpcParams.Receive.SenderClientId);
PlayerData playerData = playerDataNetworkList[playerDataIndex];
playerData.PlayerId = newPlayerId;
playerDataNetworkList[playerDataIndex] = playerData;
}
private void NetworkManager_Client_OnClientDisconnectCallback(ulong clientId) => OnFailToJoinGame?.Invoke(this, EventArgs.Empty);
[ServerRpc(RequireOwnership = false)]
private void SpawnKitchenObjectServerRpc(int kitchenObjectSOIndex, NetworkObjectReference kitchenObjectParentNetworkObjectReference) {
KitchenObjectSO kitchenObjectSO = GetKitchenObjectSOFromIndex(kitchenObjectSOIndex);
kitchenObjectParentNetworkObjectReference.TryGet(out NetworkObject kitchenObjectParentNetworkObject);
IKitchenObjectParent kitchenObjectParent = kitchenObjectParentNetworkObject.GetComponent<IKitchenObjectParent>();
if (kitchenObjectParent.KitchenObject is not null) return; //Parent already spawned an object
Transform kitchenObjectTransform = Instantiate(kitchenObjectSO.Prefab);
NetworkObject kitchenObjectNetworkObject = kitchenObjectTransform.GetComponent<NetworkObject>();
kitchenObjectNetworkObject.Spawn(true);
KitchenObject kitchenObject = kitchenObjectTransform.GetComponent<KitchenObject>();
kitchenObject.SetKitchenObjectParent(kitchenObjectParent);
Debug.Log($"Will spawn {kitchenObjectSO.ObjectName} on {kitchenObjectParent}...");
}
public int GetKitchenObjectSOIndex(KitchenObjectSO kitchenObjectSO) => KitchenObjectListSO.kitchenObjectSOList.IndexOf(kitchenObjectSO);
public KitchenObjectSO GetKitchenObjectSOFromIndex(int kitchenObjectSOIndex) => KitchenObjectListSO.kitchenObjectSOList[kitchenObjectSOIndex];
public void DestroyKitchenObject(KitchenObject kitchenObject) => DestroyKitchenObjectServerRpc(kitchenObject.NetworkObject);
[ServerRpc(RequireOwnership = false)]
private void DestroyKitchenObjectServerRpc(NetworkObjectReference kitchenObjectNetworkObjectReference) {
kitchenObjectNetworkObjectReference.TryGet(out NetworkObject kitchenObjectNetworkObject);
if (kitchenObjectNetworkObject is null) return; // This object is already destroyed
KitchenObject kitchenObject = kitchenObjectNetworkObject.GetComponent<KitchenObject>();
ClearKitchenObjectOnParentClientRpc(kitchenObjectNetworkObjectReference);
kitchenObject.DestroySelf();
}
[ClientRpc]
private void ClearKitchenObjectOnParentClientRpc(NetworkObjectReference kitchenObjectNetworkObjectReference) {
kitchenObjectNetworkObjectReference.TryGet(out NetworkObject kitchenObjectNetworkObject);
KitchenObject kitchenObject = kitchenObjectNetworkObject.GetComponent<KitchenObject>();
kitchenObject.ClearKitchenObjectOnParent();
}
public bool IsPlayerIndexConnected(int playerIndex) => playerIndex < playerDataNetworkList.Count;
public PlayerData GetPlayerDataFromPlayerIndex(int playerIndex) => playerDataNetworkList[playerIndex];
public Color GetPlayerColor(int colorId) => PlayerColorList[colorId];
public PlayerData GetPlayerDataFromClientId(ulong clientId) {
foreach (PlayerData playerData in playerDataNetworkList)
if (playerData.ClientId == clientId)
return playerData;
return default;
}
public PlayerData GetPlayerData() => GetPlayerDataFromClientId(NetworkManager.Singleton.LocalClientId);
public void ChangePlayerColor(int colorId) => ChangePlayerColorServerRpc(colorId);
[ServerRpc(RequireOwnership = false)]
private void ChangePlayerColorServerRpc(int colorId, ServerRpcParams serverRpcParams = default) {
if (!IsColorAvailable(colorId)) return;
int playerDataIndeX = GetPlayerDataIndexFromClientId(serverRpcParams.Receive.SenderClientId);
PlayerData playerData = playerDataNetworkList[playerDataIndeX];
playerData.ColorId = colorId;
playerDataNetworkList[playerDataIndeX] = playerData;
}
private bool IsColorAvailable(int colorId) {
foreach (PlayerData playerData in playerDataNetworkList)
if (playerData.ColorId == colorId)
return false;
return true;
}
public int GetPlayerDataIndexFromClientId(ulong clientId) {
for (int i = 0; i < playerDataNetworkList.Count; i++)
if (playerDataNetworkList[i].ClientId == clientId)
return i;
return -1;
}
public void KickPlayer(ulong clientId) {
NetworkManager.Singleton.DisconnectClient(clientId);
NetworkManager_Server_OnClientDisconnectCallback(clientId);
}
}