深入解析:【Unity】uNet游戏服务端框架(一)服务端架构设计

news/2025/11/7 12:47:34/文章来源:https://www.cnblogs.com/gccbuaa/p/19199333

更新日期:2025年10月9日。
项目源码:获取源码。

索引

  • uNet游戏服务端框架
    • 一、uNet源码结构
    • 二、uNet架构设计
      • 1.网络玩家 NetworkPlayer
      • 2.网络实体 NetworkEntity
      • 3.网络地图 NetworkMap
      • 4.网络房间 NetworkRoom
      • 5.启动服务端

uNet游戏服务端框架

uNet游戏服务端框架为使用.Net Core开发的高性能、高并发网络游戏服务端框架,基于async / await的多线程架构天然适应IO高并发环境,使用Protobuf进行网络数据交换能够极大的降低带宽和网络延迟,同时使用对象池技术管理服务端中的大多数实例能够显著的降低GC开销。

一、uNet源码结构

uNet解决方案目录中,存在4个项目:

在这里插入图片描述

uNet.Core:uNet框架的核心代码模块。
uNet.Engine:uNet框架中与Unity引擎进行同步交互的功能实现模块。
uNet.Example.ChineseChess:中国象棋的游戏服务端。
uNet.Example.MMO:MMORPG的游戏服务端。

二、uNet架构设计

uNet中,将一个游戏服务端程序中可能出现的所有实例划分为了如下的四类:

类型描述
网络玩家代表网络中的玩家客户端实例
网络实体代表存在于地图、房间中的具备网络同步需求的实体(比如NPC、副本中的BOSS)
网络地图代表可同时容纳大量玩家、大量实体的游戏场景(也即是游戏中的主城)
网络房间代表可同时容纳少量玩家、少量实体的游戏场景(也即是游戏中的副本)

1.网络玩家 NetworkPlayer

网络玩家由NetworkPlayer类表示,一个NetworkPlayer实例即代表了存在于当前服务器中的一名玩家客户端,他的基础属性如下:

/// <summary>/// 网络玩家
/// </summary>
public abstract class NetworkPlayer : IObjectPoolable
{
/// <summary>/// 玩家的ID
/// </summary>
public long ID { get; private set; }
/// <summary>/// 玩家姓名
/// </summary>
public string? Name { get; protected set; }
/// <summary>/// 在本次同步中是否已改变
/// </summary>
public bool IsDirty { get; set; } = false;
/// <summary>/// 心跳包校验码
/// </summary>
public abstract int HEARTBEAT { get; }
/// <summary>/// 常规信息校验码
/// </summary>
public abstract int NORMAL { get; }
//........
}

ID:玩家的ID,玩家在当前游戏服务器中的唯一标识符,重新登录后会改变。
Name:玩家的姓名。
IsDirty:在本次同步中是否已改变,在执行网络同步时,只有标记为改变的玩家才会被同步。
HEARTBEAT:心跳包校验码,在心跳机制中,用于鉴别心跳包的校验码。
NORMAL:常规信息校验码,区别于心跳包的常规信息数据包的校验码。

由于NetworkPlayer兼顾了与客户端进行双向通信的使命,所以他自身具备了区别心跳包常规信息数据包的能力。

NetworkPlayer中已封装了用于收、发数据的相关方法(使用Socket收、发),直接调用即可:

