柠檬友玩

首页 > 游戏资讯 > 正文

已出动200人,已取得版号。这款自研UE产品遇到了哪些问题?

时间:2022-11-28 02:57:01

今年7月,早晚光年的自研赛车风格MMOARPG 《晶核》获得版号,并于9月首次开始测试。 目前,游戏在TapTap上获得了42万预约,维持着8.9的分数。

游戏采用立体的箱庭式关卡结构,每章由多个线性副本连接组合而成,玩家攻占整个章节后,关卡会出现在大范围的搜索区域,增加了新的隐藏路径和搜索内容。

制作团队表示,他们可以结合开放世界和传统副本推送游戏各自的优势,在保持传统副本游戏战斗一致性和目标感的同时,融入一些场景的沉浸感、探索感。

但是,制作小组表示,《晶核》也面临着很多挑战。 例如,为了让美术效果具有市场竞争力,游戏的大型箱庭从设计方案到最终呈现,即使不考虑手机端的性能优化,也至少需要8个月的制作周期,其间存在很多不确定性和重做。 在动画的渲染、战斗设计、同步机制等技术难度较大的部分,他们也经历了很长时间的探索。

在上周2022幻想引擎技术开放日,《晶核》的服务器架构师刘豪分享了项目面临的技术挑战和解决方案。

此外,目前球队保持在200多人的规模,制作多人团队副本游戏和大规模的公会游戏。 他说,这些玩法将是玩家后期玩法的核心内容。 在这些游戏中,由于玩家数量众多,游戏也面临着不小的性能压力。

刘豪表示,他们的目标是让玩家体验高帧频、高流畅度的多人ARPG,同时尽量不降低屏幕性能。

以下是葡萄君总结的演讲内容:

你好,我叫刘豪。 是《晶核》项目的服务器架构师。 今天,我的共享主题是《虚幻DS的机遇与挑战》。

主要分为三个部分,分享梦幻DS(dedicatedserver )带来的机遇、《晶核》项目面临的技术挑战和应对策略,最后给出使用梦幻ds的建议。

对我们来说,虚幻的DS有很多优点。 其一是依靠幻想的引擎,可以提供地图、寻路、同步、AI、技能等丰富的组件和插件。 这些部分的内容我们不需要自己实现。

其二,幻像具有非常友好的编辑器,而且功能强大,可以直接启动多个服务器和客户端,便于调试。 企划中的同学也可以通过编辑器轻松创建资产、添加技能等,无需从头开始实现配置或等待编辑器。

第三,幻像引擎是代码的开源,即使遇到某些引擎尚不支持的功能,也可以直接对源代码进行修改,从而使使用幻像引擎进行开发具有更大的灵活性。 这些优点帮助我们在项目初期很快建立了多人在线游戏的模型,节省了很多时间。

但是,在《晶核》的后续开发过程中,我们仍然面临着许多技术挑战,需要逐一克服。 接下来介绍《晶核》开发过程中遇到的技术问题和我们的解决方案。 面临的技术挑战主要包括与业务功能、系统托管、性能优化和更新维护相关的挑战。

首先,说明业务功能面临的挑战。 由于《晶核》是MMOARPG类型的游戏,因此既存在MMO的复杂业务功能,也存在ARPG的复杂技能机制。

要说MMO的业务功能复杂,那就是在简单列举的几个游戏中应该实现的业务功能。 有单衣登陆、创角、任务、装备、强化、商会等,还有服饰交易行、排行榜、PVE、PVP等,还有场景、复制、移动、战斗等功能。 所有这些业务用DS实现显然是不现实的,所以我们的做法是只做DS擅长的场景、战斗相关的业务,剩下的这些业务由我们自己写的逻辑服务器来实现。

最终得到的效果是,一组服务器中存在负责外围系统的逻辑服和负责场景战斗的场景服,客户端与逻辑服和场景服保持双线连接,同时在逻辑服和场景服之间也保持链接进行数据交换。 在这样的机制下,我们可以集中精力在DS上制作擅长的内容。 这样可以降低场景服开发的复杂度,更好地控制场景服的质量。

