ゲームマネージャーを必要とし、現在のゲームの状態(誰がターンするかなど)を制御するマルチプレイヤーターンベースの戦略ゲームがあります。このマネージャーはすべてのクライアントに共通である必要があり、サーバー上で状態を同期する必要があります。
これをどのように行うかを以下に示します。ゲームマネージャーオブジェクトはNetworkBehaviourであり、ローカルプレーヤーの権限でもサーバーの権限でもないNetworkIdentityを持っています。カスタムNetworkManagerを作成し、クライアント接続でゲームマネージャーを生成し、サーバーであるかどうかもテストします。コードは次のとおりです。
public override void OnClientConnect(NetworkConnection conn)
{
ClientScene.Ready(conn);
if (NetworkServer.active)
{
var manager = Instantiate(MultiplayerManagerPrefab, Vector3.zero, Quaternion.identity) as GameObject;
var tacticsManager = manager.GetComponent<MultiplayerManagerModel>();
NetworkServer.RegisterHandler(MsgType.AddPlayer, tacticsManager.CreatePlayerOnServer);
NetworkServer.Spawn(manager);
}
ClientScene.AddPlayer(0);
}
サーバー上で実行すると正常に動作し、クライアント上にインスタンスを作成し、サーバーからクライアントに変数を同期します。しかし、クライアントからコマンドを実行しようとすると、コマンドは無視され、次の警告がスローされます。
権限なしでオブジェクトのコマンドを送信しようとしています。 UnityEngine.Networking.NetworkBehaviour:SendCommandInternal(NetworkWriter、Int32、String)
このゲームマネージャーは、プレーヤーのスポーンを担当する必要があるため、プレーヤーの前にスポーンされることに注意してください。私は何を間違えていますか?
コードフラグメントの横にある警告
権限のないオブジェクトに対してコマンドを送信しようとしています。
は以下を意味します:あなたはコマンドをauthorityのオブジェクトから送信していますが、あなたの(プレイヤー)は持っていません。
Unityドキュメントの説明:コマンドは、クライアント上のプレーヤーオブジェクトからサーバー上のプレーヤーオブジェクトに送信されます。セキュリティのため、コマンドはYOURプレーヤーオブジェクトからのみ送信できるため、他のプレーヤーのオブジェクトを制御することはできません。
[〜#〜] but [〜#〜]
Unityリリース5.2以降、クライアント権限を持つ非プレーヤーオブジェクトからコマンドを送信できます。これらのオブジェクトは、NetworkServer.SpawnWithClientAuthorityで生成されているか、NetworkIdentity.AssignClientAuthorityで権限が設定されている必要があります。これらのオブジェクトから送信されるコマンドは、クライアントの関連プレーヤーオブジェクトではなく、オブジェクトのサーバーインスタンスで実行されます( more )。
だから解決策は何ですか:コマンドを送信する前に(またはコマンド関数を実行)、そのオブジェクトの権限をプレーヤーに割り当てます。このようなもの
assignAuthorityObj.GetComponent<NetworkIdentity>().AssignClientAuthority(this.GetComponent<NetworkIdentity>().connectionToClient);
「this」は、Playerオブジェクトを表します。コマンドを呼び出した後、このコードスニペットを使用して権限を削除できます。
assignAuthorityObj.GetComponent<NetworkIdentity>().RemoveClientAuthority(this.GetComponent<NetworkIdentity>().connectionToClient);
繰り返しますが、「this」はPlayerオブジェクトを表します。
重要な注意事項:通常、OnTriggerEnterを使用してオブジェクトの権限を割り当て(使用する場合)、権限を削除しますOnTriggerExitで。どのイベントでオブジェクト権限を取得または削除するかは、特定のシナリオに依存します。
ローカル権限なしにコマンドを送信することはできません。
if (!isLocalPlayer) return;
しかし、このコマンドでどのようなデータを送信していますか?一般的に、そしてあなたが言ったように:
「サーバー上で状態を同期する必要があります」
だから、私見、プレーヤーからCommand
を送信する理由はありません。コマンドはプレイヤー入力用である必要があります。これらの入力は、ゲームでアクションをトリガーします。マネージャーは、これらのアクション(スコアの更新、ゲームの終了...)から情報を取得し、ClientRpc
を使用して、クライアントにデータを送信したり、アクションをトリガーしたりします。
これはサーバー権限モデルです。ローカルオブジェクトにコマンドを送信させると、ハッカーが簡単に侵入して上司に言うことができます。
「ねえ、それは私の番です。ねえ、それは私の番です。ねえ、私のスコアは9999999で、1秒でゲームに勝ちました。」.