/// <summary>/// 发送数据到客户端
/// </summary>
/// <param name="bytes">数据内容</param>
/// <param name="token">用于取消异步的token</param>
/// <returns>是否发送成功</returns>
protected async Task<bool> SendDataAsync(byte[]? bytes, CancellationToken token){//代码后续讲解......}/// <summary>/// 从客户端接收数据/// </summary>
/// <param name="token">用于取消异步的token</param>
/// <returns>网络消息</returns>protected async Task<NetworkMessage?> ReceiveDataAsync(CancellationToken token){//代码后续讲解......}

2.网络实体 NetworkEntity

网络实体由NetworkEntity类表示,除了玩家以外的,存在于地图或副本中的其他需要进行网络同步的实例,都统称为网络实体。

比如副本中的小怪和BOSS,他们需要进行网络同步,以在不同的玩家客户端中表现为相同状态(比如相同的血量,相同的攻击姿态),所以他们网络实体。

但某些NPC,站在原地不动,玩家仅仅能点击他进行对话或接受任务,他们不需要进行网络同步,所以他们不是网络实体。

NetworkEntity的基础属性如下:

/// <summary>/// 网络实体
/// </summary>
public abstract class NetworkEntity : IObjectPoolable
{
/// <summary>/// 实体的ID
/// </summary>
public long ID { get; private set; }
/// <summary>/// 在本次同步中是否已改变
/// </summary>
public bool IsDirty { get; set; } = false;
/// <summary>/// 实体名称
/// </summary>
public abstract string Name { get; }
/// <summary>/// 实体类型
/// </summary>
public abstract string Type { get; }
//......
}

ID:实体的ID,实体在当前地图或副本中的唯一标识符,不同类型的实体可能重复。
IsDirty:在本次同步中是否已改变,在执行网络同步时,只有标记为改变的实体才会被同步。
Name:实体的名称,同一类型的实体,他们一般具有相同的名称。
Type:实体的类型,用于在网络环境中区分实体(比如服务端的某个实体Type为Enemy,客户端的相同实体的Type也应该为Enemy,确保在网络同步时能够正确定位到该实体)。

3.网络地图 NetworkMap

网络地图由NetworkMap类表示,一个NetworkMap实例即代表了存在于当前服务器中的一个地图场景,在地图中可容纳大量玩家或实体,玩家与实体之间产生交互并经过网络同步,最终完成一整套的游戏玩法。

交互
交互
收集状态数据
收集状态数据
状态同步
状态同步
玩家
实体
地图

他的基础属性如下:

/// <summary>/// 网络地图(用于容纳大量网络玩家和大量网络实体)
/// </summary>
public abstract class NetworkMap : IObjectPoolable
{
/// <summary>/// 地图名称
/// </summary>
public abstract string Name { get; }
/// <summary>/// 地图类型
/// </summary>
public abstract string Type { get; }
/// <summary>/// 执行网络同步的间隔时间(毫秒)
/// </summary>
public abstract int SyncInterval { get; }
}

Name:地图的名称,同一类型的地图,他们一般具有相同的名称,且地图实例本身就是唯一的。
Type:地图的类型,用于在网络环境中区分地图(比如服务端的某个地图Type为Map1,客户端的相同地图的Type也应该为Map1,确保在网络同步时能够正确定位到该地图)。
SyncInterval:执行网络同步的间隔时间(毫秒),地图拥有自动对其中的玩家和实体进行网络同步的功能,此为2次同步之间的间隔时间,设置得越低同步频率越高,但同时服务端压力也越大,可能导致网络延迟卡顿。

注:通常情况下,地图的同步间隔时间可以设置较长,以降低性能开销。

4.网络房间 NetworkRoom

网络房间由NetworkRoom类表示,一个NetworkRoom实例即代表了存在于当前服务器中的一个房间场景,在房间中可容纳少量玩家或实体,玩家与实体之间产生交互并经过网络同步,最终完成一整套的游戏玩法。

交互
交互
收集状态数据
收集状态数据
状态同步
状态同步
玩家
实体
房间

由于同一类型的NetworkRoom是可以创建多个的,所以他们在大多数时候也被叫做副本

他的基础属性如下:

/// <summary>/// 网络房间(用于容纳少量网络玩家和少量网络实体)
/// </summary>
public abstract class NetworkRoom : IObjectPoolable
{
/// <summary>/// 房间ID
/// </summary>
public long ID { get; private set; }
/// <summary>/// 房间名称
/// </summary>
public abstract string Name { get; }
/// <summary>/// 房间类型
/// </summary>
public abstract string Type { get; }
/// <summary>/// 执行网络同步的间隔时间(毫秒)
/// </summary>
public abstract int SyncInterval { get; }
}

ID:房间的ID,在当前服务器中的唯一标识符,不同类型的房间可能重复。
Name:房间的名称,同一类型的房间,他们一般具有相同的名称。
Type:房间的类型,用于在网络环境中区分房间(比如服务端的某个房间Type为Room1,客户端的相同房间的Type也应该为Room1,确保在网络同步时能够正确定位到该房间)。
SyncInterval:执行网络同步的间隔时间(毫秒),房间拥有自动对其中的玩家和实体进行网络同步的功能,此为2次同步之间的间隔时间,设置得越低同步频率越高,但同时服务端压力也越大,可能导致网络延迟卡顿。

注:通常情况下,房间的同步间隔时间可以设置较短,以带来更流畅的体验。

uNet的网络同步采用的是状态同步的方式,而网络同步的时机为固定频率同步,这不一定适合所有游戏,只是我们本系列教程所采用的方式,当然,其他方式(比如帧同步)后续可能也会考虑。

5.启动服务端

启动服务端的话将非常简单,比如通过查看MMORPG的服务端入口函数Main,将看到极简的代码:

namespace uNet.Example.MMO
{
class Program
{
static void Main(string[] args)
{
//定义服务端配置信息,比如监听的IP地址、端口号,玩家类型(继承至NetworkPlayer,同一游戏服务端中只能存在一种玩家类型)
ServerConfig config = new ServerConfig("127.0.0.1", 11000, typeof(MMO_Player), 10, 20);
//创建服务端入口
ServerEntry entry = new ServerEntry(config);
//创建一个地图(比如这里是初始地图:暴风要塞)
entry.CreateMap<MMO_BeginnerMap>();//启动服务端entry.Start();//启用常规日志的打印显示Log.IsEnableInfo = true;//按下ESC键退出程序ConsoleKeyInfo consoleKeyInfo = Console.ReadKey();while (consoleKeyInfo.Key != ConsoleKey.Escape){consoleKeyInfo = Console.ReadKey();}}}}

服务端为控制台程序,启动完成后如下:

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/958732.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python哈希机制深度解析:从底层原理到工程实践

Python哈希机制深度解析:从底层原理到工程实践 摘要:本文系统剖析Python哈希机制的实现原理、冲突解决策略及数据类型适配规则,通过理论溯源、源码分析与多维度实验验证,揭示其在字典、集合等核心数据结构中的底层…

LaTeX学习笔记:数学公式编辑

LaTeX学习笔记:数学公式编辑LaTeX学习笔记:数学公式编辑 数学公式的编辑一直以来都是我们在撰写科学类文章过程中所面临的最大麻烦之一,相信大家之前应该都尝试过各种在电子文档中输入数学公式的方法,但这些方法多…

容器未正确挂载指定目录 (通常与 目录不存在、权限不足、路径拼写错误 或 系统安全策)

容器未正确挂载指定目录 (通常与 目录不存在、权限不足、路径拼写错误 或 系统安全策) 第一个参数: -v 特别注意⚠️: 以上 -v ~/zapas/dbdata/mssql:/var/opt/mssql/data ~ 等于 /home/当前用户目录 即等于…

飞牛OS Root用户SSH公钥登录完整教程

飞牛OS Root用户SSH公钥登录完整教程 前言 飞牛OS(fnOS)是一款基于Debian的NAS操作系统,提供了强大的数据存储和管理功能。在日常使用和管理过程中,SSH远程登录是必不可少的重要工具。然而,出于安全考 虑,飞牛OS…

红黑树简

package J_TreeSet;import java.util.Objects;public class B_Student implements Comparable<B_Student>{private String name;private int age;public B_Student() {}public B_Student(String name, int age) …

⸢ 柒-Ⅲ⸥⤳ 可信纵深防御建设方案:数据使用可信端安全可信 - 详解

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

【日记】我从来没见过有酒店这么设计的(533 字)

正文出差结束,终于回家了。回到自己的小房间之后,仔仔细细想了一下,发现自己有好多事情都没做。屯了好多经济学的文章没有看、内科学的笔记、买菜、写文章(日记、学海计划、实用类随记、计算机指南,今年的年度总结…

第181-182天:横向移动篇PTH哈希PTT票据PTK密匙Kerberoast攻击点TGTNTLM爆破

首要知识点: pass the hash(哈希传递攻击,简称pth) pass the ticket(票据传递攻击,简称ptt) pass the key(密钥传递攻击,简称ptk) PTH(pass the hash) #利用的lm或ntlm的值进行的渗透测试(NTLM认证攻击)…

2025年上海装修设计标杆公司最新推荐:中古风装修/轻法式装修/现代简约装修/极简风装修、上海千祥建筑定义品质居住新标准

随着城市化进程深化及居民对居住品质要求的提升,家装行业正经历从基础施工向设计美学、环保健康与全程服务一体化的转型。2025年,装修需求预计进一步释放,但市场上装修公司设计水平、施工质量、材料环保标准及售后服…

AI在开源情报搜集系统中的应用汇总

大模型在开源情报系统中的应用已贯穿采集、处理、分析、决策全链条,形成了一个从“数据获取”到“认知生成”的智能闭环。上述功能体系不仅提升了情报工作的效率与深度,更推动了情报模式从“被动检索”向“主动洞察”…

清理docker的overlay2目录

使用Docker时,镜像和容器数据都存储在Docker的存储目录中,默认是/var/lib/docker。在Docker使用overlay2存储驱动时,/var/lib/docker/overlay2目录包含了overlay2存储驱动所使用的文件和目录。 overlay2是Docker的一…

升鲜宝生鲜配送供应链管理系统---PMS--商品品牌多语言存储与 Redis 缓存同步实现

升鲜宝生鲜配送供应链管理系统---PMS--商品品牌多语言存储与 Redis 缓存同步实现 商品品牌多语言存储与 Redis 缓存同步实现文档 本设计文档说明商品品牌(pms_brand)在支持多语言环境下的数据存储、翻译同步及 Redis…

网站在苹果 Safari 进行适配遇到的问题

在网站进行移动端 Web 适配开发中,弹窗和导航栏弹出等常常会出现一些问题,如果是奇奇怪怪的客户严格要求的话,那么就会有下面这些情况:打开弹窗后页面自动放大,视图区被放大到看不全 打开对话框打开后背景仍然能滚…

Python对象模型的认知陷阱:类的`__name__`属性与名字绑定的本质辨析

Python对象模型的认知陷阱:类的__name__属性与名字绑定的本质辨析 摘要:本文通过一个典型的元类使用错误,深入剖析Python对象模型中“类的名称属性”与“名字绑定”这两个常被混淆的核心概念。许多开发者在动态创建…

Python环境教程(三)-环境高级之uv pixi

UV 官网:uv 中文文档 Github地址:astral-sh/uv: An extremely fast Python package and project manager, written in Rust. 什么是uv? uv 是由 Astral 公司开发的一款 Rust 编写的 Python 包管理器和环境管理器,它…

升鲜宝生鲜配送供应链管理系统---PMS 商品模块 + 动态翻译设计说明

PMS 商品模块 + 动态翻译设计说明书 一、模块总体定位 PMS(Product Master System)是供应链体系的商品主数据中心,负责统一维护商品的品牌、分类、标签、单位、材质、存储方式、分拣区域、SPU、SKU 及多语言翻译。 …

深入浅出 SPA/MPA

概述 在 Web 应用架构设计中,单页应用(SPA)与多页应用(MPA)是目前两种主流的前端架构,他们各自适用于不同的业务场景。 作为一个前端开发,理解这两种模式的核心原理、技术实现及优劣势,对于我们未来选择合适的…

CPP 学习笔记 语法总结 - 阿源

CPP 学习笔记秋招的时候(嵌入式方向)面试官常问到 C++,因此花了几天过了一下基础知识,本文为学习笔记。快速学习的经验:如果有其他语言基础的情况下,想要学习一门新语言,让 AI 帮你列一下这个语言的学习大纲或者…

2025 11 7

p3199考虑二分,然后判负环一个分数规划的基础应用第21场T1,从后往前贪心 15min T2,对a整除分块,后面的那个 b 有点难搞,但是设 \(\frac{i}{j}\) 下取整的值为 \(a\) 可以发现这个可以在 \(b\) 数组中体现为 \(b_0…

深入解析:大数据集群环境搭建(Ubantu)

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …