using System; using System.Collections.Generic; using Unity.BossRoom.Utils; using Unity.Netcode; using UnityEngine; using UUnity.BossRoom.ConnectionManagement; using VContainer; namespace Unity.BossRoom.ConnectionManagement { public enum ConnectStatus { Undefined, Success, //client successfully connected. This may also be a successful reconnect. ServerFull, //can't join, server is already at capacity. LoggedInAgain, //logged in on a separate client, causing this one to be kicked out. UserRequestedDisconnect, //Intentional Disconnect triggered by the user. GenericDisconnect, //server disconnected, but no specific reason given. Reconnecting, //client lost connection and is attempting to reconnect. IncompatibleBuildType, //client build type is incompatible with server. HostEndedSession, //host intentionally ended the session. StartHostFailed, // server failed to bind StartClientFailed // failed to connect to server and/or invalid network endpoint } public struct ReconnectMessage { public int CurrentAttempt; public int MaxAttempt; public ReconnectMessage(int currentAttempt, int maxAttempt) { CurrentAttempt = currentAttempt; MaxAttempt = maxAttempt; } } public struct ConnectionEventMessage : INetworkSerializeByMemcpy { public ConnectStatus ConnectStatus; public FixedPlayerName PlayerName; } [Serializable] public class ConnectionPayload { public string playerId; public string playerName; public bool isDebug; } /// /// This state machine handles connection through the NetworkManager. It is responsible for listening to /// NetworkManger callbacks and other outside calls and redirecting them to the current ConnectionState object. /// public class ConnectionManager : MonoBehaviour { ConnectionState m_CurrentState; [Inject] NetworkManager m_NetworkManager; public NetworkManager NetworkManager => m_NetworkManager; [SerializeField] int m_NbReconnectAttempts = 2; public int NbReconnectAttempts => m_NbReconnectAttempts; [Inject] IObjectResolver m_Resolver; public int MaxConnectedPlayers = 8; internal readonly OfflineState m_Offline = new OfflineState(); internal readonly ClientConnectingState m_ClientConnecting = new ClientConnectingState(); internal readonly ClientConnectedState m_ClientConnected = new ClientConnectedState(); internal readonly ClientReconnectingState m_ClientReconnecting = new ClientReconnectingState(); internal readonly StartingHostState m_StartingHost = new StartingHostState(); internal readonly HostingState m_Hosting = new HostingState(); void Awake() { DontDestroyOnLoad(gameObject); } void Start() { List states = new() { m_Offline, m_ClientConnecting, m_ClientConnected, m_ClientReconnecting, m_StartingHost, m_Hosting }; foreach (var connectionState in states) { m_Resolver.Inject(connectionState); } m_CurrentState = m_Offline; NetworkManager.OnClientConnectedCallback += OnClientConnectedCallback; NetworkManager.OnClientDisconnectCallback += OnClientDisconnectCallback; NetworkManager.OnServerStarted += OnServerStarted; NetworkManager.ConnectionApprovalCallback += ApprovalCheck; NetworkManager.OnTransportFailure += OnTransportFailure; NetworkManager.OnServerStopped += OnServerStopped; } void OnDestroy() { NetworkManager.OnClientConnectedCallback -= OnClientConnectedCallback; NetworkManager.OnClientDisconnectCallback -= OnClientDisconnectCallback; NetworkManager.OnServerStarted -= OnServerStarted; NetworkManager.ConnectionApprovalCallback -= ApprovalCheck; NetworkManager.OnTransportFailure -= OnTransportFailure; NetworkManager.OnServerStopped -= OnServerStopped; } internal void ChangeState(ConnectionState nextState) { Debug.Log($"{name}: Changed connection state from {m_CurrentState.GetType().Name} to {nextState.GetType().Name}."); if (m_CurrentState != null) { m_CurrentState.Exit(); } m_CurrentState = nextState; m_CurrentState.Enter(); } void OnClientDisconnectCallback(ulong clientId) { m_CurrentState.OnClientDisconnect(clientId); } void OnClientConnectedCallback(ulong clientId) { m_CurrentState.OnClientConnected(clientId); } void OnServerStarted() { m_CurrentState.OnServerStarted(); } void ApprovalCheck(NetworkManager.ConnectionApprovalRequest request, NetworkManager.ConnectionApprovalResponse response) { m_CurrentState.ApprovalCheck(request, response); } void OnTransportFailure() { m_CurrentState.OnTransportFailure(); } void OnServerStopped(bool _) // we don't need this parameter as the ConnectionState already carries the relevant information { m_CurrentState.OnServerStopped(); } public void StartClientLobby(string playerName) { m_CurrentState.StartClientLobby(playerName); } public void StartClientIp(string playerName, string ipaddress, int port) { m_CurrentState.StartClientIP(playerName, ipaddress, port); } public void StartHostLobby(string playerName) { m_CurrentState.StartHostLobby(playerName); } public void StartHostIp(string playerName, string ipaddress, int port) { m_CurrentState.StartHostIP(playerName, ipaddress, port); } public void RequestShutdown() { m_CurrentState.OnUserRequestedShutdown(); } } }