mirror of
https://github.com/Leahnaya/TheKingsRace.git
synced 2026-03-23 02:04:17 -05:00
266 lines
7.9 KiB
C#
266 lines
7.9 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Text;
|
|
using MLAPI;
|
|
using MLAPI.SceneManagement;
|
|
using MLAPI.Spawning;
|
|
using UnityEngine;
|
|
using UnityEngine.SceneManagement;
|
|
|
|
public class ServerGameNetPortal : MonoBehaviour {
|
|
|
|
[Header("Settings")]
|
|
[SerializeField] private int maxPlayers = 3;
|
|
|
|
public static ServerGameNetPortal Instance => instance;
|
|
private static ServerGameNetPortal instance;
|
|
|
|
public Dictionary<string, PlayerData> clientData;
|
|
public Dictionary<ulong, string> clientIdToGuid;
|
|
private Dictionary<ulong, int> clientSceneMap;
|
|
private bool gameInProgress;
|
|
|
|
private const int MaxConnectionPayload = 1024;
|
|
|
|
private GameNetPortal gameNetPortal;
|
|
|
|
private int runnersQuitEarly = 0;
|
|
|
|
private void Awake()
|
|
{
|
|
if (instance != null && instance != this)
|
|
{
|
|
Destroy(gameObject);
|
|
return;
|
|
}
|
|
|
|
instance = this;
|
|
DontDestroyOnLoad(gameObject);
|
|
}
|
|
|
|
private void Start()
|
|
{
|
|
gameNetPortal = GetComponent<GameNetPortal>();
|
|
gameNetPortal.OnNetworkReadied += HandleNetworkReadied;
|
|
|
|
NetworkManager.Singleton.ConnectionApprovalCallback += ApprovalCheck;
|
|
NetworkManager.Singleton.OnServerStarted += HandleServerStarted;
|
|
|
|
clientData = new Dictionary<string, PlayerData>();
|
|
clientIdToGuid = new Dictionary<ulong, string>();
|
|
clientSceneMap = new Dictionary<ulong, int>();
|
|
}
|
|
|
|
private void OnDestroy()
|
|
{
|
|
if (gameNetPortal == null) { return; }
|
|
|
|
gameNetPortal.OnNetworkReadied -= HandleNetworkReadied;
|
|
|
|
if (NetworkManager.Singleton == null) { return; }
|
|
|
|
NetworkManager.Singleton.ConnectionApprovalCallback -= ApprovalCheck;
|
|
NetworkManager.Singleton.OnServerStarted -= HandleServerStarted;
|
|
}
|
|
|
|
public PlayerData? GetPlayerData(ulong clientId)
|
|
{
|
|
if (clientIdToGuid.TryGetValue(clientId, out string clientGuid))
|
|
{
|
|
if (clientData.TryGetValue(clientGuid, out PlayerData playerData))
|
|
{
|
|
return playerData;
|
|
}
|
|
else
|
|
{
|
|
Debug.LogWarning($"No player data found for client id: {clientId}");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Debug.LogWarning($"No client guid found for client id: {clientId}");
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public void StartGame()
|
|
{
|
|
gameInProgress = true;
|
|
|
|
runnersQuitEarly = 0;
|
|
|
|
// Load the mountain level. Can add code to swap which level here
|
|
NetworkSceneManager.SwitchScene("Game-Mountain");
|
|
}
|
|
|
|
public void EndRound()
|
|
{
|
|
gameInProgress = false;
|
|
|
|
// Remove any networked objects that might persist back to the Lobby
|
|
//ObjectCleanup.Instance.DestroyPersistingNetObjectsServerRPC();
|
|
|
|
NetworkSceneManager.SwitchScene("Lobby");
|
|
}
|
|
|
|
private void HandleNetworkReadied()
|
|
{
|
|
if (!NetworkManager.Singleton.IsServer) { return; }
|
|
|
|
gameNetPortal.OnUserDisconnectRequested += HandleUserDisconnectRequested;
|
|
NetworkManager.Singleton.OnClientDisconnectCallback += HandleClientDisconnect;
|
|
gameNetPortal.OnClientSceneChanged += HandleClientSceneChanged;
|
|
|
|
NetworkSceneManager.SwitchScene("Lobby");
|
|
|
|
if (NetworkManager.Singleton.IsHost)
|
|
{
|
|
clientSceneMap[NetworkManager.Singleton.LocalClientId] = SceneManager.GetActiveScene().buildIndex;
|
|
}
|
|
}
|
|
|
|
private void HandleClientDisconnect(ulong clientId) {
|
|
bool kingLeft = false;
|
|
|
|
clientSceneMap.Remove(clientId);
|
|
|
|
if (clientIdToGuid.TryGetValue(clientId, out string guid))
|
|
{
|
|
clientIdToGuid.Remove(clientId);
|
|
|
|
if (clientData[guid].ClientId == clientId) {
|
|
// Check for who specifically discornnected (only if in game)
|
|
if (gameInProgress == true) {
|
|
// King left game early
|
|
if (clientData[guid].IsKing) {
|
|
kingLeft = true;
|
|
} else { // Runner left early
|
|
runnersQuitEarly++;
|
|
}
|
|
}
|
|
|
|
clientData.Remove(guid);
|
|
}
|
|
}
|
|
|
|
if (clientId == NetworkManager.Singleton.LocalClientId)
|
|
{
|
|
gameNetPortal.OnUserDisconnectRequested -= HandleUserDisconnectRequested;
|
|
NetworkManager.Singleton.OnClientDisconnectCallback -= HandleClientDisconnect;
|
|
gameNetPortal.OnClientSceneChanged -= HandleClientSceneChanged;
|
|
}
|
|
|
|
// Players Left Early and the game must be stopped early
|
|
// - If the king leaves or if both runners leave
|
|
if (kingLeft || runnersQuitEarly == 2) {
|
|
EndRound();
|
|
}
|
|
}
|
|
|
|
private void HandleClientSceneChanged(ulong clientId, int sceneIndex)
|
|
{
|
|
clientSceneMap[clientId] = sceneIndex;
|
|
}
|
|
|
|
private void HandleUserDisconnectRequested()
|
|
{
|
|
HandleClientDisconnect(NetworkManager.Singleton.LocalClientId);
|
|
|
|
NetworkManager.Singleton.StopHost();
|
|
|
|
ClearData();
|
|
|
|
SceneManager.LoadScene("TitleScene");
|
|
}
|
|
|
|
private void HandleServerStarted()
|
|
{
|
|
if (!NetworkManager.Singleton.IsHost) { return; }
|
|
|
|
string clientGuid = Guid.NewGuid().ToString();
|
|
string playerName = PlayerPrefs.GetString("PlayerName", "Missing Name");
|
|
|
|
clientData.Add(clientGuid, new PlayerData(playerName, NetworkManager.Singleton.LocalClientId));
|
|
clientIdToGuid.Add(NetworkManager.Singleton.LocalClientId, clientGuid);
|
|
}
|
|
|
|
private void ClearData()
|
|
{
|
|
clientData.Clear();
|
|
clientIdToGuid.Clear();
|
|
clientSceneMap.Clear();
|
|
|
|
gameInProgress = false;
|
|
}
|
|
|
|
private void ApprovalCheck(byte[] connectionData, ulong clientId, NetworkManager.ConnectionApprovedDelegate callback)
|
|
{
|
|
if (connectionData.Length > MaxConnectionPayload)
|
|
{
|
|
callback(false, 0, false, null, null);
|
|
return;
|
|
}
|
|
|
|
string payload = Encoding.UTF8.GetString(connectionData);
|
|
var connectionPayload = JsonUtility.FromJson<ConnectionPayload>(payload);
|
|
|
|
ConnectStatus gameReturnStatus = ConnectStatus.Success;
|
|
|
|
// This stops us from running multiple standalone builds since
|
|
// they disconnect eachother when trying to join
|
|
//
|
|
// if (clientData.ContainsKey(connectionPayload.clientGUID))
|
|
// {
|
|
// ulong oldClientId = clientData[connectionPayload.clientGUID].ClientId;
|
|
// StartCoroutine(WaitToDisconnectClient(oldClientId, ConnectStatus.LoggedInAgain));
|
|
// }
|
|
|
|
if (gameInProgress)
|
|
{
|
|
gameReturnStatus = ConnectStatus.GameInProgress;
|
|
}
|
|
else if (clientData.Count >= maxPlayers)
|
|
{
|
|
gameReturnStatus = ConnectStatus.ServerFull;
|
|
}
|
|
|
|
if (gameReturnStatus == ConnectStatus.Success)
|
|
{
|
|
clientSceneMap[clientId] = connectionPayload.clientScene;
|
|
clientIdToGuid[clientId] = connectionPayload.clientGUID;
|
|
clientData[connectionPayload.clientGUID] = new PlayerData(connectionPayload.playerName, clientId);
|
|
}
|
|
|
|
callback(false, 0, true, null, null);
|
|
|
|
gameNetPortal.ServerToClientConnectResult(clientId, gameReturnStatus);
|
|
|
|
if (gameReturnStatus != ConnectStatus.Success)
|
|
{
|
|
StartCoroutine(WaitToDisconnectClient(clientId, gameReturnStatus));
|
|
}
|
|
}
|
|
|
|
private IEnumerator WaitToDisconnectClient(ulong clientId, ConnectStatus reason)
|
|
{
|
|
gameNetPortal.ServerToClientSetDisconnectReason(clientId, reason);
|
|
|
|
yield return new WaitForSeconds(0);
|
|
|
|
KickClient(clientId);
|
|
}
|
|
|
|
private void KickClient(ulong clientId)
|
|
{
|
|
NetworkObject networkObject = NetworkSpawnManager.GetPlayerNetworkObject(clientId);
|
|
if (networkObject != null)
|
|
{
|
|
networkObject.Despawn(true);
|
|
}
|
|
|
|
NetworkManager.Singleton.DisconnectClient(clientId);
|
|
}
|
|
}
|