《晶核》的ARPG属性使得我们需要开发的技能机制非常复杂,我们目前有8个跳槽后的职业,每个职业有20多个特色技能。 另外,还需要考虑移动、跳跃和位移技能、空中战斗相结合的情况,在开发过程中遇到了许多与位移相关的问题。 在下一个视频中,我将简单展示《晶核》的技能机制。

视频见公众号原文

从视频中可以看到,游戏中远程、近战的职业有很多复杂的技能机制,技能期间的位移和打击表现也很多。 追击、空中连击、空中技能、击球等情况需要考虑。

我们最初实现的是可预测的移动和战斗,但由于存在命中和其他复杂状态,客户端经常释放技能或认为服务器无法释放。 最终展现给玩家的表现是举手回收。 这是我们的策划人不能接受的。

经过讨论,我们最后决定不具有移动带预测、技能带预测。 这带来了另一个问题。 移动波段预测由客户端先行,技能由服务器先行,从而在移动和技能连接时容易出现表达错误。 为了解决这个问题,需要对现有的技能组件进行很多入侵性的修改,这容易引起另一个问题。

最后,经过调查,我们决定使用UE的网络保护框架重构整个移动模块。 重构完成后,可以根据业务需求定制开发移动逻辑,从而大大减少移动和技能释放过程中出现的问题。

关于业务功能中面临的课题,接下来我们来看一下搭载系统带来的课题。 幻想引擎DS在一个过程中只能承载一个场景。 此外,由于要模拟的内容很多,单个进程的资源开销也很大。 在MMO中,场景的数量很多,因此最终过程的数量也会增加。

要说资源开销大,请看这张图。 在这个视野中,已经可以看到20多个玩家和4、5个NPC。 想象一下,如果有很多人在这个场景中,随着人数的增加,同步的数据量在平方水平上增加。

为了解决这个问题,我们采用了划线机制。 一条线上最多允许100名玩家进入,如果超过100人,就会开设新的线,并将玩家分配到新的线上。 通过这种方式,可以将单个进程的资源开销控制在可接受的范围内。 同时也避免了很多玩家在一张地图中,同步开销为n^2的问题。

如果知道了线,进程数会更多。 原来一张地图只需要一个过程,现在每100个人就需要一个过程。

在这里可以进行简单的计算。 现在一组服务器有1万人在线的时候,所有人都在大地图上,每100个人需要一个过程,需要100个过程。 但是随着游戏的发展,玩家需要进入副本进行体验。 假设现在同时有20%的人制作复印件,那就是2000人。 每人一个拷贝需要2000个过程,四人一个拷贝需要500个过程。 而且这只是衣服,当我们穿了成百上千的衣服时,过程数量会非常多。

为了解决这个问题,我们决定将游戏初期的推送副本设为离线副本。 所有战斗计算都在客户端进行,通过逻辑服进行退房、结算等。 这将减少项目初期大量的场景服过程数。

对于大地图和在线图书等必须在线进行的游戏,将场景服进行集群。 所有逻辑服共享该集群中的场景服资源,某逻辑服需要场景服时,向集群申请,连接场景服使用。

我有刚开放的衣服。 很多玩家都在大地图和离线图书上。 需要的场景服会变少。 开放一段时间后的衣服,大多数玩家都在玩在线图书。 需要的场景服会变多。 通过该方法可以综合不同阶段逻辑服对场景服的需求量。提高提高了场景服的使用效率,避免了大量场景服闲置的情况,而且这种做法也有利于我们后续跨服游戏的开发。

除了业务功能和系统方面的挑战外,性能优化方面也存在巨大挑战。 接下来,我将介绍我们进行了哪些性能优化。

性能优化主要包括两个方面: CPU优化和内存消耗优化。 首先,说明CPU的优化。 通过分析发现,场景软件上的CPU开销主要集中在属性同步、物理计算、移动计算和同步三个方面。 属性同步使用了前期只同步自己,不制作服务器拆分的Actor、网格同步、视距剪辑、下变频等多种优化方式。

优化属性同步时,第一步是减少需要同步的加速器数量。 我们要策划同学,就需要在玩家刚制作角的时候体验安静的山村感觉。 而且,随着等级的上升,你会看到越来越多的人。

