• Unity之NetCode多人网络游戏联机对战教程(5)--ConnectionData与MemoryPack


    前言

    ConnectionDataConnectionApproval 是搭配使用的,在ConnectionApproval系列讲解中涉及的几个使用场景将会在这里讲解


    使用场景

    • 使用密码加入房间

    • 玩家选择不同的角色

    • 房间人数

    • 各种需要服务端下发的信息等等


    ConnectionData

    ConnectionData是在(NetworkManager.ConnectionApprovalRequest.Payload)的一个参数,接受客户端应该发送到服务器的任何自定义数据。连接数据在客户端的NetworkingConfig中指定(在连接时提供)。NetworkConfig.ConnectionData会自动随着连接请求消息发送到服务器,因此在调用NetworkManager.StartClient之前,应该在客户端上填充NetworkConfig.ConnectionData

    • 例子
    using Unity.Netcode;
    
    NetworkManager.Singleton.NetworkConfig.ConnectionData = System.Text.Encoding.UTF8.GetBytes("room password");
    NetworkManager.Singleton.StartClient();
    
    • 1
    • 2
    • 3
    • 4

    由客户端的NetworkConfig.ConnectionData定义的Payload将作为连接请求消息的一部分发送到服务器,服务器将使用它来决定是否批准客户端连接。连接数据是可选的,您可以使用连接批准过程来分配玩家的唯一预制体,并实现在不需要客户端发送任何连接数据的情况下在各种位置生成玩家。


    数据序列化处理

    当你的想传送的数据不止一点半点,这时候就要对数据进行序列化处理进行传送,这里推荐一个高效率的序列化模块 --> MemoryPack

    MemoryPack

    开源链接:https://github.com/Cysharp/MemoryPack

    对于标准对象,MemoryPack比其他二进制序列化器快10倍,并且比其他序列化器快2到5倍。对于结构数组,MemoryPack更为强大,速度可比其他序列化器快50到200倍。

    MemoryPack采用了C#特定的、经过优化的二进制格式,是一个全新的设计,利用了.NET 7和C# 11,以及增量源生成器(.NET Standard 2.1(.NET 5、6),还支持Unity)。

    其他序列化器执行许多编码操作,如VarInt编码、标签、字符串等。MemoryPack格式采用了零编码设计,尽可能地复制C#内存。零编码类似于FlatBuffers,但不需要特殊类型,MemoryPack的序列化目标是POCO(普通C#对象)


    安装MemoryPack

    • Unity最低版本要求:2021.3

    • 如果你使用git方式获取MemoryPack,则需要在NuGet中安装System.Runtime.CompilerServices.Unsafe/6.0.0

    • 直接导入unitypackage则不需要额外安装

    下载release的unitypackage导入到项目当中


    Scripts新建一个脚本ConnectionData.cs

    using System;
    using MemoryPack;
    
    
    [MemoryPackable]
    public partial class ConnectionData
    {
        public readonly String Name;
        public readonly int Gender;
        public readonly String RoomPassword;
        public ConnectionData(string name, int gender, string roomPassword)
        {
            this.Name = name;
            this.Gender = gender;
            this.RoomPassword = roomPassword;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    GameManager.cs 进行数据处理反序列化

    using UnityEngine;
    using Unity.Netcode;
    using MemoryPack;
    
    public class GameManager : NetworkBehaviour
    {
        public GameObject Man;
        public GameObject Girl;
    
        public override void OnNetworkSpawn()
        {
            base.OnNetworkSpawn();
            if (IsServer)
            {
                NetworkManager.ConnectionApprovalCallback = ApprovalCheck;
            }
        }
    
        private void Update()
        {
            if (Input.GetKeyDown(KeyCode.O))
            {
                NetworkManager.Singleton.NetworkConfig.PlayerPrefab = Man;
                NetworkManager.Singleton.StartHost();
            }
    
            if (Input.GetKeyDown(KeyCode.P))
            {
                var data = new ConnectionData
                {
                    Name = "NueXini",
                    Gender = 0,
                    RoomPassword = "NueXini's room"
                };
                var bin = MemoryPackSerializer.Serialize(data);
                NetworkManager.Singleton.NetworkConfig.ConnectionData = bin;
                NetworkManager.Singleton.StartClient();
            }
        }
    
        private void ApprovalCheck(NetworkManager.ConnectionApprovalRequest request, NetworkManager.ConnectionApprovalResponse response)
        {
            var clientId = request.ClientNetworkId;
            var connectionData = request.Payload;
    
            var data = MemoryPackSerializer.Deserialize<ConnectionData>(request.Payload);
    
            Debug.Log(data.Name);
            Debug.Log(data.Gender == 0 ? "男" : "女");
            Debug.Log(data.RoomPassword);
    
            if (data.Gender == 0)
            {
                response.PlayerPrefabHash = Girl.GetComponent<NetworkObject>().PrefabIdHash;
            }
            else
            {
                response.PlayerPrefabHash = Man.GetComponent<NetworkObject>().PrefabIdHash;
            }
    
            response.Approved = true;
            response.CreatePlayerObject = true;
            response.Position = Vector3.zero;
            response.Rotation = Quaternion.identity;
            response.Reason = "Some reason for not approving the client";
            response.Pending = false;
        }
    }
    
    
    • 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
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69

    日志输出

    日志中可以看到数据可以被正确反序列化出来,MemoryPack对这种二进制数据处理速度非常优秀,值得去深入学习。


    后话

    MemoryPack作为一个序列化工具,可以在数据的存放等场景使用,并不局限于当前,例如一些存档,人物数据等等都可以使用


    学习链接

    https://neuecc.medium.com/how-to-make-the-fastest-net-serializer-with-net-7-c-11-case-of-memorypack-ad28c0366516

    https://www.cnblogs.com/InCerry/p/how-to-make-the-fastest-net-serializer-with-net-7-c-11-case-of-memorypack.html

    https://unity.com/cn/products/netcode

  • 相关阅读:
    云原生Kubernetes:Pod控制器
    SpringBoot 3.2.5 引入Swagger(OpenApi)
    基本IO接口技术——微机第七章笔记
    12030.LMK03000时钟合成器
    Spring MVC BeanNameUrlHandlerMapping原理解析
    C++ Reference: Standard C++ Library reference: Containers: deque: deque: resize
    力扣刷题记录(Java)(四)
    SQL血缘解析原理
    node笔记记录78模板引擎4
    【批处理DOS-CMD命令-汇总和小结】-文件与目录操作命令(md、rd、xcopy、dir、cd、set、move、copy、del、type、sort)
  • 原文地址:https://blog.csdn.net/a924282761/article/details/133282757