查看源码下载文档
CHAPTER / 01

先认清这份红警源码:版本、目录与构建边界

这套文档研究的是 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 命令;它们用于下载与固定版本,不是编译命令。后续做实验时宜从这个基线另开分支,保持原始代码可随时对照。所有源码链接也固定到此提交,避免未来分支位置变化导致正文与行号不一致。

bash
git clone https://github.com/electronicarts/CnC_Red_Alert.git
git -C CnC_Red_Alert checkout --detach 0dc09bb1d6188d1ec79ab4765b22a48b75ffee32

1.1 这不是 1996 年原版代码的单一时间切片

读老项目时,文件头的初始日期、注释里的版本名称、当前启用的代码可能来自不同年代。例如 DEFINES.H 保留 1993 年初始日期和 CounterStrike 路径,但当前启用了 FIXIT_ANTSFIXIT_CSIIFIXIT_CARRIERFIXIT_PHASETRANSPORT 等修改。更有价值的是 1998-09-28 的说明:Aftermath 的修改同时包含修复与游戏规则变化,后来为 DVD 与 WOLAPI 的更新,决定把 RA、Counterstrike、Aftermath 及 DVD 版本统一到同一个可执行程序,让部分扩展包差异转为运行期判断。依据:扩展包合并说明与开关

当前还定义了 FIXIT_VERSION_3DVD,后者进一步打开 MPEGMOVIE;Win32 编译清单打开 WOLAPI_INTEGRATIONWINSOCK_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 桥接 同时有 OKOLD 和备份,不等于全部进入当前构建
LAUNCH 2 DOS 启动外壳 16 位汇编准备运行环境后启动 GAME.DAT
LAUNCHER 47 Windows 启动及补丁应用外壳 独立 .dsp/.dsw 工程,不是游戏主循环
TOOLS 25 资源转换、压缩、打包工具 只有部分工具提供源码,其余主要是历史 EXE

构建清单验证了这几层的关系:主游戏按平台选择 win32lib.libwwflat32.lib,另有 vqa32wp.libvqm32wp.lib;主目录内部还把通用算法归入 tech.lib,把依赖图形库的 ROTBMPSPRITE 归入 jshell.lib。目录位置和逻辑职责并不完全重合。主程序的库分组

1.3 从一个 CPP 到游戏 EXE:构建过程究竟做什么

可以把构建分为编译、归档和链接三步:编译把每个实现文件转为目标文件,归档把一组目标文件装进静态库,链接再选择需要的符号并组织成可执行文件。红警的 CODE/MAKEFILE 使用 Watcom wmake 语法,包括 !ifdef.AUTODEPEND%create 等;不是拿现代 GNU make 原样执行就能完成的通用脚本。

Win32 英文版为例,根据清单推演一条真实依赖路径:

  1. 未指定德语或法语时,LANGUAGE=ENGLISH。定义 WIN32 后,库根变为 ..\win32lib,目标文件放到 obj\win32\ENGLISH,链接响应文件选为 win95.lnk
  2. 例如 UNIT.CPP..\watcom\binnt\wpp386 编译到相应 .obj。所有源文件共享平台宏、语言宏和头文件搜索路径。
  3. LCWMIXFILERAWFILE、加密与校验等对象归入 tech.libSPRITEROTBMP 归入 jshell.lib
  4. wmake 根据主清单生成 win95.lnk,把目标文件、内部库、图形音频库和系统导入库逐条写入。
  5. linker\nwlink 根据响应文件输出 ..\run\ra95.exe

以上是静态依赖推演,不是已执行成功的命令日志。平台路径与语言选择编译与汇编规则内部静态库生成最终链接及响应文件生成

