digows/cosmo

GitHub: digows/cosmo

经典 DOS 游戏《Cosmo's Cosmic Adventure》的原生源码跨平台移植版,通过自研硬件模拟层在现代系统上脱离 DOSBox 直接运行。

Stars: 1 | Forks: 0

# Cosmo's Cosmic Adventure — 适用于 macOS、Linux 和 Windows 的原生移植版 这是 **Cosmo's Cosmic Adventure: Forbidden Planet**(Apogee Software,1992年)的源码移植版,可在现代计算机上原生运行。无需 DOSBox,无需模拟器, 也无需虚拟机——直接使用游戏原始代码,为你的计算机编译而成。 [![CI](https://static.pigsec.cn/wp-content/uploads/repos/cas/39/39faa54be350a1dab8afd3b2fb8c1c83e4d9cff84abfef2374d19a18053687c4.svg)](https://github.com/digows/cosmo/actions/workflows/ci.yml) [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) ![平台: macOS, Linux, Windows](https://img.shields.io/badge/platforms-macOS%20%7C%20Linux%20%7C%20Windows-lightgrey) ![语言: C](https://img.shields.io/badge/language-C11-orange) | | | |:-:|:-:| | ![Cosmo's Cosmic Adventure title screen, Forbidden Planet](https://static.pigsec.cn/wp-content/uploads/repos/cas/ea/ea18344a4b1cc722d9464fc41227e6a1ce28368d052f566c3f13291445260e05.png) | ![The game's credits screen](https://static.pigsec.cn/wp-content/uploads/repos/cas/5f/5f19a483e7c2dbdc1cf70781f2a69d59b1664ce1911f9da9073433152d136f16.png) | | ![Cosmo running through a jungle level](https://static.pigsec.cn/wp-content/uploads/repos/cas/cc/cc297ec36379e714de0ec478ed60647ccdfef54abe14b5230878728c521f4d46.png) | ![Episode selection launcher drawn in the game's own font](https://static.pigsec.cn/wp-content/uploads/repos/cas/98/98de184da703102ded18ee2a41675e1c22497a3eacff17aa903415fd86bf4594.png) | 每张截图均由该移植版在 macOS 上使用原始 1992 年数据文件生成——并非从模拟器中截取。 ## 下载与游玩 **[获取最新发布版](https://github.com/digows/cosmo/releases/latest)** — 支持 macOS、Windows 和 Linux。每个下载包都包含免费的 Episode 1,解压后即可直接游玩; 无需安装。如果你拥有 Episode 2 和 3,启动器会提示你指定它们的位置。 ## 项目说明 项目的起点是游戏自身的代码,而非重新实现。该项目基于 [Cosmore](https://github.com/smitelli/cosmore),这是 Scott Smitelli 对 v1.20 版本源码的复原,其来源于对 1992 年可执行文件的反汇编,字节级还原度高达 96.3%,且仅替换了原来与 PC 硬件交互的底层部分。 该层之上的所有内容都是 Todd Replogle 当年编写的原始风貌:物理效果、 角色活动、碰撞处理以及原始 Bug。而从零开始编写的部分是底层的 机器环境——一个模拟的 EGA 适配器、可编程间隔定时器、键盘控制器、PC 扬声器以及一个 AdLib。 如果你想了解开发过程中踩过的坑,可以阅读 **[docs/porting-notes.md](docs/porting-notes.md)**。 ## 状态 | 子系统 | 状态 | |---|---| | 全部三个章节,内置游戏风格的启动器 | ✅ | | 带图标的应用程序包,下载即可直接运行 | ✅ | | 模拟的 EGA —— 写入模式、锁存器、位掩码、映射掩码、置位/复位 | ✅ 单元测试 | | 平面解码、调色板、SDL3 呈现 | ✅ 单元测试 | | 中断与时序控制层 —— int 8 / int 9、PIT、PIC | ✅ 140 Hz,经测量 | | 地图加载、滚动、角色活动、吸引模式演示 | ✅ | | 键盘控制,包括移动时跳跃 | ✅ 脚本验证 | | 游戏保存与读取 | ✅ | | PC 扬声器音效 | ✅ 已对照游戏原始音频数据进行验证 | | AdLib (OPL2) 音乐,基于 [ymfm](https://github.com/aaronsgiles/ymfm) | ✅ | | macOS、Linux 和 Windows 构建 | ✅ CI 状态为通过 | | 摇杆 | ⬜ 未实现 | | 与 DOSBox 进行逐帧对比 | ⬜ 最大的遗留差距 | 游戏可完整运行到底:`cosmo` 会在其独立的线程上启动原始的 `InnerMain()`,主线程扮演 PC 硬件的角色。它将以原版设定的 10.8 帧/秒的节奏,播放标题画面、职员表以及可玩的吸引模式演示。 ## 构建 要求安装 CMake 3.21+、支持 C11 和 C++17 的编译器以及 SDL3。如果未安装 SDL3,CMake 会自动下载并构建它。项目中唯一的 C++ 代码是用于 包装 ymfm 的封装器,用于合成 AdLib 的 YM3812 音效。 ``` git clone --recurse-submodules https://github.com/digows/cosmo.git cd cosmo cmake --preset default cmake --build --preset default ctest --preset default ``` **macOS** —— 使用 `brew install cmake sdl3`。这也是该移植版进行开发和测试的平台。 **Linux** —— 使用你系统发行版自带的 SDL3,或让 CMake 自动获取。 构建依赖项已在 [CI workflow](.github/workflows/ci.yml) 中列出。 **Windows** —— 使用 MinGW,可以通过 MSYS2 原生运行,或使用 [toolchain file](cmake/toolchain-mingw64.cmake) 进行交叉编译。目前尚未对 MSVC 进行过测试。 构建通用的 macOS 二进制文件时,由于 Homebrew 提供的软件包是单架构的,因此需要从源码为两种架构分别构建 SDL: ``` cmake --preset macos-universal && cmake --build --preset macos-universal ``` `-DCOSMO_BUNDLE=ON` 构建的是发布版所提供的内容,而非终端 程序:在 macOS 上会生成带图标的 `Cosmo.app`,在 Windows 上则会带有图标、隐藏控制台 窗口,并将 MinGW 运行时直接链接进去,而不是依赖于必须随程序一起携带的三个 DLL 文件。 ### 无需消耗 CI 资源即可检查其他平台 提供了两套容器方案,可在任何装有 Docker 的机器上复现 Linux 和 Windows 的构建任务,这比从失败的流水线中发现问题更快捷,成本也更低: ``` docker build -f tools/checks/linux.Dockerfile . docker build -f tools/checks/windows-mingw.Dockerfile . ``` 第一个方案使用了与 CI 任务相同的发行版和包列表。第二个方案 使用 MinGW-w64 进行交叉编译,这也是 Windows 任务使用的编译器系列。 这两套方案都曾在代码推送到 CI 运行器之前发现过真实的缺陷。 ## 游戏数据 游戏素材版权归 Apogee Software 所有,**不**包含在此仓库中。 发布的下载包中包含了 Apogee 免费分发的 Episode 1;如果你从源码构建,则需要手动将其放置到位。 程序会按以下顺序查找 `COSMO1.STN` 和 `COSMO1.VOL`:程序所在目录、macOS 应用程序包内部,以及游戏启动时的目录。 程序会使用最先找到的文件,如果该位置支持写入,存档文件也会保存在那里——因此解压后的文件夹可以自带数据。获取数据的途径及校验和请参见 [gamedata/README.md](gamedata/README.md)。 如果已存在 `COSMOn.CFG` 文件,它的优先级将高于本移植版的默认设置, 包括跳跃键——原版发行时自带了 ctrl 键设置。 删除该文件即可恢复默认设置,或在游戏中重新绑定按键。 ## 运行 ``` ./build/default/cosmo ``` 放置一分钟不动,游戏会自动播放吸引模式演示。 `cosmo` 是一个启动器:它会列出各章节, 标记出缺失数据的章节,并提供文件选择器来补充数据——而且列表使用游戏自带的字体绘制在游戏原始的标题背景上,通过同一套模拟的 EGA 显示。你可以直接指定章节名称以跳过菜单: ``` ./build/default/cosmo 2 ``` 三个章节是独立的程序——`cosmo1`、`cosmo2`、`cosmo3`——这 并不是出于打包的考虑。它们通过预处理器条件指令包含或排除完整的角色实现,因此编译出的代码确实有所不同。出于同样的原因,Apogee 当年也发行了三个独立的可执行文件。 `imgview` 是一个独立用于测试视频层的工具,可方便地在未启动游戏的情况下检查全屏图像: ``` ./build/default/imgview # browse them ./build/default/imgview gamedata TITLE1.MNI shot.png 2 # headless screenshot ``` ## 操作说明 方向键移动,**Space** 跳跃,**Alt** 投掷炸弹。 原版游戏默认使用 ctrl 键跳跃,这在 1992 年很常见;而时至今日,空格键长期以来一直是平台跳跃类游戏的惯例,同时也是不会引起窗口管理器冲突的按键绑定。这是该移植版对游戏行为做出的唯一刻意更改——参见 [patches/0007](patches/)。炸弹按键未作更改。 这六个按键均可在游戏自带的主菜单中进行重新绑定:在主菜单选择 **G** 进入 Game Redefine,然后按 **K** 进行 Keyboard redefine。该选择将与音效设置和最高分一起写入 `COSMOn.CFG` 文件中,从而在多次运行间得以保留——但这仅在游戏正常退出时有效。请通过游戏菜单退出(按 **Q**,然后按 **Y**),而不要直接关闭窗口,这与 DOS 系统上的情况完全一致,在 DOS 中强制结束程序同样会导致该文件丢失。 在 macOS 上,Command 键会被识别为 Control。如果你将跳跃键重新绑定回 ctrl,这一点就很重要:macOS 默认会将 Control 与任意方向键组合用于触发 Mission Control,因此 ctrl 加方向键的输入根本不会传达给应用程序。Command 键未被系统占用,因此可以用来填补这一空缺。 ## 工作原理 主线程扮演 PC 硬件的角色,而第二个线程扮演 CPU 的角色。Cosmo 的主循环从不主动让出控制权:它不断忙等一个由自身定时器中断递增的计数器,并读取由自身键盘中断填充的键盘状态。在真实硬件上,这些中断处理程序会在程序运行时于后台触发,因此在这里,主线程会按照游戏写入 PIT 的频率(140 Hz,开启音乐时为 560 Hz)触发这些中断,同时游戏在另一侧正常运行。 原版游戏通过 I/O 端口对 EGA 进行编程,并将数据写入段地址 0xA000 的视频内存中。该移植版并未重写绘图代码,而是模拟了 适配器:在普通内存中划出四个 64 KiB 的平面,并实现了游戏所依赖的写入模式、锁存器、 位掩码和置位/复位逻辑。 这种精确度非常重要。`DrawSolidTile` 在写入模式 1 下使用 `*dst = *src` 将场景从视频内存复制到 视频内存,此时 CPU 数据会被丢弃,真正送达屏幕的是由读取操作加载到锁存器中的内容。如果 EGA 模拟看起来正常,却跳过了锁存器操作,渲染出的将会是乱码。 本项目中完全避免了汇编代码。上游项目在 `C-DRAWING.md` 中发布了所有绘图例程的纯 C 实现,编写这些代码最初是出于好奇,因为它们在 286 处理器上运行得太慢了。但在现代 CPU 上,这种性能损耗可以忽略不计,并且使用纯 C 代码消除了对 Turbo Assembler 的依赖,毕竟 Borland 从未将其免费公开。 ## 调试与自动化检查 `COSMO_SCRIPT` 指向一个包含定时按键事件的文件,从而可以在无人操作键盘的情况下驱动游戏。每行格式为 `<毫秒> <按键>`;具体示例请参见 [tests/scripts](tests/scripts/)。 | 变量 | 效果 | |---|---| | `COSMO_DEBUG=1` | 每秒输出一次定时器频率、中断发送情况,以及游戏自身的按键和命令状态 | | `COSMO_SHOT_PATH=p COSMO_SHOT_MS=500,3000` | 在启动后的特定时间点自动截图。随时可按 `F12` 截图 | | `COSMO_AUDIO_WAV=out.wav` | 录制音频硬件产生的所有声音。即使游戏被强制终止而非正常退出,文件头也能保持有效 | | `COSMO_OPL_LOG=1` | 跟踪所有对 AdLib 寄存器的写入操作 | | `COSMO_SCRIPT=file` | 回放定时的按键事件 | 正是借助这些工具,我们得以将音效与游戏自身的原始数据进行比对验证,并据此追踪到键盘输入 Bug 的根源在于窗口系统,而非模拟器本身。 ## 目录结构 ``` vendor/cosmore/ upstream submodule, pinned and never modified vendor/ymfm/ YM3812 synthesiser, pinned and never modified cmake/ source preparation, run at configure time patches/ changes to upstream, one numbered patch each include/cosmo/ platform layer headers src/platform/ emulated EGA, video, audio, DOS runtime, hardware src/launcher.c episode picker, drawn in the game's own font tools/ validation harnesses and container checks tests/ unit tests and input scripts docs/ porting notes and screenshots ``` 源码准备阶段对上游代码应用了三种机械转换:删除了在现代环境下没有等效替代的 Borland 头文件的 `#include` 行,注释掉了 16 位内联汇编代码,并将基础类型固定为其原始位宽——因为在 DOS 中 `unsigned int` 是 16 位的,而且游戏逻辑依赖于其溢出回绕特性。任何无法通过这些转换表达的内容,都以编号补丁的形式存放在 [`patches/`](patches/) 目录下,每个补丁都解释了对应的缺陷以及修改正确的理由。 所有这些操作均在 CMake 中而非 Shell 脚本中执行,因此在不同平台上的行为完全一致,并且每个补丁在应用前后都会进行指纹校验:如果某个补丁报告成功,但实际上没有做出任何更改,那么它将导致 configure 步骤失败,而不是静默地什么都不做。这并非假设性的场景——这种情况真实发生过,并在 [the notes](docs/porting-notes.md) 中有相关描述。 ## 许可证与致谢 本仓库中的代码遵循 MIT 许可证,详见 [LICENSE](LICENSE)。 *Cosmo's Cosmic Adventure* 及其素材和商标版权归 © 1992 Apogee Software, Ltd. 所有,本仓库不对其进行再分发。more 遵循 MIT 许可证,© Scott Smitelli 及贡献者所有;ymfm 遵循 BSD 3-Clause 许可证,© Aaron Giles 所有。完整的致谢名单(包括游戏的原始作者)请参见 [ATTRIBUTION.md](ATTRIBUTION.md)。
标签:Bash脚本, Gophish, 复古游戏, 客户端加密, 开源游戏, 游戏源码移植, 请求拦截