Mirror Networking命令失效,客户端执行时断开连接
解决Mirror Networking中Command命令触发空引用导致客户端断开的问题
问题分析
你遇到的NullReferenceException发生在Mirror的NetworkServer.OnCommandMessage方法中,核心原因是服务器接收到Command请求时,找不到对应的NetworkIdentity实例。主机端正常是因为主机同时作为服务器和客户端,本地实例化的对象自动关联了网络身份,但纯客户端实例化的对象没有被服务器同步注册,导致服务器无法识别该对象的网络ID,处理Command时触发空引用并断开连接。
具体解决方案
1. 修正方块的实例化方式
不要用普通Instantiate()生成方块,必须通过服务器来Spawn网络对象:
- 客户端向服务器发送实例化请求(比如通过一个Command)
- 服务器调用
NetworkServer.Spawn()生成方块预制体,该方法会自动同步对象到所有客户端,并分配合法的网络身份 - 示例流程:
// 客户端请求服务器生成方块 [Command(requiresAuthority = false)] public void CmdSpawnBlock(Vector3 position, int index) { GameObject block = Instantiate(blockPrefab, position, Quaternion.identity); block.GetComponent<ClickableBlock>().blockIndex = index; NetworkServer.Spawn(block); // 关键:服务器Spawn同步到所有客户端 }
2. 检查NetworkIdentity配置
- 确保方块预制体上添加了
NetworkIdentity组件,且未勾选"Server Only"(客户端需要交互该对象) - 确保Command所在的脚本挂载在带有
NetworkIdentity的GameObject上,且该对象已被服务器Spawn
3. 调整Command的调用载体
避免在客户端本地实例化的对象上直接调用Command,改为通过全局的、已被服务器Spawn的网络对象(比如GameManager)来转发请求:
- 将Command方法移到带有
NetworkIdentity的GameManager脚本中 - 客户端点击方块时,调用GameManager的Command传入方块ID
修正后的代码示例:
// GameManager脚本(挂载在服务器Spawn的对象上) public class GameManager : NetworkBehaviour { [Command(requiresAuthority = false)] public void CmdSendBlockClick(int index) { Debug.Log("服务器收到方块点击请求:ID=" + index); // 同步到所有客户端执行点击逻辑 RpcSyncBlockClick(index); } [ClientRpc] public void RpcSyncBlockClick(int index) { // 所有客户端执行对应ID方块的点击操作 Debug.Log("客户端执行方块点击:ID=" + index); // 这里添加你的方块逻辑,比如找到对应ID的方块并修改状态 } }
// 方块点击脚本 public class ClickableBlock : MonoBehaviour { public int blockIndex; private GameManager _gameManager; void Awake() { _gameManager = FindObjectOfType<GameManager>(); } void OnMouseDown() { _gameManager?.CmdSendBlockClick(blockIndex); } }
4. 验证网络对象状态
- 在服务器端打印
NetworkServer.spawned集合,确认方块对象已被注册到网络系统中 - 客户端可以通过
NetworkClient.spawned检查是否同步到了对应的方块对象
内容的提问来源于stack exchange,提问作者Povst
相关产品推荐
相关产品推荐

