Unreal Fest 2023

时隔3年终于又有线下的技术分享大会了,这几年UE的技术发展确实很快, 这次有机会来参加UE的技术分享还是挺开心的。

第一天前两场都是老外的开场,介绍UE5的新功能,这些官网都有详细介绍,其中比较有意思的是UEFN平台,是堡垒之夜Mod编辑器加分享平台,可以利用堡垒之夜的资源制作自己的玩法、关卡提供给其他玩家玩。平台也提供推广、付费分成这些。UGC确实是一个风口,Epic在这方面也是通过UEFN平台在发力。

《 基于虚幻引擎的数字孪生开发平台客户端搭建 》

因为A区索尼在卖广告,就跑来B区听了,意外发现很有意思。现在制造业里面不仅会使用UE来做一些产品展示,还会通过图像识别或者在生产线中加装传感器来收集各种数据,然后在UE里面还原一个生产(监控)现场,再利用游戏引擎自带的碰撞体或者其他Trigger机制来触发他们关心的各种事件,配合蓝图来做后续各种控制。这就好比现实工厂是服务端,产生逻辑数据(或操作),UE作为客户端同步构建现场,再触发各种事件以后通知回服务器(工厂)。分享里还举一个状态同步及一个帧同步的例子。状态同步就是通过图像识别获取汽车信息及位置,在UE里还原汽车的速度,行驶轨迹,检测是否越线超速这些。帧同步的例子就是生产流水线上有传送带和升降机等各种机械信号,这些信号就是针对流水线上物品的操作,通过帧同步的方式下发操作,在UE内(客户端)还原出实际的物品状态,再通过各种Trigger监听是否有意外情况的发生。而他们使用的蓝图节点也是定制的,通过反射自定义数据自动生成他们需要的蓝图节点。网络同步、自定义的图像化编程,这些都是最近这几年有在做的东西,想不到这些技术游戏技术与制造业已经能如此结合,真是大开眼界。

Continue reading

C#与.Net

最近用C#开发一套独立的编辑器,使用WPF界面框架,引入了Telerik界面库。后来为了让处理数据的逻辑能跨平台运行又创建了一个.Net Core的console app来完成这部分独立的功能。做Unity开发的时候也知道mono可以支持C#代码的跨平台运行,在此打算把C#生态涉及到的各种概念梳理一下。包括C#、.Net、.Net Framework、.NetCore、.Net Standard、mono、MAUI、WPF、Telerik、CIL、CLR、ECMA标准等等。

最初C#是微软推出的基于.Net Framewok的编程语言。C#与Java一样是托管语言,通过编译器生成中间语言 CIL( Common Intermediate Language ),再在运行时由中间语言运行时库CLR( Common Language Runtime)翻译执行并调用对应系统的API来工作。因为C#语法比较接近C/C++,但具有托管语言的优势(内存管理,异常机制等),很快流行起来。但当初的.Net Framework只支持Windows平台,就有公司及开源社区希望能让C#跨平台运行,这就是mono的出现。此后C#语言就不再是微软自家的产品了,需要有统一的标准。关于C#语言及C#编译出来的中间语言CIL的标准由欧洲计算机协会ECMA(European Computer Manufacturers Association)制定。

Continue reading

帧同步技术(二)

第一篇文章中我们讲了帧同步的核心:如何保证各个客户端的一致性。保证不同客户端各自计算的结果都相同就能确保帧同步玩法的正确有效,但如果服务端消息没下来前整个客户端画面一动不动,体验是非常不好的。在确保一致性的前提下做一些预表现以及降低网络传输的延迟能给到玩家更好的体验。这篇文章主要讲这方面的一些优化,另外还有关于不同步问题的定位排查、防止客户端修改作弊、断线重连与网络消息堆积时的一些处理方案。

UDP传输:TCP传输因为在底层做了各种关于可靠性及稳定性的处理(详细可见《计算机网络——传输层:TCP与UDP》),所以延迟会比较高。而在帧同步战斗中,操作需要上行到服务器然后经过转发到达到各个客户端才能推进真正的逻辑,低延迟对玩家操作体验非常重要。而帧同步战斗这种频繁(1秒30帧)的传输小量(只转发操作)的数据,用UDP也是很有优势的。在相同的网络环境下,UDP可以在一个逻辑帧内完成来回的,延迟在33ms以内,而使用TCP至少要3-4个逻辑帧才能完成来回,延迟在130ms以上。

使用UDP传输需要自己处理乱序和丢包的问题。帧同步战斗中,服务器定时派发的帧数据本来就是有序号的,所以乱序到达的问题只要缓存起来按顺序使用就可以了。而丢包的问题我们可以采用冗余传输来尽量避免。服务器一次下行中不仅带上当前第n帧的信息,还可以带上n-1,n-2或更多的冗余信息,这样只要不是连续丢多个包,都能保证客户端最终收到连续的帧信息。如果客户端当前在等第t帧, 但已经收到第m帧的信息,m-t的差值大于一定程度,就认为已经连续丢了多个包,这个时候靠冗余信息已经拼凑不回来完整的序列了,就需要利用TCP重新请求缺失的帧,服务端用TCP把客户端请求的帧信息重新补发。利用TCP来做请求重传虽然速度慢,但可以保证一定能收到。具体流程图如下:

Continue reading

帧同步技术(一)

关于帧同步技术原理及实现方案网上已经有非常多的文章介绍了,但做《月夜狂想曲》的帧同步战斗时还是有遇到很多具体的细节问题,也做了很多相关处理,在这打算分两篇文章记录一下。第一篇主要讲客户端如何保持一致性,会遇到哪些问题以及怎么处理。第二篇主要讲通过哪些改进可以让帧同步有更好的游戏体验。

帧同步的原理是,服务器只负责收集指令,然后以恒定帧率(例如30帧1秒)转发指令,真正的游戏逻辑由各个客户端各自计算,客户端要等到服务器派发的指令才能推进逻辑,没有收到指令时逻辑是暂停的(LockStep)。帧同步最重要的是确保各个客户端在不同硬件不同平台下各自计算游戏逻辑结果都是一致的。在Unity中为了达到这个目标,我们需要解决以下问题:

随机数:Unity自带的随机数因为有可能会被物理系统,粒子系统,UI系统,第三方组件等各种模块使用,我们是无法保证他在不同客户端下每次都能取到统一的随机数的。这就需要我们自己实现一套自己控制的随机数发生器,关于如何实现随机数的算法,之前写过一篇文章介绍《随机数生成算法》。在有可控的随机数发生器后,我们需要查找项目中所有用到随机数的地方,判断该流程是逻辑相关需要被统一接管的,还是表现相关可以由各个客户端自由决定的,从而使用不同的随机数发生器。 目标就是确保逻辑相关的流程下在各个客户端下都能取到同样的随机数。

Continue reading

游戏开发安全问题

这几年开发Unity手游时,陆续会针对安全问题做一些处理,在这里分享一下我们的一些做法。我将安全问题分为四大块,每一块都有很多可以深入挖掘的点,也有专门做安全的部门或第三方支持。这里更多介绍的是一些项目组会用到的安全策略。

—— 数据安全

数据安全首先需要处理的是内存安全,面对大量的内存扫描,内存修改工具,如果项目内的核心数据是裸放在内存中的话,肯定避免不了被改属性或者锁血这些问题。 内存安全我们的具体做法是把关键数据int或float的4字节随机映射到一块36字节的空间内。

Continue reading