207 lines
8.5 KiB
C#
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);
|
|
}
|
|
} |