Mirror/UNET c# - 即使使用 Command & ClientRpc 也没有对象权限 - 我错过了什么?

Mirror/UNET c# - No authority on object even when using Command & ClientRpc - What am I missing?

长话短说: 我使用 Mirror/Unet 进行了多人聊天,效果很好。我已经做到了,在 x 秒后,显示聊天的游戏对象(“t​​extContainer”)变为非活动状态。我希望这样当客户端 1 按下“提交”时,所有客户端的 textContainer 游戏对象再次激活。但它只适用于按下提交的客户端,而不适用于所有客户端。我已经在 [Client] [Command] 和 [ClientRpc] 中设置了函数,但仍然收到关于对象没有权限的错误。
我认为这是因为客户端 1 没有权限请求客户端 2 激活他们的 UI 面板。我以为 Command 和 ClientRpc 会解决这个问题?

短篇小说: 所以,为了简单起见,假设当客户端 1 按下输入“提交”时,我希望所有客户端的 textContainer 游戏对象都处于活动状态。
我希望有人能指出我正确的方向。干杯。

此脚本将附加到播放器预制件。

public GameObject textContainer;

[Client]
void Update()
{
    if (Input.GetAxisRaw("Submit") == 1)
    {
        CmdActivateChatClientRPC();
        textContainer.SetActive(true);

    }
}

[Command]
private void CmdActivateChatClientRPC()
{
    ActivateChatClientRPC();
}

[ClientRpc]
private void ActivateChatClientRPC()
{
    textContainer.SetActive(true);
        
}

怎么样 客户端->服务器:请求激活

然后

服务器->客户端:单

[SyncVar(hook = nameof(AcivateText))]
bool textActivated = false;

[Command]
private void CmdActivateChatClientRPC()
{
    ActivateChatClientRPC();
}

void AcivateText(bool oldval, bool newval)
{
    textContainer.SetActive(newval);
}

您没有检查您是否有此对象的 authority

void Update()
{
    // Does your device have the authority over this object?
    // only then you can invoke a Cmd
    if(!hasAuthority) return;

    if (Input.GetAxisRaw("Submit") == 1)
    {
        CmdActivateChatClientRPC();
        textContainer.SetActive(true);
    }
}

[Command]
private void CmdActivateChatClientRPC()
{
    ActivateChatClientRPC();
}

// This will be executed on ALL clients!
// BUT only for this one instance of this class   
[ClientRpc]
private void ActivateChatClientRPC()
{
    textContainer.SetActive(true);      
}

如果只是您尝试对属于服务器的对象调用命令,那将变得棘手 ;)

您必须通过本地播放器对象中继命令,然后在服务器上将调用转发给相应的对象,例如通过它的网络身份引用实际目标。


对我来说,这听起来有点像你让每个玩家预制件都有这个 class 并且你想在所有这些预制件上调用 RPC。

这只能由服务器完成,例如

void Update()
{
    // Does your device have the authority over this object?
    // only then you can invoke a Cmd
    if(!hasAuthority) return;

    if (Input.GetAxisRaw("Submit") == 1)
    {
        CmdActivateChatClientRPC();
        textContainer.SetActive(true);
    }
}

[Command]
private void CmdActivateChatClientRPC()
{
    foreach (var player in NetworkManager.singleton.client.connection.playerControllers)
    {
        if (player.IsValid)
        {
            player.gameObject.GetComponent<YourScriptName>().ActivateChatClientRPC();
        }
    }
}

似乎 .client.connection.playerControllers 已被删除。

我想在那种情况下你需要一个自定义 NetworkManager 并通过 OnServerConnect and OnServerDisconnect 自己跟踪它们,有点像

public CustomNetworkManager : NetworkManager
{
    public static readonly HashSet<NetworkConnection> players = new HashSet<NetworkConnection>();

    public override void OnServerConnect(NetworkConnection conn)
    {
        base.OnServerConnect(conn);

        players.Add(conn);
    }

    public override void OnServerDisconnect(NetworkConnection conn)
    {
        base.OnServerDisconnect(conn);

        players.Remove(conn);
    }
}

然后改为访问

foreach (var player in CustomNetworkManager.players)
{
    player.identity.GetComponent<YourScriptName>().ActivateChatClientRPC();
}