先认清这份红警源码:版本、目录与构建边界
这套文档研究的是 EA 发布的 《Command & Conquer: Red Alert》第一代源码。研究基线固定为提交 0dc09bb1d6188d1ec79ab4765b22a48b75ffee32,提交日期为 2025-02-27。这里的 2025 是公开仓库提交时间,不能当成游戏代码的创作时间。它也不是《红色警戒 2》、OpenRA 的重新实现,或 Remastered Collection 的现代宿主工程。以下解释以这份实际文件树及其编译条件为边界。
最先需要建立的认识是:源代码可读,不等于仓库可直接编译,更不等于已经包含一套可运行游戏。 官方 README 明确说明目前不能完整编译,恢复需要工作;重建说明限于 Win32,列出的历史工具是 Watcom C/C++ 10.6 与 TASM 4.0。本文进行了源码和构建清单审计,没有声称已编译、启动或通关游戏。依据:README 的构建说明
如果自行取得同一阅读基线,可以使用下面的 Git 命令;它们用于下载与固定版本,不是编译命令。后续做实验时宜从这个基线另开分支,保持原始代码可随时对照。所有源码链接也固定到此提交,避免未来分支位置变化导致正文与行号不一致。
git clone https://github.com/electronicarts/CnC_Red_Alert.git
git -C CnC_Red_Alert checkout --detach 0dc09bb1d6188d1ec79ab4765b22a48b75ffee321.1 这不是 1996 年原版代码的单一时间切片
读老项目时,文件头的初始日期、注释里的版本名称、当前启用的代码可能来自不同年代。例如 DEFINES.H 保留 1993 年初始日期和 CounterStrike 路径,但当前启用了 FIXIT_ANTS、FIXIT_CSII、FIXIT_CARRIER、FIXIT_PHASETRANSPORT 等修改。更有价值的是 1998-09-28 的说明:Aftermath 的修改同时包含修复与游戏规则变化,后来为 DVD 与 WOLAPI 的更新,决定把 RA、Counterstrike、Aftermath 及 DVD 版本统一到同一个可执行程序,让部分扩展包差异转为运行期判断。依据:扩展包合并说明与开关
当前还定义了 FIXIT_VERSION_3 和 DVD,后者进一步打开 MPEGMOVIE;Win32 编译清单打开 WOLAPI_INTEGRATION 与 WINSOCK_IPX。因此阅读单位、视频和网络逻辑时,应把它理解为含后期补丁、扩展包统一与 Windows 在线服务接入的第一代红警代码。版本及 DVD 开关;Win32 编译宏
版本常量也不能只取一个名字就下结论。RAWOLAPI.H 定义 GAME_VERSION = 0x00030003,而 VERSION.CPP 特意说明旧 Version_Number() 已不再使用,旧版本界限存在过时值,现用 GAME_VERSION。这为“后期 3.03 相关代码”提供证据,但仅凭常量不能证明这份树能一字节不差地生成某张发行光盘上的 EXE。当前在线版本常量;旧版本函数的弃用说明
另一个阅读陷阱是“文件存在”与“功能启用”不同。当前定义的是 RELEASE_VERSION;场景编辑器要求 INTERNAL_VERSION,完整作弊键要求内部版或测试版。源码保留编辑器实现,不代表默认发行配置会向玩家开放。发行配置;编辑器和作弊键条件
1.2 整个仓库是游戏、底层库和生产工具的集合
以下数量为固定提交本地文件树统计,包含头文件、汇编、构建文件、备份和少量二进制;不能相加后宣称“有这么多独立源码模块”。根目录 README 与 LICENSE 不计入表内。
| 目录 | 文件数 | 在制作流程中的角色 | 阅读时的边界 |
|---|---|---|---|
CODE |
589 | 游戏规则、对象、地图、界面、AI、事件、网络与通用技术模块 | 第一阅读入口;277 个 .cpp、242 个 .h,并非只有玩法代码 |
WWFLAT32 |
400 | DOS 时代 32 位底层库 | 包含内存、定时器、VGA/VESA、文件、音频等历史实现 |
WIN32LIB |
568 | Windows 底层库 | DirectDraw、DirectSound、输入、计时及软件绘图;有历史副本 |
VQ |
183 | DOS 路径下的 VQA 播放与配套工具库 | 不能直接等同于视频制作源素材 |
WINVQ |
216 | Windows 路径下的 VQA 播放与配套工具库 | 包含播放器、查看器、历史版本与少量库文件 |
IPX |
52 | 早期 Windows 32/16 位 IPX 桥接 | 同时有 OK、OLD 和备份,不等于全部进入当前构建 |
LAUNCH |
2 | DOS 启动外壳 | 16 位汇编准备运行环境后启动 GAME.DAT |
LAUNCHER |
47 | Windows 启动及补丁应用外壳 | 独立 .dsp/.dsw 工程,不是游戏主循环 |
TOOLS |
25 | 资源转换、压缩、打包工具 | 只有部分工具提供源码,其余主要是历史 EXE |
构建清单验证了这几层的关系:主游戏按平台选择 win32lib.lib 或 wwflat32.lib,另有 vqa32wp.lib 与 vqm32wp.lib;主目录内部还把通用算法归入 tech.lib,把依赖图形库的 ROTBMP、SPRITE 归入 jshell.lib。目录位置和逻辑职责并不完全重合。主程序的库分组
1.3 从一个 CPP 到游戏 EXE:构建过程究竟做什么
可以把构建分为编译、归档和链接三步:编译把每个实现文件转为目标文件,归档把一组目标文件装进静态库,链接再选择需要的符号并组织成可执行文件。红警的 CODE/MAKEFILE 使用 Watcom wmake 语法,包括 !ifdef、.AUTODEPEND、%create 等;不是拿现代 GNU make 原样执行就能完成的通用脚本。
以 Win32 英文版为例,根据清单推演一条真实依赖路径:
- 未指定德语或法语时,
LANGUAGE=ENGLISH。定义WIN32后,库根变为..\win32lib,目标文件放到obj\win32\ENGLISH,链接响应文件选为win95.lnk。 - 例如
UNIT.CPP由..\watcom\binnt\wpp386编译到相应.obj。所有源文件共享平台宏、语言宏和头文件搜索路径。 LCW、MIXFILE、RAWFILE、加密与校验等对象归入tech.lib;SPRITE与ROTBMP归入jshell.lib。wmake根据主清单生成win95.lnk,把目标文件、内部库、图形音频库和系统导入库逐条写入。linker\nwlink根据响应文件输出..\run\ra95.exe。
以上是静态依赖推演,不是已执行成功的命令日志。平台路径与语言选择;编译与汇编规则;内部静态库生成;最终链接及响应文件生成
查看流程图源文本
flowchart TD
A[游戏 CPP 与 ASM] --> B[平台及语言对应 OBJ]
C[通用技术模块] --> D["tech.lib 与 jshell.lib"]
E[平台库及 VQA 库] --> F[生成链接响应文件]
B --> F
D --> F
F --> G["ra95.exe 或 DOS game.dat"]这里有一个容易误报的“缺文件”:仓库中没有现成 WIN95.LNK、CONQUER.LNK,但主 Makefile 明确会生成它们,所以不能仅凭缺失就判为构建损坏。相反,IPX 的独立脚本引用 thipx32.lnk、thipx16.lnk,在当前树中既未找到文件,也未见这些脚本生成它们,这才是需要补齐的另一类输入。主响应文件规则;IPX 的依赖
DOS 分支默认目标叫 game.dat,但它是程序,不是资源数据库。其规则先链接 dos.exe,再经过 wstrip 与 DOS/4GW Professional 绑定得到 game.dat。LAUNCH.ASM 的 GameName 则直接写着 GAME.DAT。DOS 绑定过程;启动目标字符串
平台条件还会更换实现文件:Win32 编译 2KEYFBUF、2KEYFRAM,DOS 编译 KEYFBUFF、KEYFRAME。研究形状帧缓存时若读错分支,会把不同实现混为一谈。平台对象清单
1.4 编译选项也是游戏格式的一部分
主清单为 Windows 使用 /5r,DOS 使用 /5s,对应不同调用约定;公用选项包含 /zp1 一字节结构体对齐、/j 有符号 char、/ri 对小整型返回值的约定,以及严格警告设置。这些选项会影响 C++ 与汇编互调、对象布局和二进制读写。移植时单纯让编译器“不报错”,无法证明游戏状态或资源格式仍然正确。完整核心编译参数
一个具体例子是 FUNCTION.H:当年的编译器没有原生 bool,代码自行声明 false/true 并 typedef int bool。把它替换成现代一字节 bool,有可能改变包含布尔字段的对象大小。这个问题是否影响某条存档路径,要结合该对象的序列化方式检查;不能笼统认定“改成现代写法总是安全”。历史布尔类型兼容层
因此,在源码分析中,“字段类型”“对象内存”“文件格式”“网络格式”要分别看待。现代工程可以用明确位宽的格式结构、字段级序列化和适配层减少耦合;但那属于移植设计,不是原项目已经具有的保证。
1.5 目前缺少什么,哪些只是生成产物
官方首先列出四组需自行寻找、替换或移除使用代码的依赖:DirectX 5 SDK、DirectX Media 5.1 SDK、Greenleaf Communications Library、HMI SOS。这里不是“所有第三方痕迹都不存在”:树中确实能找到部分 SOS 头文件及 .lib,但不能据此认定版本、ABI、完整性和授权分发条件全部满足。官方依赖表
| 审计项目 | 固定提交中的观察 | 对重建的含义 |
|---|---|---|
watcom、dxsdk、dxmedia、gcl510 |
未包含对应完整目录 | 主清单硬编码了相邻路径,需要外部环境或替代实现 |
CODE/linker/nwlink、CODE/utils/tasm |
未找到指定工具 | 原命令路径不能直接使用 |
CODE/mpgdll.lib、uuid.lib |
未找到链接清单指定文件 | 需审计视频导入符号和系统导入库的来源 |
CODE/ipx/wwipx32.lib |
主清单引用此处;IPX 源码实际在顶层 | 必须明确子项目输出与拷贝步骤,而不是只补搜索路径 |
WIN32LIB/LIB、目标 OBJ、tech.lib |
无完整预构建产物 | 很多是待生成结果,缺失本身不是缺源码的证明 |
WINVQ 所需两个播放器库 |
有源代码与 Makefile,未发现目标 vqa32wp.lib/vqm32wp.lib |
需要单独构建并校核调用约定 |
RULES.INI、.MIX/.SHP/.AUD/.VQA 游戏资源 |
本树未发现这些扩展名的成套游戏资源 | 编译后仍需要合法获得且匹配版本的游戏数据 |
链接清单可逐项验证 DirectDraw、DirectSound、DirectX Media 与 MPEG 库依赖,资源初始化则实际尝试打开 REDALERT.MIX、LOCAL.MIX 等文件。这里的“未发现”只描述本次固定提交,不推断所有历史发行包或其他仓库。Win32 导入库清单;游戏资源包入口
资源制作也另有流水线。RULES.MAK 设置光盘、音频、电影、美术和临时 MIX 路径,大量指向当年的盘符与共享目录;它不是运行时 RULES.INI。代码构建、资源转换和光盘打包曾经属于同一工作室的生产系统,而公开仓库只保存了其中一部分。资源制作环境;资源类型路径
1.6 从工作室的生产方式理解这些构建文件
这个工程还有一个很有教学价值的特点:构建文件不仅描述程序,还携带当时工作室的工作方式。JOEMAKE.BAT 会配置本地与共享盘路径、复制头文件和源文件到网络目录,启动 netexec 并运行 wmake,最后取回目标文件。它的注释明确称其为借助网络从机的编译脚本。这说明开发者已在处理编译耗时和多人协作问题,但采用的是当时环境中的盘符映射、共享目录和外部工具;我们没有这些共享盘,也不能只凭脚本推断当年的分布式编译性能。网络构建准备;启动与取回产物
主 Makefile 还把源码、美术、音频、运行文件复制到网络及光盘目录,调用打包工具并生成带日期的测试版本目录。今天常把编译、资源制作、发布分成不同任务,这里则直接写进一个大型 Makefile。它能帮助读者理解:制作游戏不仅是编写单位 AI,还包括把正确资源与正确语言、补丁、程序组合到同一发行介质上。资源及源码同步;光盘与测试版本准备
语言构建也能展示“中间产物隔离”和“最终产物隔离”的区别。MAKE_ALL.BAT 依次重建英文、德文、法文;主清单把各自 OBJ 放进语言子目录,但链接命令仍输出相同的 ..\run\ra95.exe。所以从当前脚本可推断,若这些命令依次成功且没有外部复制步骤,后一次会覆盖前一次 EXE。恢复工程应为各语言保留独立最终目录,不能以“有三个 OBJ 目录”证明“三套发行产物已妥善保存”。三语言脚本;公共 EXE 输出路径
底层库同样是多阶段产物。WIN32LIB/MAKEFILE 逐个进入子目录执行 wmake,子目录先生成自己的 .lib,再由总目录的 libs.lbc 将各库组成 win32lib.lib。因此游戏链接失败时,应沿依赖向下定位:是某个 CPP 尚未编译、子库未生成、总库未合并,还是最终缺了系统导入符号。直接把所有报错归因于“旧代码不兼容新系统”,反而丢失了可行动的信息。子库递归构建与总库归档
1.7 正确的研究顺序与恢复目标
如果目的是理解游戏,先沿主程序、对象模型和事件链阅读,暂时不必恢复每一套历史工具。如果目的是运行修改版,先选一个明确目标,例如“Win32 英文、单机、固定资源版本”,再建立依赖清单与实验门槛。不要同时尝试 DOS、DVD、三种语言、拨号、WOL 和全部工具:它们的构建环境并不统一,连 AUDIOMAK 都使用 Borland bcc/tlink 与大内存模型。音频工具的独立工具链
仓库 README 将本次发布定位为保存用途并支持游戏 Workshop 相关工作,说明仓库不接受贡献、没有支持。它指向 GPL v3 及附加条款,并要求使用编译产物时拥有游戏。附加条款明确涉及商标、来源标识和随附声明等事项;这不意味着游戏美术、配乐与商标随源码自动成为可任意重发的素材。分发前应直接阅读完整 LICENSE,本文只记录仓库自己的说明。发布及支持定位;附加条款
源码阅读路线
README.md → CODE/MAKEFILE 的平台分支和目标 → DEFINES.H 的版本开关 → RAWOLAPI.H 的版本常量 → WIN32LIB/MAKEFILE 与 WINVQ 子项目 → RULES.MAK。完成这一圈后,再读后续游戏架构章节,能持续判断“这段逻辑属于哪个构建、依赖哪一层”。底层实现与恢复实验详见 第 15 章。
尚未确认的边界
本次没有恢复 Watcom/TASM 历史环境,没有链接或运行游戏,没有逐个验证随附 EXE 的功能,没有证明公开树与某个商业发行二进制完全一致。当前编译宏可从清单确认;某个历史发行版本究竟启用了哪些宏、带了哪些资源,仍需相应发行产物作对照。