#version #modding #halo #combat #information #issue #evolved

ringhopper

Halo: Combat Evolved 模改库

3个版本

使用旧的Rust 2015

0.1.3 2022年11月14日
0.1.2 2022年11月13日
0.1.1 2022年10月29日
0.1.0 2022年10月29日

#8 in #halo

GPL-3.0-only

370KB
6.5K SLoC

invader

这是Invader的Rust重写。

原始的C++项目可以在https://github.com/SnowyMouse/invader找到。

Invader遵循GNU通用公共许可证版本3。有关更多信息,请参阅LICENSE.txt。

结构

所有源代码都位于src文件夹中。

  • src/invader - 命令行前端
  • src/ringhopper - Rust库,用于修改Halo: Combat Evolved。

为什么需要重写Invader?

Invader对我来说已经变得非常难以维护,而且原始版本也是在技能水平和知识储备都大不相同的时候开始的。

原始的Invader也因为不断添加新功能而有很多缺陷,因为原始实现的目标仅仅是编译多玩家Halo Custom Edition缓存文件,并没有真正的目标。

当时并没有预期它会成为一个用于从头制作资产的完整工具包,因为在Invader开始的时候,并没有完全意识到这个需求的重要性。

Invader解决的问题

当时,我们普遍认为我们已经满足了大部分需求

  • 我们在HEK的Guerilla和MEK的Mozzarilla中有标签编辑器
  • 我们在MEK的Refinery中有标签提取器
  • 我们可以使用tool.exe构建缓存文件和制作位图、声音、模型等
  • 我们有场景编辑器,使用Sapien实现了整个游戏

最初,能够稍微更好地构建缓存文件的项目更多的是一个有趣的边项目 - 一个开源应用程序,与MEK一起使用,以帮助制作一个不错的开源工具包。

然而,Halo Custom Edition和Halo CEA的编辑套件存在许多问题,这些问题只能通过一个完整的开源重新实现来解决。

  • 错误检查不完善:原始的HEKs有一些错误检查,但它们通常引用不可公开获取的源文件,而且打印的消息相当模糊。通常只是断言或最糟糕的情况是没有任何有用信息的异常错误。而且大多数情况下,它甚至不会在实际上有问题的标签数据上出错,让你这个修改者去发现游戏是否会崩溃。

    当涉及到制作游戏时,这可能没问题。Bungie可能没有预料到这个编辑工具包会被用于除了在工作室内部制作《光环》(或那次《僵尸史都布斯》)之外的任何地方。存在的错误检查已经足够制作游戏了。然而,修改者需要更多来制作自定义内容,因为整个引擎基本上是一个黑盒子,因为它是封闭源代码。

    高质量的准确错误是必要的,这正是Invader在原始C++版本中做得非常好的地方(尽管重写可能做得更好!)。

  • 信息不足:工具是封闭源代码,几乎没有任何官方文档,这意味着理解标签系统和编辑《光环》内容的其他方面可能会很困难。

    Invader完全免费,自从它的首次公开发布以来一直是免费的。通过提供一个完整的开源修改工具包的实现,我们可以更好地理解《光环》的整个引擎,因为所有的验证和实验都是通过Invader的源代码来学习这个引擎的工作方式,并进行了文档记录。拥有公共信息和更多内容使社区能够持续发展。

    多亏了Invader是免费的工具包,我们现在考虑缓存文件中存储的每一个字节——加载到游戏引擎中的最后一个位。每个隐藏的字段都是已知的,预先处理的内容都有记录。由于有了像Invader这样的免费工具,游戏修改中不再有任何“陷阱”。

  • 性能问题:使用《光环》编辑工具包构建缓存文件或打开大型标签需要非常多的时间。在具有复杂几何形状的BSP标签上打开可能需要超过20秒,即使在2016年之后的现代PC上(距离《光环》原版Xbox发布超过15年)。这可能看起来不是很长时间,但当你不断打开和关闭标签时,20秒就会累积成很多。当前的Invader在这些相同的机器上打开这些标签只需要不到一秒,甚至可以比Guerilla打开该地图的BSP更快地编译地图。

    原始工具是为Windows的32位x86编译的,尽管《光环:战神版》的当前版本原生支持现代的64位x86 Windows。

    据说,游戏的许多检查和断言进一步降低了性能。当前的Invader C++实现表明,我们可以在具有更强大错误检查和更多功能的同时,实现比原始《光环》编辑工具包更高的性能。我们甚至可以针对现代PC和Linux,Invader可以直接通过一个Arch Linux AUR软件包来支持。

当前的C++ Invader有什么问题?

如前所述,Invader有一个问题,就是为了实现当时需要的某个功能而随意添加了一些功能。

例如,Python代码是一团糟,它生成了大量的C++代码来使Invader运行更快。这导致编译时间很长,并且很难增量地工作在解析器上。

此外,还存在一个名为 hek 的模块,最初是为了定义从《光环编辑套件》逆向工程或提取出来的内容而存在的。这已经成为一个不一致、令人困惑的混乱状态,以至于即使我自己在源代码树中寻找东西也要花很长时间。

我还认为很多代码可以做得更好。大部分现有的代码可以使用,但很多代码在针对多个引擎时都写得很“ hacks”,为了“完成任务”。例如,定义缺少区分不同游戏引擎的任何标志。这些应该在项目开始时就添加进去,但又一次,我没有预料到《入侵者》会变得如此庞大。

为什么选择 Rust?

Rust 是一种很好的语言,它强调安全,同时又不牺牲速度。这对于只有极少数开发者参与如此庞大的项目来说非常棒。无意中破坏了代码中已经存在多年的东西或触发难以调试的段错误是非常令人沮丧的。

Rust 生态系统还通过 cargo 程序提供了内置的功能,用于单元测试和外部模块。这意味着代码在发布之前可以测试其破坏性。

与 Rust 相比,静态链接要容易得多,因为它是默认进行的。动态链接是一种反模式,会导致分发大量的 DLL 文件,以及寿命不长的可执行文件。动态链接仅适用于系统库,如 kernel.dll 或 Linux 内核,因为这些都是稳定且保证在目标机器上存在的 API。不期望在目标机器上存在的动态链接库会导致依赖地狱。对于 Linux,包管理器试图解决这个问题,但 API 破坏仍然会发生。对于 Windows,通过工具包分发超过 100 MB 的 DLL 会导致使用工具时的体验不佳,并且在某些情况下,DLL 可能会发生冲突或需要单独更新。

总的来说,Rust 和 Cargo 提供了完成这项工作的正确工具。我仍然认为 C++ 是一种非常棒的语言,但 Rust 本身是为了解决我在开发《入侵者》时遇到的问题而设计的。

C++ 项目将会如何发展?

目前,在 Rust 重写尚未达到与 C++ 版本相同的特性级别时,C++ 项目将继续维护。对《光环:战斗进化纪念版》的模组功能的未来版本的支持和更新将继续进行,并且将继续修复主要错误。

然而,一旦重写包含 C++ 版本的所有功能并证明是一个可行的替代品,C++ 版本将被完全放弃。此外,重写的版本号将继续从完成时的 C++ 版本号开始(例如,如果《入侵者》的版本是 0.60.3,则重写将是 0.61.0)。在此之前,Rust 重写的版本号将保持为 0.1.0 作为占位符。

依赖关系

~3–42MB
~604K SLoC