Unity Netcode自定义数据传输——结构体及其序列化

在 Unity Netcode 中,要实现自定义数据的网络传输,确实需要两个关键部分:

✅ 两个必需组件:

  1. 数据结构定义

    public struct PlayerState : INetworkSerializable
    {
        public int id;          // 字段1:玩家ID
        public bool isReady;    // 字段2:准备状态
        // ...其他字段
    }
    
    • 作用:定义要传输的数据内容
    • 本质:声明"要传输什么"
  2. 序列化方法实现

    public void NetworkSerialize<T>(BufferSerializer<T> serializer)
    {
        serializer.SerializeValue(ref id);       // 处理字段1
        serializer.SerializeValue(ref isReady);  // 处理字段2
        // ...处理其他字段
    }
    
    • 作用:控制数据如何打包/解包
    • 本质:定义"如何传输"

类比解释(快递包裹)

网络传输 快递包裹类比
数据结构 要寄送的物品
NetworkSerialize 方法 打包/拆包的操作说明书
网络管道 快递运输通道
接收方 收件人
  1. 发送方

    • 按照说明书(NetworkSerialize)打包物品(数据)
    • 通过快递(网络)寄出
  2. 接收方

    • 收到包裹
    • 按照相同的说明书NetworkSerialize)拆包
    • 获得完全相同的物品(数据)

为什么必须两者结合?

  1. 没有数据结构 → 不知道传输什么内容

    // 无效:不知道传输什么
    public void NetworkSerialize<T>(...) {
        // 没有字段可序列化
    }
    
  2. 没有序列化方法 → 不知道如何传输

    // 编译错误:未实现接口
    public struct PlayerState : INetworkSerializable {
        public int id;
        // 缺少NetworkSerialize方法
    }
    

完整工作流程

发送端 网络 接收端 准备数据 1. 创建PlayerState实例 2. 填充数据(id=101, isReady=true) 序列化(打包) 3. 调用NetworkSerialize - 写入id(101) - 写入isReady(true) 4. 发送二进制数据 5. 传输数据 反序列化(解包) 6. 创建空的PlayerState 7. 调用NetworkSerialize - 读取id → 101 - 读取isReady → true 8. 获得完整数据 发送端 网络 接收端

特殊注意事项

  1. 字段顺序必须严格一致
    发送端和接收端的序列化顺序必须完全相同:

    // ✅ 正确顺序
    serializer.SerializeValue(ref id);
    serializer.SerializeValue(ref isReady);
    
    // ❌ 危险!顺序不一致会导致数据错乱
    serializer.SerializeValue(ref isReady);
    serializer.SerializeValue(ref id);
    
  2. 新增字段的版本处理
    如果后续增加字段,需要处理兼容性:

    public string name; // 新增字段
    
    public void NetworkSerialize<T>(...)
    {
        serializer.SerializeValue(ref id);
        serializer.SerializeValue(ref isReady);
        
        // V2新增字段
        if (serializer.IsReader) {
            // 处理旧版本数据缺失的情况
            name = "默认名称";
        }
        serializer.SerializeValue(ref name);
    }
    
  3. 值类型 vs 引用类型

    • 结构体(值类型):直接使用 ✅
    • 类(引用类型):需要特殊处理 ❗
      public class Weapon // 引用类型
      {
          public int damage;
      }
      
      // 在序列化方法中需要:
      if (serializer.IsWriter) {
          serializer.SerializeValue(ref weapon.damage);
      } else {
          weapon = new Weapon();
          serializer.SerializeValue(ref weapon.damage);
      }
      

最终总结

组件 必须存在 作用
数据结构定义 声明要传输的数据内容
NetworkSerialize 方法 定义数据如何打包/解包
: INetworkSerializable 接口 标记该类型支持网络序列化

三者缺一不可,共同实现 Unity Netcode 的自定义数据网络传输能力。

你可能感兴趣的:(unity,游戏引擎)