【问题标题】:Using [Command] to send game objects from client to server使用 [Command] 将游戏对象从客户端发送到服务器
【发布时间】:2021-09-23 07:05:48
【问题描述】:

真的可以吗?

我在命令中将单个值发送回服务器没有问题,但我无法将它们打包成游戏对象(具有网络身份),然后将其作为参数发送到命令中。

按照 Mirror 文档应该是可能的,我已经尝试按照这个例子:

class Item 
{
    public string name;
}

class Weapon : Item
{
    public int hitPoints;
}

class Armor : Item
{
    public int hitPoints;
    public int level;
}

class Player : NetworkBehaviour
{
    [Command]
    void CmdEquip(Item item)
    {
        // IMPORTANT: this does not work. Mirror will pass you an object of type item
        // even if you pass a weapon or an armor.
        if (item is Weapon weapon)
        {
            // The item is a weapon, 
            // maybe you need to equip it in the hand
        }
        else if (item is Armor armor)
        {
            // you might want to equip armor in the body
        }
    }

    [Command]
    void CmdEquipArmor(Armor armor)
    {
        // IMPORTANT: this does not work either, you will receive an armor, but 
        // the armor will not have a valid Item.name, even if you passed an armor with name
    }
}

但是我没有运气,在服务器上而不是我传递的对象,服务器有自己的副本和自己的值。

知道我哪里出错了吗?

【问题讨论】:

  • 您是否尝试过让您的课程[Serializable]?对于CmdEquip,如果参数是Item,您通常只会得到Item。最近实现了一个自定义多用户模块,通常您会查看预期的类型,创建该类型的实例并用接收到的数据填充它。如果镜子有什么不同,我不能告诉你;)
  • 我确实在 Rusty 提到它之后添加了 [Serializable] 和 [SerializeField],但没有骰子。我不认为 Mirror 使用了这些属性,但可能是错误的!
  • 这些属性(至少 [Serializable])是核心 c# 不是 Unity 或 Mirror 特定的;)我只认为 mirrorigjt 使用需要这些的 Unity 序列化程序.. 参见例如mirror-networking.gitbook.io/docs/guides/data-types
  • -> Classes as long as each field has a supported data type These will allocate garbage and will be instantiated new on the receiver every time they're sent. 所以对于第一个问题,他们和我一样 -> 只有接收到的类型很重要,你永远不会得到 WeaponArmor 作为参数。我会为这种情况推荐一个重载
  • 一般来说,它会帮助你向我们展示你是如何调用这些方法的;)

标签: unity3d mirror


【解决方案1】:

它在文档中说明“此代码不能开箱即用。”。 从文档: 如果您为 Item 类型提供自定义序列化程序,CmdEquip 将起作用。 例如:

public static class ItemSerializer 
{
    const byte WEAPON = 1;
    const byte ARMOR = 2;

    public static void WriteItem(this NetworkWriter writer, Item item)
    {
        if (item is Weapon weapon)
        {
            writer.WriteByte(WEAPON);
            writer.WriteString(weapon.name);
            writer.WritePackedInt32(weapon.hitPoints);
        }
        else if (item is Armor armor)
        {
            writer.WriteByte(ARMOR);
            writer.WriteString(armor.name);
            writer.WritePackedInt32(armor.hitPoints);
            writer.WritePackedInt32(armor.level);
        }
    }

    public static Item ReadItem(this NetworkReader reader)
    {
        byte type = reader.ReadByte();
        switch(type)
        {
            case WEAPON:
                return new Weapon
                {
                    name = reader.ReadString(),
                    hitPoints = reader.ReadPackedInt32()
                };
            case ARMOR:
                return new Armor
                {
                    name = reader.ReadString(),
                    hitPoints = reader.ReadPackedInt32(),
                    level = reader.ReadPackedInt32()
                };
            default:
                throw new Exception($"Invalid weapon type {type}");
        }
    }
}

看来您需要在客户端和服务器之间传递序列化信息而不是原始类型才能使其工作。以防万一您没有考虑到这一点。

【讨论】:

  • 感谢生锈。我使用了那个例子,因为它是我能找到的唯一代码,显示了一个正在传递给服务器的对象。我说的更笼统,文档声明“任何允许的数据类型的参数都将使用命令自动传递给服务器。”游戏对象和结构应该可以工作,但我也没有任何运气,我已经尝试过各种方式。我会看看序列化,以防我遗漏了它。
  • 我将“任何参数”理解为序列化信息......但是我没有使用 Mirror 的经验,尽管我有兴趣将其作为技术选项进行选择
  • 现在是最好的时机!不用担心,我希望那些知道这是一个简单的答案。当我发现我会在这里发帖。
猜你喜欢
  • 1970-01-01
  • 2013-11-16
  • 2013-01-12
  • 1970-01-01
  • 2017-12-24
  • 1970-01-01
  • 1970-01-01
  • 2014-10-08
  • 1970-01-01
相关资源
最近更新 更多