我们可以在玩家等级较低时,让玩家只同步自己,其他玩家的数据不直接同步到客户端。 这将减少穿着初始场景衣服进行同步的加速器数量。

前期只同步自己

正如在下面的照片中所看到的,场景中存在很多NPC用于与玩家进行交互。 此外,每个玩家可以在宠物系统开放后携带宠物。 另外,也有像照片中的魔人偶师那样,随身携带魔人偶的职业。

如果它们都同步,则需要同步的加速器数量也会增加。 分析结果显示,地图中NPC提供的交互功能其实是逻辑服提供的功能,场景服无需保留这些NPC,且地图中没有战斗相关内容,也不需要宠物和魔偶。 因此,通过从场景软件中排除NPC、宠物和人偶,仅在客户端上创建和表示,进一步减少了需要同步的加速器数量。

然后使用ReplicationGraph插件进行定制开发,根据需要将所有Actor分为需要全图同步的组、根据距离需要同步的组、需要链接同步的组、需要团队同步的组,每个组

对于需要根据可视距离进行同步的Actor,每个游戏都提供了不同的可视距离。 由于大地图中人员密集,可视距离设定得相对较小,副本中玩家和怪物相对较少,而且战斗中的位移和技能可能影响的范围也较大,所以可视距离设定得相对较大,同步到全图。

移除不需要同步的加速器后,也会尝试降低必须同步的加速器的同步频率。 有些宏达可能在我的视野范围内,但他在我的照相机后面,我得转动镜头才能真正看到他。 此时,可以降低他的同步频率,从每秒10次降低到每秒3次或1次,从而减少平均每帧需要同步的数据量。

在游戏中,玩家经常要去某台NPC进行任务交互、装备搭建、换装等操作,此时玩家完全没有位移。 如果我们仍然以很高的同步频率使他的数据与周围的玩家同步,显然没有必要。 我们会降低这种不移动玩家的同步频率,并在他开始移动时重新开始满帧速率的同步。

在减少需要同步的Actor和降低可以下变频的Actor的同步频率后,我们也在项目后期清除了Actor无法使用的属性。 减少每次Actor同步时实际同步的数据量。 更新UE4.25版本后,使用推送模型减少了同步前属性比较的开销。

在使用推送模型之前,每次同步时,必须将所有属性与同步的数据进行比较,查看是否更改,然后确定是否需要同步。

但在实际开发中,仅仅在一帧期间修改一些数据,大多数比较可能是没有意义的。 使用推送模型后,可以对修改后的数据进行脏标记。 比较时只需比较标记为脏的数据是否已修改即可,大幅降低比较开销。

以上是属性同步的优化。 接下来,我们将讨论物理计算的相关优化。

首先,我从服务器上删除了角色和怪物的所有装饰性组件。 服务器上不需要这些组件,因此完全不需要服务器上这些组件的更新或计算开销。 然后,在服务器上关闭动画计算,仅在业务需要具体坐标时进行计算。 我给你看一段视频。

当角色正常运行时,服务器上的骨骼保持为TPos,实际上不需要播放奔跑动画。 角色释放技能时,在创建子弹之前先更新骨骼的正确位置一次,然后保持此状态直到下次需要更新骨骼位置,以便从正确的位置创建子弹。 这样可以大大减少服务器上动画计算的开销。

然后,还优化了移动同步的开销。

如上所述,我们使用NetworkPrediction重建了整个移动组件。 重构完成后,我们的处理方式是客户端主机侧进行移动的模拟,以ServerMove数据包的方式发送到服务器,由服务器进行验证。 如果在客户端主机端完全没有移动的情况下,我也不断地发送服务器移动包,那显然是不需要的,服务器检查的开销也会增加。

因此,可以在玩家没有移动的时候降低ServerMove数据包的发送频率,减少了协议的数据量,并且也减少了服务器上检查的开销。

在移动模拟时,我们以前缺省情况下对每帧执行查找流操作,这需要物理检测,而且开销也很大。 在我们不移动的期间,其实完全不需要这个检查。 所以,我们可以在玩家不移动的时候,降低FindFloor的频率,减少很多不必要的开销。

