我们如何制作引擎和游戏长达一年半。 第二部分 基础设施

首先,对上一篇文章的痕迹进行一些评论。 我们确实曾经在Wargaming工作,在那里我们开发了一个称为dava.frameworkdava.engine的引擎。 因此,与我们保持着良好关系的许多老同事都积极参加了讨论。

许多人对此表示怀疑:这是同一技术还是另一技术? 答:这是从头开始编写的新技术。

短短一年内我们如何管理? 我们的团队拥有丰富的经验。 许多公司已经开发引擎和游戏超过15年。

为什么要从头开始,如果您可以使用我们的旧引擎,它也是开源的? 他大约10岁,大多数代码已经过时。 我们引以为傲的引擎最好的部分,有时甚至包含一些代码,还包含5、7甚至10年前的基础知识。 许多建筑解决方案都是为当时的设备设计的-从3G iPhone开始。 现在,我们至少关注于iPad Air 1和功能强大的Android设备。 因此,方法有所改变。

最常见的问题是:为什么要拥有自己的发动机? 在上一篇文章中,有几种不同程度的说服力的论点。 我想专注于最主要的事情:只有我们自己的技术才能让您充分利用铁,针对您的游戏玩法和视觉风格进行最大数量的优化。 我们将自己定位为一家技术公司,而不仅仅是游戏开发商。 我们相信,凭借我们的工程师水平和我们的经验,我们可以在高科技移动产品市场上认真竞争。

现在到了关键点:什么工具和技术帮助我们在短时间内完成了这一雄心勃勃的任务?

基础设施


我们选择了Atlassian Bitbucket Server + Jenkins。 Jenkins连接到的主存储库(主存储库)位于Bitbucket中。 每个开发人员都有自己的分叉。 对于每个任务,将在派生中创建一个新派生,并通过拉取请求将其重新集成。 通常,该方案是非常标准的。 每个请求都必须接受强制审查和自动测试。 并且,如果成功,它将自动合并到母版中。

詹金斯


詹金斯(Jenkins)有几个缺点:他是一个古老但不太快,贪食的网络枪口,看上去就像90年代的互联网门户。 但是,即使在2019年,它的灵活性,大量模块和免费功能也使其成为一个不错的选择。 通过使用模块和设置,您可以实现可消化的外观,即对管道的声明式描述(位于存储库中)。 顺便说一下,现在大约有40条管道:测试,编辑器,适用于所有平台的游戏; 与服务器基础架构和元游戏一起使用。 收集所有20个buildagentov。

当然,将来,我想尝试现代的时髦解决方案,例如GitLab或自托管的TravisCI。 由于我们的存储库,资产的大小以及相应的构建时间和工件的大小,我们没有考虑完全的云解决方案(Nevercode,Bitrise,CircleCI等)。

建立系统


该系统的主要要求如下:用一个脚本为iOS,MacOS,Android,Windows,Linux生成项目。 我们设法尝试了Premake,SCons,Bazel和CMake。 由于各种原因,我们停止了经过时间考验的CMake。

近年来,CMake已几乎成为C ++库的标准。 从Abseil到SDL的几乎所有内容都可以在几行中连接到您的CMake项目。 当然也有一些例外,例如OpenSSL或V8,我不得不为此付出一些努力。 在裸露的Zmeik之上,我们开发了一个小型框架(总共约3,000行)。 主要特点:
模块化。 发动机的各个部分设计为模块。 例如,声音,UI,物理,网络等。 每个模块可以拥有自己的资产(例如,着色器),并且可能对其他模块具有依赖性。

引擎上的最终应用程序(游戏,编辑器,实用程序)仅连接所需的那些模块。 核心模块相差不大,它是大多数其他模块的依赖项。 核心实现入口点,主要应用程序周期,与操作系统和其他基本实体的交互。
第三方模块。 我们的框架允许您以多行下载git存储库或存档,解压,编译,复制库和/或源代码。 如今,我们有66个此类第三方模块:分析,第三方文件格式,中间件(如物理),声音库等。

开发过程


根据以前的经验,我们决定将引擎和游戏都添加到一个存储库中。 这使您可以轻松地更改引擎API并同步调整游戏。 结果就是所谓的单一存储库,它具有优点和缺点。 但是,由于我们立即计划保持很高的发展速度,因此引擎和游戏同步重构的可能性超过了此解决方案的所有其他缺点。

