EKsumic's Blog

let today = new Beginning();

Click the left button to use the catalog.

OR

[Unity]Mirror联网插件——Custom Data Types

Custom Data Types(自定义数据类型)

 

本篇介绍一般情况下能通过Network传输的变量。

 

一般结构体能通过Network传递,

一般类能传递,但是有继承的类,不行

需要custom serialize。

 

举例:

(基础操作已省略,具体操作同→这里

代码:

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

public class CustomDataTypes : NetworkBehaviour
{
    #region Will serialize
    public struct A
    {
        public byte ID;
        public Vector3 Position;
    }

    public class B
    {
        public string Name;
        //Won't serialize if ItemStats is null
        public C stats;
    }
    /* Will serialize because it uses built-in types.
     * Any type which isn't built in would need to have a
     * serializer made.*/

    public class C
    {
        public int count;
    }
    #endregion

    #region Demo Classes
    public class Item
    {
        public string Name;
    }
    /*The Next 2 classes will not serialize over the Network without
     * making a custom serializer*/

    public class Armour : Item
    {
        public int Protection;
        public int Weight;
    }

    public class Potion : Item
    {
        public int Health;
    }
    #endregion

    public override void OnStartAuthority()
    {
        base.OnStartAuthority();

        Potion pot = new Potion();
        pot.Name = "Health Potion";
        pot.Health = 5;
        CmdSendItem(pot);
    }

    [Command]
    private void CmdSendItem(Item item)
    {
        if (item is Item)
            Debug.Log("My Name is"+item.Name+".");
        if(item is Potion potion)
            Debug.Log("My potion gives"+potion.Health+" health.");
    }
}

结果:

Saved

如图所示,

Debug.Log("My potion gives"+potion.Health+" health.");

这一句明显没有执行。

 

这就是为什么要需要custom serialize。

 

那么该怎么做呢?

 

这里直接写一个Script就行了。

注意,并不需要挂到任何物体上。

 

代码:

using Mirror;
using System;
using static CustomDataTypes;

public static class ItemSerializer
{
    private const byte ITEM_ID = 0;
    private const byte POTION_ID = 1;
    private const byte ARMOUR_ID = 2;

    public static void WriteItem(this NetworkWriter writer,Item item)
    {
        if(item is Potion potion)
        {
            writer.WriteByte(POTION_ID);
            writer.WriteString(potion.Name);
            writer.WritePackedInt32(potion.Health);
        }

        else if(item is Armour armour)
        {
            writer.WriteByte(ARMOUR_ID);
            writer.WriteString(armour.Name);
            writer.WritePackedInt32(armour.Protection);
            writer.WritePackedInt32(armour.Weight);
        }

        else
        {
            writer.WriteByte(ITEM_ID);
            writer.WriteString(item.Name);
        }
    }

    public static Item ReadItem(this NetworkReader reader)
    {
        byte id = reader.ReadByte();

        switch(id)
        {
            case POTION_ID:
                return new Potion
                {
                    Name = reader.ReadString(),
                    Health = reader.ReadPackedInt32()
                };
            case ARMOUR_ID:
                return new Armour
                {
                    Name = reader.ReadString(),
                    Protection = reader.ReadPackedInt32(),
                    Weight = reader.ReadPackedInt32(),
                };
            case ITEM_ID:
                return new Item
                {
                    Name = reader.ReadString(),
                };
            default:
                throw new Exception($"Unhandled item type for {id}.");
        }
    }
}

结果:

Saved22

我们可以看到子类Potion的内容正确地输出了。

 

如果你想传递其他子类,那就必须继续补全ItemSerializer这个静态类。

This article was last edited at 2020-04-14 15:32:23

BLUCE LEE

writer.WritePackedInt32;reader.ReadPackedInt32;这两个方法报错,应该是删掉的原因吧,请教一下换什么方法呢?

reply

2021-11-02 22:27:15

BLUCE LEE

@BLUCE LEE 我知道了,直接把方法改成write即可

reply

2021-11-03 10:35:05

* *