Unity Mirror 自定义序列化器传输数据

Mirror支持许多内建类型的传输,具体可参考Mirror的NetworkWriter类的定义。这里提供一个自定义序列化传输数据的方法。

而一些自定义的类型,比如下面这个:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
using Mirror;
using UnityEngine;

public class CustomDataTypes : NetworkBehaviour
{
public class Item
{
public string name;
}

public class Armour : Item
{
public int protection;
public int weight;
}

public class Potion : Item
{
public int health;
}

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

Potion potion = new Potion();
potion.name = "Health Potion";
potion.health = 5;

CmdSendItem(potion);
}

[Command]
private void CmdSendItem(Item item)
{
if(item is Item)
Debug.Log("Item name is " + item.name);

if (item is Potion potion)
Debug.Log("Potion gives " + potion.health + " health.");
}
}

其中存在继承关系,如果尝试直接传输,会发现CmdSendItem的第二条log没有输出:

下面提供一种自定义序列化器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
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}.");
}
}
}

再次运行:

可以看到成功打印出Potion的health数据