平均而言,我们每天会增加20多个拉取请求。 这意味着母版每天可能被破坏20次。 幸运的是,早在1991年,他们就提出了持续集成技术。 我们来了什么?

持续整合


如上所述,在开发人员的分支中为每个任务创建了早午餐。 接下来,创建从此早午餐到主存储库的拉取请求。 此拉取请求通过了Jenkins的一系列自动化测试:

  1. 所有平台(Windows,Linux,MacOS,iOS,Android)的单元测试。 Googletest作为基础,OpenCppCoverage(其报告由其他python脚本检查)用于检查覆盖率。 如果特定文件的覆盖率百分比小于75%,则认为测试失败。 因此,我们通过测试涵盖了大多数低级引擎类。
  2. 编码格式器 对于C ++代码,我们使用clang格式。 在开发人员的计算机上进行提交时,更改后的代码的格式首先自动发生,然后在测试中进行检查。 对于用作脚本语言的javascript,使用npm linter。
  3. 资产测试。 相当大量的测试:从验证文件格式到检查依赖关系(例如,检查游戏级别中使用的纹理是否确实存在)。
  4. 编辑器的单元和功能测试。 引擎不可或缺的一部分是编辑器,可在其中创建和编辑游戏关卡和其他资产。 除单元测试外,froglogic Squish for Qt还用于测试编辑器-一种用于自动GUI测试的实用程序。 所有这些使我们无需手动测试编辑器即可完成此工作。 此外,根据美术师和关卡设计师的评论,其质量和稳定性水平高于以前的公司,当时我们只有五个测试人员。 同时,每天都会发布一次,通过手动测试,每2周就会发布一次。
  5. 游戏功能测试。 很明显,我想对游戏使用自动功能测试。 因此,我们开始开发以下系统:

  • 测试应用程序(特别是python脚本)使用某些参数启动游戏服务器和客户端
  • 正在运行的服务器和客户端打开网络端口,
  • 测试应用程序将与它们连接并发送命令:下载地图,选择角色和武器,移至某个点,瞄准,射击等。
  • 测试语法本身是python pytest。 该系统目前正在积极开发中。

多数测试项目都是在“将警告作为错误处理”标志打开的情况下收集的,并且在MacOS平台上还打开了clang AddressSanitizer,这使您可以在准备拉取请求的阶段捕获更多错误。

除测试外,每个拉取请求还至少由其他两个开发人员审查,并在必要时发送以进行修订。 当所有测试都完成并且审阅者没有评论时,pullrequest自动冻结。
由于某些测试会花费大量时间(例如,一个完整的GUI编辑器测试持续一个多小时),因此在请求请求中使用了缩短的脚本。 每四小时在向导中启动全套测试。

迄今为止,已经以这种方式创建并执行了6,600个拉式任务。



持续交付


我们使用每日(或每天)自动发布的概念。 这是如何发生的:

  1. git标签已创建,
  2. 它运行所有测试的完整版本,
  3. 如果成功,将收集工件:

  • MacOS和Windows的编辑器。 因此,每个人每个早晨都有新版的工具。 而且,由于有自动测试功能,我们对其一定的质量和稳定性充满信心。
  • 适用于所有平台的游戏客户端和服务器。 适用于iOS的客户端已上传至TestFlight,适用于Android的客户端已上传至Google Play,其他平台则已上传至JFrog Artifactory,游戏服务器和其他服务均已上传至云。 也就是说,每天早上我们都会有一个全新的游戏版本,可以进行测试和测试。

当然,并非每个晚上发布都会成功结束。 某些测试可能会失败,或者在应用程序启动时会发生严重错误。 在这种情况下,白天发现的问题将由值班的开发人员修复,然后重新启动发布过程。
每天有几班值班:

  1. 一级服务员。 监视主存储库中测试的稳定性。
  2. 游戏中的2级服务员。 修复游戏错误。
  3. 二级编辑人员。 修复编辑错误,为用户(艺术家,关卡设计师,游戏设计师)提供建议。

同样在值班当天,您可能会感到技术上的负担:为旧功能添加缺少的测试,补充文档或进行重构,而这在通常的发布计划中不会花费时间。



在下一篇文章中,我们将仔细研究引擎本身的软件体系结构以及主要模块和子系统。

待续...

第一部分: habr.com/en/post/461623

Source: https://habr.com/ru/post/zh-CN465343/


All Articles