You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity Mirror:如何等待Cmd命令执行完成后再执行本地方法

解决多人背包系统中Cmd方法同步等待问题

方案1:利用服务器回调通知(适配Unity Netcode/UNet)

核心思路是让服务器在执行完CmdAddItemToDatabase或CmdChangeItemAmount后,主动给发起请求的客户端发送确认信号,客户端收到信号后再继续后续逻辑。

以UNet为例的代码实现:

private bool _awaitingServerConfirm;

// 客户端入口方法
public void AddItem(Item targetItem)
{
    StartCoroutine(ProcessAddItem(targetItem));
}

private IEnumerator ProcessAddItem(Item targetItem)
{
    // 先做本地插槽校验
    if (!CanAddItem(targetItem)) yield break;

    _awaitingServerConfirm = true;
    // 调用对应Cmd方法
    if (HasSameItemInSlot(targetItem))
    {
        CmdChangeItemAmount(targetItem);
    }
    else
    {
        CmdAddItemToDatabase(targetItem);
    }
    // 等待服务器确认
    while (_awaitingServerConfirm)
    {
        yield return null;
    }
    // 这里执行添加完成后的后续逻辑(比如处理下一件物品)
}

// 服务器端执行完操作后,给发起请求的客户端发确认
[TargetRpc]
private void TargetNotifyAddComplete(NetworkConnection target)
{
    _awaitingServerConfirm = false;
}

// 在Cmd方法末尾调用确认Rpc
[Command]
private void CmdAddItemToDatabase(Item item)
{
    // 执行添加至SyncList的逻辑
    TargetNotifyAddComplete(connectionToClient);
}

[Command]
private void CmdChangeItemAmount(Item item)
{
    // 执行修改物品数量的逻辑
    TargetNotifyAddComplete(connectionToClient);
}

方案2:监听SyncList的变更事件

SyncList自带OnChanged事件,可通过监听这个事件来判断服务器的同步操作是否完成,以此触发后续逻辑。

代码示例:

private SyncList<Item> _backpackSlots;
private Queue<Item> _pendingItems = new Queue<Item>();
private bool _isProcessing = false;

private void Awake()
{
    _backpackSlots.OnChanged += OnBackpackSlotsUpdated;
}

// 客户端调用的添加方法
public void AddItem(Item item)
{
    _pendingItems.Enqueue(item);
    if (!_isProcessing)
    {
        ProcessNextPendingItem();
    }
}

private void ProcessNextPendingItem()
{
    if (_pendingItems.Count == 0)
    {
        _isProcessing = false;
        return;
    }
    _isProcessing = true;
    var currentItem = _pendingItems.Peek();
    if (CanAddItem(currentItem))
    {
        if (HasSameItemInSlot(currentItem))
        {
            CmdChangeItemAmount(currentItem);
        }
        else
        {
            CmdAddItemToDatabase(currentItem);
        }
    }
    else
    {
        _pendingItems.Dequeue();
        ProcessNextPendingItem();
    }
}

// 监听SyncList变更,确认操作完成后继续处理下一件
private void OnBackpackSlotsUpdated(SyncList<Item>.Operation op, int index, Item oldItem, Item newItem)
{
    if ((op == SyncList<Item>.Operation.Add || op == SyncList<Item>.Operation.Set) && _isProcessing)
    {
        _pendingItems.Dequeue();
        ProcessNextPendingItem();
    }
}

方案3:使用Netcode的ServerRpc回调(Unity Netcode for GameObjects)

如果用的是新版Netcode,ServerRpc支持直接传递回调委托,服务器执行完后可直接触发客户端的回调逻辑:

// 客户端添加方法
public void AddItem(ItemData item)
{
    if (CanAddItem(item))
    {
        AddItemServerRpc(item, OnAddItemFinished);
    }
}

[ServerRpc(RequireOwnership = true)]
private void AddItemServerRpc(ItemData item, ServerRpcParams rpcParams)
{
    // 执行添加或修改数量逻辑
    if (HasSameItem(item))
    {
        UpdateItemAmount(item);
    }
    else
    {
        AddItemToSyncList(item);
    }
    // 触发客户端回调
    AddItemCompleteClientRpc(rpcParams.Receive.SenderClientId);
}

[ClientRpc]
private void AddItemCompleteClientRpc(ulong clientId)
{
    if (NetworkManager.Singleton.LocalClientId == clientId)
    {
        OnAddItemFinished();
    }
}

// 后续逻辑的回调方法
private void OnAddItemFinished()
{
    // 处理下一件物品或后续流程
}

内容的提问来源于stack exchange,提问作者Draas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 11:01:01