最后,对CPU的纸箱进行了底层优化。 因为一个帧的运行时间非常长,如果服务器出现较大的帧速率波动,也可能会影响后续逻辑的计算和前端的展示。 以客户端平滑帧频为参考,在服务器上也添加了平滑帧频机制。 如果CPU使用率超过80%,则会逐渐降低帧以控制CPU使用率。 默认情况下以30帧模式工作,但如果超过80%,将以80%的控制为目标计算当前帧速率。 当然,为了不使帧频过低,设定下限。

结束这个CPU相关的优化之后,再来谈谈内存相关的优化吧。

我们的内存优化主要基于Linux本身的fork接口提供的copy on write机制进行。 将与资源相关的内容(如映射、设置、怪物和播放器)预加载到父进程中,并从这些资源派生若干子进程,以便这些子进程可以共享父进程及其之间配置的所有物理内存仅当子进程需要修改某些内容时,才复制并修改。

我们现有的做法是在一个父进程中将100个子进程提交给for,可以大大减少这个组,也就是这100个场景服务器消耗的内存量。 在实际测试中,这种方法可以减少50%以上的内存使用量。

简要总结刚才共享的性能优化相关内容。 我们主要优化了CPU和内存相关的东西。 这些优化将CPU开销和内存开销优化50%以上。

但是在优化过程中必须优先满足业务相关的需求。 不能因为我优化,就策划出来需求,说这个不行,你这个支出太大了,这件事绝对不行。 我们的首要目的是给玩家带来更好的体验,所以在此基础上进行适当的优化。 所有这些优化都是为了降低资源开销,节约最终运输成本。

接下来,介绍更新维护中面临的挑战。 在更新维护的过程中,还是游戏,所以你开发了这么多内容。 你在线的时候,有可能没有考虑,或者有配置错误导致的错误。 这个时候,我们有必要考虑如何解决那个。

首先,它支持在线更新机制。 无需完全关闭场景服务,即可更新配置、资源和通过Lua脚本实现的这些功能。 这样,玩家就可以完全无意识地修复此服务的大部分bug。 同时,为了防止在这个场景的衣服中发生一些内存泄漏,或者逻辑可能没有打扫干净。 复制的场景衣服逻辑执行后,让其自己关闭,父进程重新启动一个。 这可能会导致前一个逻辑未被清理干净,从而影响后续逻辑,或者由于内存泄漏导致场景服务器内存持续增加。

在线更新无法解决的这些问题,例如c中出现的逻辑错误,在在线更新的情况下无法解决。 这时,我们又引入了版本号机制。 例如,我们在第一个时候配置场景服集群。 假设其版本号为10001,如果现在出现了无法通过在线更新解决的bug,我们首先修复它,然后拿出更高版本的,比如10002的场景服,为新版本的场景服做新的分类器逻辑软件优先选择版本号高的场景软件。 这样,我们就可以在玩家剪掉的时候,将他优先安排在更新的场景服上,解决在线更新无法解决的问题。

通过这种方式我们也可以实现滚动更新,在玩家在线的时候,我可以直接启动更高版本的场景服,强制玩家下线,然后不用采取让他们出场的方式,玩家当然,在后续版本启动的时候,我们会尽量让之前的版本也继续存在下去,即使一些玩家长时间在大图里,也不会掉线,老版场景服里的玩家离开了,我们那

除了以上四种挑战外,我们还遇到了一些其他挑战。 例如,我发现大地图存在很久之后,玩家在行走的时候总是会被拉一点。 分析结果表明,浮点型时间戳在描述时间时,在连续运行4小时以上后,其时间精度将无法描述毫秒级的精度,从而导致时间精度的损失。 如果最终反映在移动计算中,则计算出的移动位移会存在偏差,最终会被拉动。 发现这个问题后,我们扩展了时间精度。 将游戏中所有时间精度的字段从float扩展到double,彻底解决了这个问题。

另一个是有关同步顺序的问题。 举个例子吧。

