为什么宿主玩家没有权限向服务器发送[命令]?统一 - 镜像

Why does the host player not have authority to send server [Command]? Unity - Mirror

我正在使用 Unity 2019.3.2f1 制作一款回合制多人游戏,并使用 Mirror 连接玩家。我的目标是将玩家对象添加到 GameMaster 脚本(正如您将在我最底部的脚本中看到的那样),以便我可以跟踪它们并在玩家脚本中更新它们的进度。我遵循了 DapperDino 的 youtube 教程 (https://www.youtube.com/watch?v=oBRt9OifJvE&list=PLS6sInD7ThM1aUDj8lZrF4b4lpvejB2uB&index=2) 并制作了一个大厅,复制了教程中的所有内容,除了刷怪笼系统,我还调整了场景的名称,删除了地图处理程序,而只有 2 个场景。 2个玩家进入大厅后,点击ready,主持人点击Start,MainMenu场景变为GameScene,正式游戏开始,但在此之前调用函数NetworkServer.ReplacePlayerForConnection(conn, gameplayerInstance.gameObject),在场景变化之前。我得到这个错误:

RemoveClientAuthority 只能在服务器上为生成的对象调用。 UnityEngine.Logger:Log(LogType, Object) Mirror.ILoggerExtensions:LogError(ILogger, Object)(在 Assets/Mirror/Runtime/LogFactory.cs:58)Mirror.NetworkIdentity:RemoveClientAuthority()(在 Assets/Mirror/Runtime/NetworkIdentity.cs:1230) Mirror.NetworkServer:InternalReplacePlayerForConnection(NetworkConnection, GameObject, Boolean) (在 Assets/Mirror/Runtime/NetworkServer.cs:843) Mirror.NetworkServer:ReplacePlayerForConnection(NetworkConnection, GameObject, Boolean) (在 Assets/Mirror/Runtime/NetworkServer.cs:680) DapperDino.Mirror.Tutorials.Lobby.NetworkManagerLobby:ServerChangeScene(String)(在 Assets/Lobby/Scripts/NetworkManagerLobby.cs:181)DapperDino.Mirror.Tutorials.Lobby.NetworkManagerLobby:StartGame()(在 Assets/Lobby/Scripts/NetworkManagerLobby.cs: 163)

为什么要调用 RemoveClientAuthority()?

然后我收到此警告:试图为未经授权的对象发送命令。 Player.CmdAddPlayer

这是我的代码。如您所见,在更新时我检查 if(!hasAuthority),如果客户端不检查,我会 return 更新函数,但它从来没有,所以我将其注释为调试。我收到的警告是关于主机进程的,这让我很困惑。主机不应该有权限,因为它也是服务器吗?

using System.Collections.Generic;
using UnityEngine;
using Mirror;


public class Player : NetworkBehaviour
{
    GameMaster gameMaster=null;
    //public NetworkManager networkManager;

    public Country country;
    public List<Territory> controlledTerritories;
    public List<Army> armies = new List<Army>();
    public int gold;
    bool set = false;
    void Start()
    {
        //networkManager = GameObject.FindWithTag("NetworkManager").GetComponent<NetworkManager>();
    }
    [Client]
    void Update()
    {
        //Debug.Log(networkManager);
        if (!set)
        {
            if (!hasAuthority)
            {
                //return;
            }
            Debug.Log("About to call CmdAddPlayer()");
            //This is the furthest I get. I get the warning after trying to call CmdAddPlayer() and it isn't called
            CmdAddPlayer();
        }
    }
    [Command]
    void CmdAddPlayer()
    {
        //Validate logic here
        Debug.Log("Called CmdAddPlayer()");
        RpcAddPlayer();
    }

    [ClientRpc]
    void RpcAddPlayer()
    {
        Debug.Log("Called RpcPlayer()");
        GameObject _mapTmp = GameObject.FindWithTag("GameController");
        GameMaster _gameMasterTmp = null;
        if (_mapTmp != null)
        {
            _gameMasterTmp = _mapTmp.GetComponent<GameMaster>();
        }
        if (gameMaster == null && _gameMasterTmp != null)
        {
            gameMaster = _gameMasterTmp;
            gameMaster.players.Add(this);
            set = true;
        }
    }
}

我正在学习相同的教程并遇到了相同的错误。

基本上显然与 Mirror 的 ServerChangeScene 有关。

你可以很容易地解决这个问题。在 DapperDino NetworkManagerLobby 脚本中,转到 ServerChangeScene 覆盖,并获取销毁的 reid,以便它从这里开始:

NetworkServer.Destroy(conn.identity.gameObject);     
NetworkServer.ReplacePlayerForConnection(conn, gameplayerInstance.gameObject); 
 

所以改为:

 NetworkServer.ReplacePlayerForConnection(conn, gameplayerInstance.gameObject); 
 

这应该可以解决问题。房间播放器对象似乎自动销毁了。

如果这不起作用,您可以在此处找到有关错误的更多信息:https://github.com/vis2k/Mirror/issues/1593

回答问题的后半部分,这里有一个很好的解释:

基本上,您可能试图从没有权限的对象发送命令。那么这是什么意思呢?

您只能从您的播放器对象向另一台计算机上代表您的播放器对象发送命令。

从你的代码中看不清楚,但你可能是:

  1. EITHER 尝试从属于其他玩家的 'player' 对象发送命令(例如,如果您正在循环遍历游戏中的所有玩家)。
  2. 或者您编写了一个名为 'player' 的脚本,但尚未获得授权(我怀疑是这个脚本,因为您将对象命名为 'player' 而不是 'NetworkGamePlayer' 如教程中所述。

如果您尝试第一个,请确保检查播放器是否为本地播放器:

    void CallCommandMove(){
       if(!isLocalPlayer){
        return;
         }
       CmdMove();
    }

或者,如果你想做第二个,你需要给你自己的玩家对象权限(如在这个线程中接受的答案:

最后,学习时最简单的方法是简单地将您的代码放在 NetworkGamePlayer 脚本上。