ConnectionApproval を利用して接続人数制限を実装する【Netcode for GameObjects】

検証環境

  • Unity 2020.3.20f1
  • Netcode for GameObjects 1.0.0-pre.3 (以降 NGO)

ConnectionApproval

ConnectionApprovalNGO のサーバ側の機能で,接続を許可するかどうかを接続ごとに決定することができます.
以前,以下の記事でホストの入力パスワードとクライアントの入力パスワードが一致すれば
接続できるようにする時に ConnectionApproval を利用しました.

xrdnk.hateblo.jp

この ConnectionApproval を利用すれば接続人数制限処理を実装することができます.

サンプルコード

Server 側のみに記述するコード

Server 側に ConnectionApproval の処理を記述します.

        public delegate bool ApproveCheckDelegate(byte[] connectionData, ulong clientId);
        /// <summary>
        /// ConnectionApproval 時に利用するコールバックイベント
        /// </summary>
        public event ApproveCheckDelegate ConnectionApproveCheck = null;

        public void StartServer()
        {
            ...
            // サーバ起動前にコールバック処理追加
            NetworkManager.Singleton.ConnectionApprovalCallback += ApprovalCheck; 
            ...
        }

        public void StopServer()
        {
            ...
            // サーバ終了時にコールバック処理解除
            NetworkManager.Singleton.ConnectionApprovalCallback -= ApprovalCheck; 
            ...
        }

        private void ApprovalCheck(byte[] connectionData, ulong clientId, NetworkManager.ConnectionApprovedDelegate callback)
        {
            var approved = true;

            if (ConnectionApproveCheck != null)
            {
                approved = ConnectionApproveCheck.Invoke(connectionData, clientId);
            }

            callback(createPlayerObject: false, playerPrefabHash: null, approved: approved, position: null, rotation: null);
        }

ConnectionApproval の処理は毎度変わると思われるので,処理を外部に任せられるようにしましょう.

接続人数制限処理

        private int _maxCcu = 100;
        private bool _isConnectionApprovalOn;

        public void Awake()
        {
            if (_isConnectionApprovalOn)
            {
                _ngoServer.ConnectionApproveCheck += CheckCcu;
            }
            ...
            // サーバ起動処理
            _ngoServer.StartServer();
        }

        bool CheckCcu(byte[] data, ulong connectingClientId)
        {
            Debug.Log($"現在の人数は{NetworkManager.Singleton.ConnectedClients.Count}です.");
            Debug.Log($"Id: {connectingClientId} が入室を試みています.");

            var tempCounter = NetworkManager.Singleton.ConnectedClients.Count + 1;

            Debug.Log($"人数制限:{_maxCcu}");

            if (_networkConfig.MaxCcu <= -1)
            {
                Debug.Log($"人数無制限設定のため,検証なしに接続許可を行います");
                return true;
            }

            if (tempCounter <= _maxCcu)
            {
                Debug.Log($"入室成功しました.現在の人数は{NetworkManager.Singleton.ConnectedClients.Count}です.");
                return true;
            }
            else
            {
                Debug.Log($"人数上限の{_maxCcu}人を越えたため入室失敗しました.");
                return false;
            }
        }

簡易なサンプルコードですが,_maxCcu に接続制限人数(非負整数)を設定します.
負数の場合は無制限設定と等しくするようにしています.

_maxCcu を越えてしまった場合は false を返して通さない,超えない場合は true を返して通すという単純な処理です.

クライアント側の処理

ConnectionApproval を通らなかった場合は,クライアント側では NetworkManager.Singleton.OnClientDisconnectCallback
登録された処理が走ります.ただここで少し工夫しないと通常切断処理と変わりない感じになるので,
各自で切断原因を作ったり,接続状態のステートを実装するとよいと思います.Photon みたいに DisconnectCause 欲しい.

参考文献

NGO の公式サンプルである Boss Room にも似たような実装があります.
ここでは ClientRpc を利用してエラーコードを送っているようです.

docs-multiplayer.unity3d.com