概览:这个仓库是什么
本页给出整个代码库的“地图”:它包含哪些可部署单元、它们如何在运行时组合、一个玩家在服务器上开一枪时代码会穿过哪些模块,以及这份快照缺了什么。后续各页按子系统展开。
阅读前提:本文所有结论都基于仓库快照
f82112a2388b841d72cb62ca48ab1846dfcc11c8(提交日期 2020-04-23)的静态阅读,没有编译或运行。
1. 一句话定位#
这是 Valve Source 引擎(CS:GO 分支)+ CS:GO 游戏模块 + 配套内容工具的 C++ 源码树,构建由 Valve 自有的 VPC 工程生成器驱动,默认工程组是 csgo_partner:CreateSolution.bat:1、vpc_scripts/default.vgc:11-24。
它不是可直接运行的游戏发行包:仓库中找不到任何 .bsp/.vpk/.mdl/.vtf/.vmt 内容文件(本次用文件扫描确认为 0 个),根目录的提示文本也要求另行下载 2017-05-18 的游戏文件:[CSGO NEEDS MAY 18 2017 FILES BEFORE HYDRA.txt](../Counter-Strike-Global-Offensive/CSGO NEEDS MAY 18 2017 FILES BEFORE HYDRA.txt)。
2. 仓库形态#
| 维度 | 观察 | 证据 |
|---|---|---|
| 规模 | git ls-files 共 14,245 个文件;game/ 2,744、thirdparty/ 2,634、materialsystem/ 1,733、public/ 1,717、engine/ 741 | 本次统计命令(见 审计) |
| 游戏 | VPC 只启用 CSGO 一个游戏,其余游戏(TF、Portal2、DOTA…)被注释 | vpc_scripts/default.vgc:11-21 |
| 平台 | 工程条件同时出现 Windows、POSIX/Linux、OSX、X360、PS3 | vpc_scripts/projects.vgc:185、vpc_scripts/projects.vgc:1243 |
| 构建 | 没有统一 CMake;vpc.exe 生成 .sln,.proto 通过自定义构建步骤调用仓库内 protoc.exe | CreateSolution.bat:1、vpc_scripts/protobuf_builder.vpc:9-19 |
| 测试 | unittests/ 只有 1 个跟踪文件,而工程注册表登记了多个测试工程 | vpc_scripts/projects.vgc:1626-1634、unittests/rendersystemtest/worldrenderertest.cpp |
3. 运行时组件关系#
图中每条边的证据:
csgo.exe入口加载bin\launcher.dll并调用导出函数LauncherMain:launcher_main/main.cpp:151-176。LauncherMain用CSteamApplication包裹CSourceAppSystemGroup并运行:launcher/launcher.cpp:1870-1881;CSteamApplication::Create先加载 cvar 与文件系统模块:appframework/WinApp.cpp:148-171。CSourceAppSystemGroup::Create的模块清单包含 engine、filesystem_stdio、inputsystem、vphysics、materialsystem、datacache、studiorender、soundemittersystem、vscript 等:launcher/launcher.cpp:727-770。- 引擎在
CModAppSystemGroup::Create中加载matchmaking(专用服务器为matchmaking_ds)、client 与 server 模块:engine/sys_dll2.cpp:2190-2259。 - 专用服务器入口加载
bin\dedicated.dll并调用DedicatedMain:dedicated_main/main.cpp:98-113,后者通过VENGINE_HLDS_API_VERSION获取引擎的专用服务器接口:dedicated/sys_windows.cpp:266-289。
模块之间几乎全部通过“版本化接口名 + CreateInterface 工厂”连接,而不是直接链接导出符号;这是理解整个代码库的第一把钥匙,见 接口工厂与 AppSystem。
4. 一次射击如何穿过各层(代表性端到端路径)#
- 客户端引擎在每个 tick 的输入阶段调用
CL_Move,再由 client.dll 的CInput::CreateMove生成CUserCmd:engine/host.cpp:3278-3290、game/client/in_main.cpp:1350-1361。 - 命令被增量编码进
CCLCMsg_Move发往服务器:engine/cl_main.cpp:2684-2731。 - 服务器引擎收到
clc_Move后交给IServerGameClients::ProcessUsercmds,玩家在随后的GameFrame物理模拟中执行命令:engine/sv_client.cpp:253-305、game/server/player.cpp:3598-3611。 - 武器的
PrimaryAttack→CSBaseGunFire→ 共享函数FX_FireBullets,服务端在其中包裹延迟补偿并逐弹调用CCSPlayer::FireBullet:game/shared/cstrike15/weapon_csbasegun.cpp:305-337、game/shared/cstrike15/fx_cs_shared.cpp:380-383、game/shared/cstrike15/fx_cs_shared.cpp:548-577。 - 伤害改变网络变量(如血量、金钱),帧末
SV_SendClientUpdates打快照、按客户端 PVS 差量编码实体并发送:engine/sv_main.cpp:3402-3417、engine/sv_main.cpp:2213-2263。 - 客户端
CL_ProcessPacketEntities解码实体,HUD 在下一帧读取新值(例如金钱面板读GetAccount()):engine/cl_ents_parse.cpp:574-701、game/client/cstrike15/Scaleform/HUD/sfhudmoney.cpp:194-227。
各步骤的细节分别在 输入与预测、武器与射击、延迟补偿、实体复制、HUD 页面。
5. 关键设计约束(贯穿全书)#
- 同一份源码编译两次。
game/shared下的规则、移动、武器文件同时出现在 client 与 server 工程里,分别用CLIENT_DLL/GAME_DLL宏区分分支:game/client/client_cstrike15.vpc:175-181、game/server/server_cstrike15_inc.vpc:96-110、game/client/client_base.vpc:60、game/server/server_base.vpc:56。阅读这些文件时必须先确认当前分支属于哪一端。 - 服务器权威、客户端预测。 服务器真正执行
CUserCmd;客户端用同一套移动/武器代码先行模拟并在收到权威状态后重放,见 输入与预测。 - 固定 tick。 引擎把可变的帧时间累积并切成整数个
interval_per_tick,每个 tick 依次跑输入、服务器、客户端:engine/host.cpp:4079-4096、engine/host.cpp:4185-4277。 - 输出不在仓库内。 引擎与工具输出到
$SRCDIR\..\game\bin,游戏 DLL 输出到$SRCDIR\..\game\csgo\bin:engine/engine_inc.vpc:8、game/client/client_base.vpc:8。
6. 完整性边界(重要)#
| 缺口 | 证据 | 影响 |
|---|---|---|
vphysics 实现源码不存在,但启动器与专用服务器都要加载 vphysics 模块 | vpc_scripts/projects.vgc:1956-1959、launcher/launcher.cpp:739、dedicated/sys_windows.cpp:274 | 只能依赖外部二进制;lib/common 下有 IVP/Havana 预编译库 |
Scaleform SDK(thirdparty/scaleform/sdk42)不存在,但 scaleformui 工程引用它 | scaleformui/scaleformui.vpc:33-51 | HUD/菜单接入层源码在,SDK 不在 |
服务端调用 GCClientSystem(),但全仓库没有任何头文件声明它;多个客户端文件 include 的 gc_clientsystem.h 也不存在 | game/server/gameinterface.cpp:1397-1405、game/server/cstrike15/cs_voteissues.cpp:22-24 | 不定义 NO_STEAM_GAMECOORDINATOR 时服务端很可能无法编译(推断) |
44 个源文件中共有 131 处 Removed for partner depot 标记,函数体或分支被删空,例如武器后坐力 CWeaponCSBase::Recoil | game/shared/cstrike15/weapon_csbase.cpp:3833-3836、game/server/cstrike15/cs_gameinterface.cpp:149-165 | 部分玩法、GC、反作弊/认证、UI 行为在源码层面不完整 |
GC 后端、gcsdk_game.vpc 不存在,仅有接口与预编译 gcsdk.lib | vpc_scripts/projects.vgc:445-453 | 只能看到协议与客户端接入 |
| 无内容资源、几乎无测试 | 见上文 | 不能把“源码覆盖面”当作“可重建程度” |