所有Unreal网游开发者都应该看的文章:使用虚幻引擎4年,再谈UE的网络架构

所有Unreal网游开发者都应该看的文章:使用虚幻引擎4年,再谈UE的网络架构
文章图片


文章转自公众号“游戏开发那些事”作者Jerish



这是【所有Unreal网游开发者】都应该看的一篇技术文章 。

我从16年开始接触unreal , 到如今已经4年了 。 最近看了不少关于网络同步的论文和书籍 , 总算是理解了Doom和Quake这种古董级游戏的发展历史 , 对其网络架构也有了更深一层的认识 。 这次想根据自己的工作和学习经验 , 以一个全局的视角来重新回顾一下虚幻的网络模块 , 并总结一些我们常见的问题 , 相信对UE同步细节模糊不清的你看完后一定会醍醐灌顶 。

开始前 , 我先给初学者一个建议 。 如果你打算看UE4的同步源码 , 最好先大致阅读一遍这本书——《网络多人游戏架构与编程》 , 里面基本涵盖了UE4同步框架的大部分内容 , 可以让你少走不少弯路 。

所有Unreal网游开发者都应该看的文章:使用虚幻引擎4年,再谈UE的网络架构
文章图片


下面进入正题:

网络同步 , 就是使各个客户端上的角色表现保持一致 , 属于游戏引擎的高级功能 , 所以一般我们都将其归于Gameplay模块当中 。 不过具体的实现方案其实会深刻影响到底层的网络架构(甚至是整个游戏架构) , 我们既要决定通过哪种网络协议来完成 , 又要决定游戏各个模块的循环执行顺序 , 其实已经不单单是“Gameplay
”层面的东西了 。

虚幻引擎属于标准的CS架构(经过无数次改版的) , 内置状态同步功能 , 其同步频率与游戏的帧率相同 , 属于变长步更新 。 由于帧率完全受CPU、GPU性能的影响 , 所以网络同步的频率与整个项目的性能息息相关 。 不过 , 有一点我们要认识到 , unreal已经是尽可能的按照自己最快的速度进行数据的发送与接收了 , 只要我们做好各方面的性能优化即可 。

一、RPC与属性同步


在Unreal里面 , 同步有两种手段 , 即RPC与属性同步(很多服务器引擎都是如此) 。 与其说RPC是同步手段 , 不如说他是一种传输数据的方式 , 好处就是可以直接通过类的函数形式书写 , 方便理解 。 同时不需要你直接写Socket , 也不需要你处理封包和拆包 。 在计算机网络的概念里面 , RPC叫做“远程过程调用” , 本质上就是一种传递数据的手段 , 而其实现方式既可以是应用层的Http , 也可以是传输层的TCP/UDP 。 在虚幻里面 , 由于很多游戏的同步(比如FPS)对网络延迟要求比较苛刻 , 所以我们放弃了需要三次握手的TCP而改用UDP(更不可能考虑HTTP了) 。 RPC既可以标记为可靠 , 也可以标记为不可靠 。 可靠的RPC最终一定会到达目标终端 , 但不可靠的RPC除了在网络拥挤的环境下丢失 , 也可能在引擎限流的情况下被提前拦住 。 RPC本身并不是一个可以持续存在的对象 , 我们只能通过RPC参数“一次性”的将数据从一端发送到另一端 , 所以每个RPC调用只能“只执行一次”(可以理解为生命周期只有瞬间的)
。 如果RPC消息从网络中丢失 , 那么他就会永久的丢失(不可靠的RPC) , 所以并不适合游戏世界各种对象的状态恢复 , 必须要结合可以保持对象状态的属性才行 。 此外 , UE4里面RPC并不支持回调 , 所有RPC函数的返回类型都是void 。

属性同步 , 本质上属于一个比较上层的功能特性 , 是以每个对象为单位处理的(不支持更细粒度的同步 , 但理论上可以通过条件属性做部分调整 , 详见AACtor::PreReplicate) 。 unreal的服务器会按照一定频率的去执行同步对象属性的数据发送和接收 , 同时处理回调函数 。 属性同步的产生是为了维持对象的状态 , 是一个从概念上非常贴近“同步”二字的功能 , 一旦服务器上的同步属性发生了变化 , 就一定会发送给客户端(注意:属性同步只是服务器向客户端的同步 , 不存在客户端向服务器流通


推荐阅读