Unity3D。 试图在没有权限的情况下发送对象的命令

我有一个多人回合制战略游戏,需要一个游戏经理,控制当前的游戏状态(轮到谁了)。 这个管理器应该对每个客户端都是通用的,它的状态应该在服务器上同步。

以下是我这样做的方法:游戏管理器对象是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(); NetworkServer.RegisterHandler(MsgType.AddPlayer, tacticsManager.CreatePlayerOnServer); NetworkServer.Spawn(manager); } ClientScene.AddPlayer(0); } 

当我在服务器上运行它时它工作正常,它在客户端上创建一个实例并同步从服务器到客户端的变量。 但是,当我尝试从客户端运行命令时,它会忽略它们,抛出此警告:

试图在没有权限的情况下发送对象的命令。 UnityEngine.Networking.NetworkBehaviour:SendCommandInternal(NetworkWriter,Int32,String)

请注意,此游戏管理器是在任何玩家之前生成的,因为它必须负责产生玩家。 我究竟做错了什么?

在您的代码片段旁边,警告

试图在没有权限的情况下发送对象的命令

意味着:您从一个权限 ,您的(玩家)没有的对象发送命令

Unity文档声明的内容: 命令从客户端上的播放器对象发送到服务器上的播放器对象。 为了安全起见, 命令只能从您的玩家对象发送,因此您无法控制其他玩家的对象。

从Unity版本5.2开始, 可以从具有客户端权限的非玩家对象发送命令 。 必须使用NetworkServer.SpawnWithClientAuthority生成这些对象,或者使用NetworkIdentity.AssignClientAuthority设置权限。 从这些对象发送的命令在对象的服务器实例上运行,而不是在客户端的关联播放器对象上运行( 更多 )。

那么解决方案是什么:在发送Command (或执行命令function)之前, 将该对象的权限分配给您的Player 。 像这样的东西

 assignAuthorityObj.GetComponent().AssignClientAuthority(this.GetComponent().connectionToClient); 

this ”将代表您的Player对象。 进行Command调用后,您可以使用此代码段删除权限。

  assignAuthorityObj.GetComponent().RemoveClientAuthority(this.GetComponent().connectionToClient); 

同样,“ this ”将代表您的Player对象。

重要说明 :我通常使用OnTriggerEnter分配对象的权限(如果我想使用它)并删除OnTriggerExit的权限 。 它取决于您希望获取或删除对象权限的特定情况。

没有本地权限,您无法发送命令。

 if (!isLocalPlayer) return; 

但是,您使用此命令发送了哪种数据? 总的来说,正如你所说:

“它的状态应该在服务器上同步”

所以,恕我直言,你没有理由从你的播放器发送Command 。 命令应该是播放器输入。 这些输入将触发游戏中的操作。 您的经理将使用ClientRpc从这些操作(分数更新,游戏结束……)获取信息并在客户端上发送数据和/或触发操作

这是服务器权限模型。 如果您让本地对象发送命令,黑客可以很容易地进入并告诉您的经理

“嘿,轮到我了。嘿,轮到我了。嘿,我的分数是9999999,我在1秒内赢了比赛。”