chapter-01-diagram-1:游戏 CPP 与 ASM → 平台及语言对应 OBJ;通用技术模块 → tech.lib 与 jshell.lib;平台库及 VQA 库 → 生成链接响应文件;平台及语言对应 OBJ → 生成链接响应文件;tech.lib 与 jshell.lib → 生成链接响应文件;生成链接响应文件 → ra95.exe 或 DOS game.dat
查看流程图源文本
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.LNKCONQUER.LNK,但主 Makefile 明确会生成它们,所以不能仅凭缺失就判为构建损坏。相反,IPX 的独立脚本引用 thipx32.lnkthipx16.lnk,在当前树中既未找到文件,也未见这些脚本生成它们,这才是需要补齐的另一类输入。主响应文件规则IPX 的依赖

DOS 分支默认目标叫 game.dat,但它是程序,不是资源数据库。其规则先链接 dos.exe,再经过 wstrip 与 DOS/4GW Professional 绑定得到 game.datLAUNCH.ASMGameName 则直接写着 GAME.DATDOS 绑定过程启动目标字符串

平台条件还会更换实现文件:Win32 编译 2KEYFBUF2KEYFRAM,DOS 编译 KEYFBUFFKEYFRAME。研究形状帧缓存时若读错分支,会把不同实现混为一谈。平台对象清单

1.4 编译选项也是游戏格式的一部分

主清单为 Windows 使用 /5r,DOS 使用 /5s,对应不同调用约定;公用选项包含 /zp1 一字节结构体对齐、/j 有符号 char/ri 对小整型返回值的约定,以及严格警告设置。这些选项会影响 C++ 与汇编互调、对象布局和二进制读写。移植时单纯让编译器“不报错”,无法证明游戏状态或资源格式仍然正确。完整核心编译参数

一个具体例子是 FUNCTION.H:当年的编译器没有原生 bool,代码自行声明 false/truetypedef int bool。把它替换成现代一字节 bool,有可能改变包含布尔字段的对象大小。这个问题是否影响某条存档路径,要结合该对象的序列化方式检查;不能笼统认定“改成现代写法总是安全”。历史布尔类型兼容层

因此,在源码分析中,“字段类型”“对象内存”“文件格式”“网络格式”要分别看待。现代工程可以用明确位宽的格式结构、字段级序列化和适配层减少耦合;但那属于移植设计,不是原项目已经具有的保证。

1.5 目前缺少什么,哪些只是生成产物

官方首先列出四组需自行寻找、替换或移除使用代码的依赖:DirectX 5 SDK、DirectX Media 5.1 SDK、Greenleaf Communications Library、HMI SOS。这里不是“所有第三方痕迹都不存在”:树中确实能找到部分 SOS 头文件及 .lib,但不能据此认定版本、ABI、完整性和授权分发条件全部满足。官方依赖表

审计项目 固定提交中的观察 对重建的含义
watcomdxsdkdxmediagcl510 未包含对应完整目录 主清单硬编码了相邻路径,需要外部环境或替代实现
CODE/linker/nwlinkCODE/utils/tasm 未找到指定工具 原命令路径不能直接使用
CODE/mpgdll.libuuid.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.MIXLOCAL.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.mdCODE/MAKEFILE 的平台分支和目标 → DEFINES.H 的版本开关 → RAWOLAPI.H 的版本常量 → WIN32LIB/MAKEFILEWINVQ 子项目 → RULES.MAK。完成这一圈后,再读后续游戏架构章节,能持续判断“这段逻辑属于哪个构建、依赖哪一层”。底层实现与恢复实验详见 第 15 章

尚未确认的边界

本次没有恢复 Watcom/TASM 历史环境,没有链接或运行游戏,没有逐个验证随附 EXE 的功能,没有证明公开树与某个商业发行二进制完全一致。当前编译宏可从清单确认;某个历史发行版本究竟启用了哪些宏、带了哪些资源,仍需相应发行产物作对照。

红色警戒初代 · 源码剖析18 章正文 / 5 份附录
输入关键词,检索 24 份完整文档
全文检索 · 点击结果直达对应小节