CD Code Digest Hub /CS:GO

游戏 DLL 契约:client.dll 与 server.dll

12 分钟阅读 7 个章节

引擎通过一组版本化接口调用游戏代码,游戏代码再通过另一组接口回调引擎。理解这些契约就能知道“某段玩法代码在什么时候、被谁、在哪个进程里执行”。

子页面:

相关页面:引擎总览 · 主循环与 Tick · CS:GO 玩法总览

相关源码文件#

  • 契约:public/eiface.h(服务端)、public/cdll_int.h(客户端)
  • 服务端实现:game/server/gameinterface.cpp
  • 客户端实现:game/client/cdll_client_int.cpp
  • 引擎侧加载:engine/sys_dll2.cpp、engine/sys_dll.cpp、engine/sv_main.cpp、engine/cdll_engine_int.cpp

1. 接口一览#

方向接口(版本)实现证据
引擎→服务端IServerGameDLL(ServerGameDLL005)CServerGameDLLpublic/eiface.h:547-574、game/server/gameinterface.cpp:696
引擎→服务端IServerGameClientsCServerGameClientspublic/eiface.h:767、game/server/gameinterface.cpp:3098
引擎→服务端IServerGameEnts(含 CheckTransmit)CServerGameEntspublic/eiface.h:736-756、game/server/gameinterface.cpp:2650
服务端→引擎IVEngineServerCVEngineServerpublic/eiface.h:139、engine/vengineserver_impl.cpp:2059
引擎→客户端IBaseClientDLL(VClient018)CHLClientpublic/cdll_int.h:878、public/cdll_int.h:1177、game/client/cdll_client_int.cpp:1058
客户端→引擎IVEngineClientCEngineClientpublic/cdll_int.h:298、engine/cdll_engine_int.cpp:736

2. 加载与初始化#

  • 引擎在 Mod 组 Create 中加载 client 与 server 模块,并读取二者声明的共享 AppSystem:engine/sys_dll2.cpp:2240-2321。
  • server 的 DLLInit 由 SV_InitGameDLL 调用,传入的第一个工厂是 g_GameSystemFactory:engine/sv_main.cpp:1095-1097。它先连接 tier 库,再逐个获取引擎接口(任一缺失返回 false),获取 IGameTypes,初始化数学库与游戏系统,最后初始化游戏模式表:game/server/gameinterface.cpp:702-786、game/server/gameinterface.cpp:794-795、game/server/gameinterface.cpp:843-845、game/server/gameinterface.cpp:923-935。
  • client 的 Connect 连接 tier 库、获取 Scaleform 接口并注册 ConVar(FCVAR_CLIENTDLL):game/client/cdll_client_int.cpp:1387-1437;Init 获取各类引擎接口与 IGameTypes、初始化游戏系统与粒子管理器:game/client/cdll_client_int.cpp:1452、game/client/cdll_client_int.cpp:1529、game/client/cdll_client_int.cpp:1651-1699。它由引擎的 ClientDLL_Init 以 g_GameSystemFactory 调用:engine/cdll_engine_int.cpp:2720。

一个跨模块的细节:谁提供 IGameTypes?#

gametypes.cpp 同时编译进 client、server、matchmaking 三个模块,每个模块都用 EXPOSE_SINGLE_INTERFACE_GLOBALVAR 暴露 VENGINE_GAMETYPES_VERSION:game/shared/cstrike15/gametypes.cpp:209、matchmaking/matchmaking_cstrike15_inc.vpc:35。游戏 DLL 通过 g_GameSystemFactory 获取它,而该工厂的查询顺序是 AppSystem 组 → matchmaking → client → GameUI:engine/sys_dll.cpp:1014-1044;matchmaking 作为 AppSystem 的 QueryInterface 只回答 IMatchFramework:matchmaking/main.cpp:160-166。由此推断:client 与 server 拿到的都是 matchmaking.dll 中的那份 GameTypes 单例,三方共享同一份模式状态(推断,未运行验证)。

3. 服务端回调时间线#

时机回调证据
换图开始LevelInit:解析实体字符串、创建并 Spawn 地图实体game/server/gameinterface.cpp:1192-1275
地图激活ServerActivate(同时激活 Bot 管理器)game/server/gameinterface.cpp:1338、game/server/gameinterface.cpp:1382
Steam 就绪GameServerSteamAPIActivated:初始化 Steam 上下文与 GC 客户端系统game/server/gameinterface.cpp:1389-1411
每个服务器 tickGameFrame(simulating)game/server/gameinterface.cpp:1418-1536
每帧最后一个 tickThink(finalTick)、PreClientUpdategame/server/gameinterface.cpp:1593-1620、game/server/gameinterface.cpp:1542
收到 clc_MoveProcessUsercmdsgame/server/gameinterface.cpp:3565-3651
打快照CheckTransmit、发送后 PostClientMessagesSentgame/server/gameinterface.cpp:2784、game/server/gameinterface.cpp:3654-3658
换图结束LevelShutdowngame/server/gameinterface.cpp:1627

4. 客户端回调时间线#

时机回调证据
每帧开头FrameStageNotify(FRAME_START)engine/sys_engine.cpp:530-535
每个 tick 输入阶段CreateMove → CInput::CreateMoveengine/cl_main.cpp:2789-2793、game/client/cdll_client_int.cpp:2169-2185
收到实体包FRAME_NET_UPDATE_START … _ENDengine/cl_ents_parse.cpp:631-698
渲染前FRAME_RENDER_START → OnRenderStart:插值、客户端动画、数据变化事件、SimulateEntitiesengine/gl_screen.cpp:287、game/client/cdll_client_int.cpp:3234-3323
渲染View_Render → CViewRender::Rendergame/client/cdll_client_int.cpp:2222-2235
渲染后FRAME_RENDER_ENDengine/gl_screen.cpp:311

帧阶段枚举定义见 public/cdll_int.h:218-237,client.dll 对各阶段的处理见 game/client/cdll_client_int.cpp:3400-3521。

5. 共享代码的双端编译#

game/shared 下的文件同时编译进两端,靠 CLIENT_DLL/GAME_DLL 区分。阅读时要注意三种常见模式:

模式例子证据
同名类在客户端加 C_ 前缀FX_FireBullets 中 C_CSPlayer 与 CCSPlayergame/shared/cstrike15/fx_cs_shared.cpp:169-173
只在服务端执行的权威逻辑延迟补偿仅在 !CLIENT_DLL 下启用game/shared/cstrike15/fx_cs_shared.cpp:380-383
只在客户端执行的表现/防重入客户端同一发子弹 20ms 内不重复追踪game/shared/cstrike15/fx_cs_shared.cpp:201-214

约束与边界#

  • 只有 IServerGameDLL 等核心接口被逐条核对;IServerGameTags、IServerGameDLL 的存档/读档回调(SaveInit 等)对 CS:GO 多人模式意义不大,未展开。
  • client.dll 中大量 C_ 实体(视觉效果、HUD、GameUI)只按需在其它页面引用。