fredangstadt-lang/LineWarsII-SDL
GitHub: fredangstadt-lang/LineWarsII-SDL
基于模拟器验证的C重构代码,将1994年DOS游戏LineWars II移植到SDL3平台,实现像素级精确还原并支持高分辨率渲染。
Stars: 4 | Forks: 0
# LineWars II,便携版
1994 年 DOS 游戏 LineWars II 的可游玩重构版本,使用可移植的 C 语言编写,目标平台为 SDL3。
这里的引擎并非简单的视觉复刻。每一个函数都是从原版游戏的机器码中重构出来的,并经过了逐一验证:共有 35 个自动化测试关卡,其中 23 个会在模拟器中运行 1994 年的原版二进制文件,并将其返回值、VGA 端口写入和像素与我们编译的 C 代码产生的结果进行 diff(差异比对)。这些测试关卡可以在任何主机上运行,它们随源码一起提供,也是本移植版必须遵守的契约。


## 关于本移植版
这是 [LineWars II 重构项目](https://github.com/fredangstadt-lang/LineWarsII-DOS) 的原生 SDL3 移植版。
该代码库包含了完整的来源、验证过程以及制作背景故事。
LineWars II © 1994 Patrick Aalto;该重构版本已获得他的授权作为免费软件发布,任何商业用途都需要与他进行许可协商。
游戏核心与 DOS 版本一样,都是经过验证的 C 代码。重构版本中所有涉及硬件的操作都汇聚于一小部分封闭的底层函数中,因此本次移植实际上只是在已经存在的接缝(接口边界)背后替换了新的后端。这就是为什么它能在半天之内从无到有变得可玩。DOS 版本中独立于平台的测试关卡套件同样会在主机上针对本版本运行。
相比 DOS 版本新增了:高分辨率渲染、可调整窗口大小、全屏模式。支持在 Linux 和 Windows 上构建(Windows 二进制文件在 Linux 下交叉编译,并通过 Proton 测试)。
有两个值得记录的移植 Bug。原版游戏依赖于 32 位整数的溢出回绕,而在 LP64 的 Linux 系统上,未回绕的值引发了光照 Bug:太阳的位置是由溢出值推导而来的。另一个是文件名大小写敏感问题。这两个问题都已修复并经过了游戏测试。
## 项目来源
重构工作是在一个单独的代码库中完成的,,该代码库保持原样。
它包含了反汇编代码、每条注释中的字节偏移标注、审计追踪记录以及 DOS 版本的构建。**当本移植版出现异常行为时,你需要回到那个代码库去查明原版到底是怎么做的。**
本代码库包含了经过整理的纯净版本:相同的已验证逻辑,但剥离了“考古”痕迹,其编写初衷是让从未接触过 16 位反汇编器的人也能轻松阅读源码。
## 目录结构
```
src/ the engine, portable C
include/ its headers
platform/sdl3/ the SDL3 backend
platform/dos_reference/hal_dos.c
the DOS backend, kept as the SPEC: every seam it answers,
the SDL backend has to answer too
tests/gates/ the verification gates (verify_*.py + their C runners)
tests/oracle/ the emulator harness that executes the original's bytes
tests/unit/ host unit tests
tools/ asset extractor, asset packer, test runner
docs/ port notes, architecture, coverage, asset format
reference/original/ original game material (Patrick Aalto's work, see below)
assets/game.dat the asset container (Patrick Aalto's work, see below)
```
## 本移植版是后端替换,而非重写
引擎中每一个涉及硬件的操作都汇聚于一小部分封闭的底层函数。DOS 后端通过 INT 10h、INT 21h、VGA 端口写入以及 Sound Blaster 的 DMA 循环来响应这些操作。而 SDL3 后端则使用纹理、音频流和键盘扫描码队列来响应相同的调用。接缝(接口边界)之上的所有逻辑都没有改变。
这些接缝在 `docs/SDL3_PORT_NOTES.md` 中被一一列出,并附带了对应响应这些操作的 SDL3 调用。
## 本代码库的编码规则
DOS 代码库就像是一个考古遗址,读起来也像。但本代码库不是。
1. **注释中不要包含字节偏移考古信息。** `/* @0x1d8f 扫描线循环 */` 这种内容应该放在另一个代码库中。这里的注释只需说明代码的作用和原因,而不是它的出处。
2. **禁止使用魔术数字。** 每个常量都必须有一个能说明其含义的命名。使用 `LW2_TRIG_SHIFT` 而不是 `14`;使用 `LW2_VGA_BYTES_PER_ROW` 而不是 `80`。
3. **统一使用 KNF 风格**(即 OpenBSD 规范)。
4. **保持测试关卡全绿。** 任何改变测试关卡输出结果的“清理”都不是清理,而是 Bug。在修改前后,请务必运行 `tools/run_unit_tests.sh`。
## 原版游戏素材
原版游戏的文件随本代码树一起分发,已获得游戏作者 Patrick Aalto 的书面许可,作为免费软件重新发布(`NOTICE.md` 中包含具体条款):
- `reference/original/` - 原版可执行文件的代码。测试关卡需要它,因为它们会运行真正的原版程序,并将我们的 C 代码与其进行 diff 比对。
- `assets/game.dat` - 美术、音乐和任务文本,已重新打包到我们自己的容器中。
这两者都可以从一份游戏副本重新构建,而不是盲目相信现有文件:`tools/extract_assets.py` 会解包原版素材,而 `tools/pack_gamedat.py` 会根据找到的内容构建 `game.dat`。请保持这些工具可用。它们不仅是其他人重现该容器格式的途径,也是你在格式发生变化时重新生成该文件的唯一方法。
## 状态
DOS 版本已完整且可玩:包含全部十个任务、字节级精确的生成表、音效、驾驶舱、雷达和爆炸效果。在 DOSBox-X 中运行任务时的帧率约为 47 fps,而原版为 60 fps。
SDL3 版本已经可以全程流畅游玩。`linewars2.exe` 支持运行启动画面、菜单、过场动画、飞行、任务汇报、命令界面以及游戏内设置界面,并通过 `SDL_AudioStream` 播放 Sound Blaster Pro 音乐和音效,支持键盘和鼠标控制。它支持在 Windows(WinLibs gcc 16.1.0 UCRT,或从 Linux 交叉编译的 mingw-w64)和原生 Linux 上构建;INDEX8 纹理路径和音频流均能在软件/OpenGL/Vulkan 驱动下正常工作。
**已针对原版进行验证,而非依赖截图比对:**
- 渲染器:`tests/gates/test_gfx_runner_sdl.c` 将正式发布的 SDL 后端链接到 oracle 测试框架中,并将其与在 Unicorn 中执行的原版 VGADRV 机器码进行比对:431 个测试用例,0 个不匹配。`tools/run_unit_tests.sh` 会在每次调用时运行该测试。
- 菜单:与 DOS 版本的 `SHOT01.RAW` 单元格转储数据进行字节级精确比对。
- 过场动画、飞行过程和演示:与 DOS 参考捕捉画面相匹配(`docs/captures/`)。
- 音频:混音器代码与 DOS 版本共享源码;捕获的 PCM 音频电平与 DOS 参考版本相比,误差在 ~10% 以内。
玩家可以更改的所有设置都位于一个 DOS 风格的选项卡式设置界面中(图形、控制、声音、退出),可通过菜单的“Configure”行进入,并保存在 .exe 旁边的 `settings.dat` 文件中:输出分辨率(从 640x480 到 1920x1440,以及全屏模式)、音乐与音效音量、8x16 字体,以及每一个飞行控制按键都支持重新绑定或清除。分辨率设置会实际调整窗口大小;当超过 640x480 时,3D 场景会以 2 倍内部细节进行渲染;在 2 倍模式下,字体、驾驶舱贴图、仪表盘条和雷达光标都会进行像素加倍,以保持其原有大小。640x480 模式保持字节级精确,且所有测试关卡全绿。
`docs/PORTING_CHECKLIST.md` 是开发计划与状态看板;`docs/ROADMAP.md` 列出了后续计划开发的功能(全向导弹、局域网联机、自定义任务启动器);`docs/captures/` 存放了每个界面的截图。`docs/SDL3_PORT_NOTES.md` 记录了底层的研究过程,并通过修订框标出了其中的错误之处。
## 编译说明
SDL 3.4.12,使用与游戏相同的编译器从源码编译(WinLibs gcc 16.1.0,`x86_64-w64-mingw32`,UCRT)。官方的 SDL mingw 开发包是基于 MSVCRT 构建的,混合使用不同的 CRT 简直是自找麻烦。
```
git clone --depth 1 --branch release-3.4.12 https://github.com/libsdl-org/SDL.git
cmake -S SDL -B SDL/build -G Ninja -DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=/path/to/SDL3 -DSDL_SHARED=ON -DSDL_STATIC=OFF \
-DSDL_TESTS=OFF -DSDL_EXAMPLES=OFF
cmake --build SDL/build --parallel && cmake --install SDL/build
```
然后编译游戏(请将 `CMAKE_PREFIX_PATH` 指向上面安装 SDL3 的位置):
```
cmake -S . -B build -G Ninja -DCMAKE_PREFIX_PATH=/path/to/SDL3
cmake --build build
```
## 移植背后的决策
**我们自行渲染 3D 画面。** 不依赖 GPU,不进行模型转换,也不使用现代引擎。SDL 只提供一个窗口、一张纹理、一个音频流和一个事件队列。游戏每帧只需绘制几百个无纹理的平坦三角形;对于本世纪生产的任何计算机而言,软件渲染处理这些只需不到一毫秒,而且定点数运算正是核心中最值得保留的精髓。
**单一 Chunky 帧缓冲。** 平面 VGA 地址与 Chunky 像素索引的数值是相同的(`pixel = 4*off + plane`,推导过程见 `docs/ARCHITECTURE.md`),因此本移植版完整保留了每一个经过验证的光栅化器代码,依然实现了字节级的一致,同时成功获得了平铺缓冲区,免去了平面数组和逐帧转换的开销。
**首先实现 320x480 分辨率下的像素级精确。** 只有在冻结场景的 diff 结果完全干净之后,才会进行更高分辨率的适配。320x480 构建版本是验证高分辨率版本正确性的基准。
## 许可证
重构后的源代码版权归 2026 Fred Angstadt 所有,基于 PolyForm Noncommercial License 1.0.0(`LICENSE.md`)授权:允许出于任何非商业目的使用、修改和分享。原版游戏及其素材(`reference/original/`,`assets/game.dat`,`dist/game.dat`)版权归 1994 Safari Software 和 Patrick Aalto 所有,并已获得 Patrick Aalto 于 2026 年 7 月 16 日出具的书面授权,作为免费软件重新发布。任何形式的商业用途都必须事先获得他的同意。
`dist/SDL3.dll` 是基于 zlib 许可证的 SDL 3.4.12。详见 `NOTICE.md`。
标签:Bash脚本, SDL3, 云资产清单, 像素级还原, 客户端加密, 游戏引擎, 经典游戏, 逆向工具, 逆向工程