/// <summary>/// An abstract class that summarizes common processing when implementing lobbies/// Since MonoBehaviour is inherited, it can be inherited as it is./// </summary>[Serializable]publicabstractclassLobbyBase:SingletonNetworkPersistent<LobbyBase>{/// <summary>/// Payload used when connecting to the host./// </summary>[Serializable]publicclassPayloads{publicstringversion;publicstringpassword;}/// <summary>/// Lobby data to be displayed in the lobby list./// </summary>[Serializable]publicclassLobbyData{publicstringname;publicboolhasPassword;publicintcurrentMembers;publicintmaxMembers;}/// <summary>/// Minimum and maximum number of members in the lobby./// </summary>publicconstintMIN_MEMBERS=2;publicconstintMAX_MEMBERS=10;/// <summary>/// Max number of members in the lobby./// (Can only be set by the host.)/// (It will not be an error if the client sets it, but it will be ignored.)/// </summary>/// <exception cref="ArgumentOutOfRangeException">/// Throws an "ArgumentOutOfRangeException" if the number is set to less than the number of clients already connected./// Also, values less than MIN_MEMBERS or greater than MAX_MEMBERS are clamped./// </exception>publicvirtualintMaxMembers{get=>maxMembers;set{if(IsHost){if(NetworkManager.Singleton.ConnectedClients.Count>value){thrownewArgumentOutOfRangeException(nameof(maxMembers),"MaxMembers must be greater than the number of connected clients.");}}maxMembers=ClampMaxMembers(value);}}/// <summary>/// Payload used when connecting to the host./// </summary>publicPayloadsPayload{get;set;}/// <summary>/// Disconnect scene to be loaded when disconnected from the host./// </summary>publicLoadingSceneManager.SceneNameDisconnectScene{get;set;}=LoadingSceneManager.SceneName.Title;/// <summary>/// Disconnect reason to be displayed when disconnected from the host./// </summary>publicstringDisconnectReason{get;set;}="Disconnected from the host.";/// <summary>/// Is already set up./// </summary>publicboolIsSetUp{get;privateset;}=false;/// <summary>/// Stores lobby search results./// </summary>publicList<LobbyData>LobbyList{get;}=new();privateintmaxMembers=MIN_MEMBERS;/// <summary>/// Clamp the number of members to the minimum and maximum values./// </summary>/// <param name="members"></param>/// <returns></returns>publicstaticintClampMaxMembers(intmembers)=>Mathf.Clamp(members,MIN_MEMBERS,MAX_MEMBERS);//==================================================// 1. For host, it must be called first.//==================================================publicvirtualboolSetup(boolisApproval,Payloadspayload){if(IsSetUp){thrownewInvalidOperationException("Already set up.");}try{usingvarCheckInternet=newWebClient();using(CheckInternet.OpenRead("http://clients3.google.com/generate_204")){}}catch{DisconnectReason="No internet connection.";DisconnectScene=LoadingSceneManager.SceneName.Title;DisconnectAsync(NetworkManager.Singleton.LocalClientId).Forget();returnfalse;}Payload=payload;NetworkManager.Singleton.NetworkConfig.ConnectionData=Encoding.UTF8.GetBytes(JsonUtility.ToJson(Payload));NetworkManager.Singleton.OnClientDisconnectCallback+=OnClientDisconnect;NetworkObjectManager.Instance.Initialize();if(isApproval){NetworkManager.Singleton.ConnectionApprovalCallback+=ApprovalCheck;}IsSetUp=true;returntrue;}//==================================================// 2.Then call.//==================================================publicabstractUniTask<bool>CreateLobbyAsync();publicabstractUniTask<bool>JoinLobbyAsync();publicabstractUniTask<bool>LeaveLobbyAsync();publicabstractUniTask<bool>SearchLobbyAsync();protectedvirtualboolStartHost()=>NetworkManager.Singleton.StartHost();protectedvirtualboolStartClient()=>NetworkManager.Singleton.StartClient();//==================================================// 3. End processing.//==================================================publicasyncvirtualUniTaskDisconnectAsync(ulongclientId,boolreturnToTitle=true){if(clientId==NetworkManager.Singleton.LocalClientId){IsSetUp=false;NetworkObjectManager.Instance.Shutdown();NetworkManager.Singleton.Shutdown(true);// Wait for the shutdown to completeawaitUniTask.WaitUntil(()=>NetworkManager.Singleton.ShutdownInProgress==false);if(returnToTitle){LoadingSceneManager.Instance.LoadSceneAsync(DisconnectScene,LoadSceneMode.Single,false).Forget();}}else{DisconnectClientServerRpc(clientId);}}}