这张照片中的玩家,各自的角色由Pawn、PlayerController、PlayerState三部分组成。 他各自都有自己的数据,也有自己的功能。 当他们同步到客户端时,客户端写逻辑时,可能需要三个数据到达才能进行某个逻辑。 例如,要让Pawn看到什么样的外观,外观数据存储在PlayerState中。

但是,当我执行判断逻辑时,PlayerState可能还没有同步。 如果我正常去写,我会需要两头堵车。 Pawn已同步。 怎么办? PlayerState已同步。 我想怎么办,这样写容易看漏,也容易发生问题。 为了解决这个问题,我们提供了代理中间层,我们提供了一个叫FutureCall的接口,当你依赖的所有Actor都需要同步后再执行业务逻辑的时候,调整FutureCall接口

如果此时所有依赖的Actor都已经下来了,则该逻辑将直接执行。 否则,在相关的Actor同步后,执行相应的业务逻辑。 这样可以降低编写代码时的复杂性,也大大降低错误的发生概率。 接下来是无缝的切割。 因为有需要从一个拷贝切换到另一个拷贝连续挑战的游戏。 通常,客户端必须断开与复制副本a的连接,然后才能连接到复制副本b。在这种情况下,网络波动可能会断开与复制副本a的连接,然后才能连接到复制副本b。

而且,在很多情况下,我连续挑战的时候,需要把复印件a中的一些逻辑拿到复印件b中。 因此,需要穿着逻辑服进行战斗数据的中继,有些是没有必要的。 基于幻像引擎( UE )中提供的无缝映射机制,我们支持在一个过程中直接从副本a切换到副本b的逻辑,以及客户端也从副本a切换到副本b的逻辑当然在使用无缝切割的过程中,我们也发现了一些问题,我们进行了很多修改并解决了。

以上是《晶核》在开发中遇到的技术问题和我们的处理方法。 最后给出使用梦幻DS的建议。

第一个建议是使用分布式编译系统,并同时打开unit build。 这两种方法可以大大缩短我们的编译时间,避免每天编译半天开发的情况,大大提高提高我们的开发效率。

二是组件迁移。 因为为了保持发动机的稳定性,一般将发动机和自己项目的代码分为两个仓库进行管理。 为了稳定性,引擎的代码仓库可能会在一段时间内更新。 但是,我们修改逻辑时,有时会修改引擎的某些组件,并经常进行修改。 但如果我只是每半年更新一次引擎,肯定不能满足频繁修改和测试的需要。 在这种情况下,可以将此组件或插件移动到项目的代码仓库中,以便更快地进行修复测试。

第三,提前制定代码计划。 在进行优化的过程中,我们发现许多不需要在服务器上运行的逻辑都在服务器上运行。 其实这可以在前期计划的过程中解决。 因为前后代码是一起写的,所以最开始写代码的时候,提前规划好哪些部分的代码在前端跑,哪些部分的代码在后端跑,前后代码跑,不仅减少了后续优化的工作量,而且前后代码也减少了最后一项建议是确保进行与服务器相关的监视。

包括与我们在开发中编译和打包失败相关的监视。 因为UE开发的时候,前端后端的同学都会修改同一个仓库里的代码,美术同学、策划同学也会提交相关的内容。 此时,如果有错误上传的东西,可能影响的范围会变大。

此时,我们使用自动打包机制,如果打包失败,可以立即在自己的工作组报警,及时解决,减少问题影响的时间。 此外,项目早期就要及早关注内存和CPU的状况,出现内存使用量上升、CPU开销上升、甚至内存泄漏、CPU死循环等情况,都需要及早发现并尽早解决。 可以每周进行一次检查。 这样,如果发现类似情况,马上定位在这一周内,我能修改什么,马上解决它。

最后,由于虚幻的DS是由c开发的,服务器崩溃可能是不可避免的。 我们如何在这次崩溃后尽快解决它,一个是进行监视。 另一点是,当我们在线时,包括测试时在内,关注并分析解决服务器崩溃中出现的酷睿文件,作为警示,最终解决和避免后续的服务器崩溃问题。

以上是今天我分享的内容。 谢谢您的聆听。