Last active
March 2, 2023 04:54
-
-
Save liveasnotes/f8d4693a4a4b261c449094b82511d6d2 to your computer and use it in GitHub Desktop.
AutoNetworkDiscovery.cs for Unity multi play with Mirror
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| original: https://qiita.com/OKsaiyowa/items/ecef8e5d50c84664f2a2 | |
| modified by liveasnotes | |
| > 登録ユーザーは、本サイトに投稿したコード、スニペットなどプログラムに類するものに限り、他の登録ユーザーが商用私用問わず無償で使用することを許諾し、他の登録ユーザーはこれを使用できるものとします。 | |
| > 前各項の登録ユーザーによる利用許諾には、地域制限、著作権表示義務その他付随条件はないものとします。 | |
| cf. https://qiita.com/terms (2023-01-04 checked) | |
| */ | |
| using System; | |
| using System.Threading; | |
| using Cysharp.Threading.Tasks; | |
| using Mirror; | |
| using Mirror.Discovery; | |
| using UnityEngine; | |
| using UnityEngine.UI; | |
| /// <summary> | |
| /// Automation of Server Discovery and Connection | |
| /// </summary> | |
| public class AutoNetworkDiscovery : NetworkDiscovery | |
| { | |
| [SerializeField] private Button _multiPlayButton; | |
| [SerializeField] private Button _backButton; | |
| [SerializeField] private Button _playButton; | |
| [SerializeField] private Text _playerCountText; | |
| [SerializeField] private Text _connectionStateText; | |
| [SerializeField, Scene] private string _gameSceneName; | |
| // Attribute "Scene" is one of the features of Mirror. | |
| // The referenced scene on the inspector can be used as a string in code. | |
| private ServerResponse _discoveredServer; | |
| private CancellationTokenSource _cancellationTokenSource; | |
| private const int CONNECT_INTERVAL_TIME = 2; | |
| private const int WAIT_TIME = 2; | |
| private const int CONNECT_TRY_COUNT = 1; | |
| private const string CONNECTION_STATUS_CLIENT_WAITING = "Waiting start..."; | |
| private const string CONNECTION_STATUS_HOST_WAITING = "Waiting other player..."; | |
| private const string CONNECTION_STATUS_SUCCESS = "Success!"; | |
| private bool _isHostReady; | |
| private NetworkManager _networkManager; | |
| private void OnDestroy() | |
| { | |
| // Stop server discovery before destroying self (e.g., scene transition). | |
| StopDiscovery(); | |
| } | |
| private void Awake() | |
| { | |
| // Prepare for receiving data | |
| NetworkClient.RegisterHandler<SendHostReadyData>(ReceivedReadyInfo); | |
| NetworkClient.RegisterHandler<SendPlayerCountData>(ReceivedPlayerCountInfo); | |
| OnServerFound.AddListener(serverResponse => | |
| { | |
| _discoveredServer = serverResponse; | |
| Debug.Log("ServerFound"); | |
| }); | |
| // Start server discovery and connection | |
| _multiPlayButton.onClick.AddListener(() => | |
| { | |
| Debug.Log("Search Connection"); | |
| _backButton.transform.gameObject.SetActive(true); | |
| _multiPlayButton.transform.gameObject.SetActive(false); | |
| // Try connection | |
| _cancellationTokenSource = new CancellationTokenSource(); | |
| CancellationToken token = _cancellationTokenSource.Token; | |
| TryConnectAsync(token).Forget(); | |
| }); | |
| // Return to the first view | |
| _backButton.onClick.AddListener(() => | |
| { | |
| Debug.Log("Cancel"); | |
| // Leave server | |
| StopDiscovery(); | |
| NetworkManager.singleton.StopHost(); | |
| // Stop asynchronous process | |
| _cancellationTokenSource.Cancel(); | |
| _cancellationTokenSource.Dispose(); | |
| }); | |
| // This button is displayed only for Host. It completes preparation if the button is pressed. | |
| _playButton.onClick.AddListener(() => | |
| { | |
| Debug.Log("Ready Ok"); | |
| SendHostReadyData sendData = new SendHostReadyData() { IsHostReady = true }; | |
| NetworkServer.SendToAll(sendData); | |
| _playButton.transform.gameObject.SetActive(false); | |
| }); | |
| } | |
| /// <summary> | |
| /// Reflect the state of the host ready to the local client(s). | |
| /// </summary> | |
| private void ReceivedReadyInfo(SendHostReadyData receivedData) | |
| { | |
| _isHostReady = receivedData.IsHostReady; | |
| } | |
| /// <summary> | |
| /// Reflect the state of connection amount to the local client(s). | |
| /// </summary> | |
| private void ReceivedPlayerCountInfo(SendPlayerCountData receivedData) | |
| { | |
| if (_playButton == null) return; | |
| _playerCountText.text = receivedData.PlayerCount + "/" + _networkManager.maxConnections; | |
| } | |
| /// <summary> | |
| /// Asynchronous trial of connection | |
| /// </summary> | |
| private async UniTaskVoid TryConnectAsync(CancellationToken token) | |
| { | |
| _networkManager = NetworkManager.singleton; | |
| int tryCount = 0; | |
| StartDiscovery(); | |
| // Loop until connected to a server | |
| while (!_networkManager.isNetworkActive) | |
| { | |
| await UniTask.Delay(TimeSpan.FromSeconds(CONNECT_INTERVAL_TIME), cancellationToken: token); | |
| // Run every n seconds | |
| // Server found | |
| if (_discoveredServer.uri != null) | |
| { | |
| Debug.Log("Start Client"); | |
| _networkManager.StartClient(_discoveredServer.uri); | |
| _connectionStateText.text = CONNECTION_STATUS_CLIENT_WAITING; | |
| StopDiscovery(); | |
| await UniTask.WaitUntil(() => _isHostReady, cancellationToken: token); | |
| _connectionStateText.text = CONNECTION_STATUS_SUCCESS; | |
| } | |
| // Server not found | |
| else | |
| { | |
| Debug.Log("Try Connect..."); | |
| tryCount++; | |
| // Make self as host if the trial failed over n times. | |
| if (tryCount > CONNECT_TRY_COUNT) | |
| { | |
| Debug.Log("Start Host"); | |
| _networkManager.StartHost(); | |
| AdvertiseServer(); | |
| // Send notice that this is a server (host). | |
| _connectionStateText.text = CONNECTION_STATUS_HOST_WAITING; | |
| _playButton.gameObject.SetActive(true); | |
| await UniTask.WaitUntil(() => _isHostReady, cancellationToken: token); | |
| _connectionStateText.text = CONNECTION_STATUS_SUCCESS; | |
| await UniTask.Delay(TimeSpan.FromSeconds(WAIT_TIME), cancellationToken: token); | |
| _networkManager.ServerChangeScene(_gameSceneName); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| [Serializable] | |
| public struct SendPlayerCountData : NetworkMessage | |
| { | |
| /// <summary> | |
| /// Number of connected player | |
| /// </summary> | |
| public int PlayerCount; | |
| } | |
| [Serializable] | |
| public struct SendHostReadyData : NetworkMessage | |
| { | |
| /// <summary> | |
| /// Is the host ready | |
| /// </summary> | |
| public bool IsHostReady; | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // source is same to above. | |
| // some parts modified. | |
| using Mirror; | |
| using UnityEngine; | |
| using UnityEngine.SceneManagement; | |
| /// <summary> | |
| /// 接続にまつわるいろいろ | |
| /// </summary> | |
| public class CustomNetworkManager : NetworkManager | |
| { | |
| [SerializeField, Scene] private string _titleScene; | |
| [SerializeField, Scene] private string _mainScene; | |
| private Transform _playerTransform; | |
| private Material _playerMaterial; | |
| /// <summary> | |
| /// プレイヤー入室時にサーバー側が実行 | |
| /// </summary> | |
| /// <param name="conn">接続されたプレイヤーのコネクション</param> | |
| public override void OnServerAddPlayer(NetworkConnectionToClient conn) | |
| { | |
| Debug.Log("Add Player"); | |
| //タイトルシーンでのみ実行 | |
| if (_titleScene.Contains(SceneManager.GetActiveScene().name)) | |
| { | |
| //接続中の人数表記を変える | |
| SendPlayerCountData sendData = new SendPlayerCountData() { PlayerCount = NetworkServer.connections.Count }; | |
| NetworkServer.SendToAll(sendData); | |
| } | |
| //メインシーンでのみ実行 | |
| if (_mainScene.Contains(SceneManager.GetActiveScene().name)) | |
| { | |
| Debug.Log("Spawn Player"); | |
| //プレイヤー生成 | |
| GameObject player = Instantiate(playerPrefab); | |
| //今立ち上げているサーバーにプレイヤーを追加登録 | |
| NetworkServer.AddPlayerForConnection(conn, player); | |
| } | |
| } | |
| /// <summary> | |
| /// 各プレイヤー退室時にサーバー側が実行 | |
| /// </summary> | |
| /// <param name="conn">切れたコネクション</param> | |
| public override void OnServerDisconnect(NetworkConnectionToClient conn) | |
| { | |
| //接続中の人数表記を変える | |
| SendPlayerCountData sendData = new SendPlayerCountData() { PlayerCount = NetworkServer.connections.Count }; | |
| NetworkServer.SendToAll(sendData); | |
| Debug.Log("Anyone Disconnect"); | |
| base.OnServerDisconnect(conn); | |
| } | |
| /// <summary> | |
| /// サーバーとの接続が切れた時にクライアント側で呼ばれる | |
| /// </summary> | |
| public override void OnStopClient() | |
| { | |
| SceneManager.LoadScene(_titleScene); | |
| Debug.Log("Disconnect"); | |
| base.OnStopClient(); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment