客户端启动链:从 csgo.exe 到第一帧
本页追踪 Windows 客户端(同时也是“监听服务器”)的启动顺序:可执行文件如何找到 DLL、三层 AppSystemGroup 如何嵌套、引擎何时加载游戏 DLL、以及主循环从哪里开始。
相关页面:接口工厂与 AppSystem · 专用服务器 · 主循环与 Tick
相关源码文件#
launcher_main/main.cpp:最外层可执行入口launcher/launcher.cpp:LauncherMain、CSourceAppSystemGroupappframework/WinApp.cpp:CSteamApplicationengine/sys_dll2.cpp:CEngineAPI、CModAppSystemGroupengine/sys_engine.cpp、engine/sys_dll.cpp、engine/host.cpp:引擎加载与Host_Init
1. 总体时序#
下文逐步给出每条箭头的证据。
2. 可执行入口 WinMain#
- 用可执行文件路径推出根目录,把
<root>\bin(64 位为bin\x64)前置到PATH:launcher_main/main.cpp:118-149。 - 用
LoadLibraryEx(..., LOAD_WITH_ALTERED_SEARCH_PATH)加载bin\launcher.dll;失败时弹出系统错误信息并返回 0:launcher_main/main.cpp:151-173。 - 取导出函数
LauncherMain并直接调用:launcher_main/main.cpp:175-176。
同一文件还包含 PS3 与 POSIX 版本的入口(POSIX 用 dlopen/dlsym):launcher_main/main.cpp:619、launcher_main/main.cpp:681。
3. LauncherMain:命令行整理与重启循环#
LauncherMain 由 extern "C" __declspec(dllexport) 导出:launcher/launcher.cpp:1479-1485。在进入 AppSystem 之前它会修补命令行,例如非 Steam 启动时自动追加 -insecure:launcher/launcher.cpp:1847-1851;构建 cubemap 时追加 -nosound -noasync:launcher/launcher.cpp:1861-1866。
核心是一个重启循环:每轮构造新的 CSourceAppSystemGroup 与包裹它的 CSteamApplication 并运行;若在初始化阶段返回 INIT_RESTART 或运行阶段返回 RUN_RESTART 就重来,并清除与窗口尺寸相关的命令行覆盖项:launcher/launcher.cpp:1870-1922。这就是“修改视频设置后引擎整体重启”的实现位置。
4. 第一层:CSteamApplication#
Create 先通过 FileSystem_GetFileSystemDLLName 决定文件系统模块,然后把 vstdlib 的 cvar 工厂与文件系统加入本组:appframework/WinApp.cpp:148-171。Main 设置基础路径后,把自己作为父组传给 CSourceAppSystemGroup 并运行它:appframework/WinApp.cpp:202-210。
5. 第二层:CSourceAppSystemGroup#
Create:决定加载哪些模块#
模块表以 {DLL 名, 接口版本} 的形式列出,注释特别说明 engine 必须排第一:launcher/launcher.cpp:727-770。随后:
- 定义
INCLUDE_SCALEFORM时,按-sf3选择scaleformui_3或scaleformui:launcher/launcher.cpp:784-810。 -tools/-p4时加载p4lib;Windows PC 上加载 vstdlib 的IProcessUtils;-dev时加载资源访问控制:launcher/launcher.cpp:812-840。- 取得
IMaterialSystem与IEngineAPI指针;-edit模式额外加载hammer_dll:launcher/launcher.cpp:842-858。 - 必须在 Connect 之前选择 Shader API:默认
shaderapidx9,-noshaderapi改用shaderapiempty,-shaderapi <dll>可任意指定:launcher/launcher.cpp:860-872。材质系统随即加载该 DLL 并保存其工厂:materialsystem/cmaterialsystem.cpp:746-774。
PreInit:连接基础库并挂载内容#
依次 ConnectTier1Libraries、ConVar_Register、ConnectTier2/3Libraries,若文件系统或材质系统指针为空直接失败:launcher/launcher.cpp:880-889。然后设置 Steam 环境、挂载 gameinfo 内容、可选 -vpk 追加 VPK、加入 platform 搜索路径:launcher/launcher.cpp:895-936。最后把实例句柄、基础目录、初始 mod/game、父组指针打包成 StartupInfo_t 交给引擎:launcher/launcher.cpp:958-966。
Main#
只有一行:return g_pEngineAPI->Run();:launcher/launcher.cpp:969-972。
6. 引擎:CEngineAPI::Run → RunListenServer#
Run在-insecure时禁止连接安全服务器;Windows 非调试会话下用 SE translator 捕获结构化异常并写 minidump,异常时TerminateProcess(…,100):engine/sys_dll2.cpp:1736-1779。RunListenServer调ModInit(设置host_parms.mod/game、注册表路径、读取预启动配置并创建游戏窗口:engine/sys_dll2.cpp:1319-1355),然后构造以启动器组为父的CModAppSystemGroup并运行,结束后ModShutdown:engine/sys_dll2.cpp:1409-1447。
7. 第三层:CModAppSystemGroup#
Create 的顺序:
- 非 Perforce 运行且需要时,通过
SteamAPI_RestartAppIfNecessary让 Steam 重启进程:engine/sys_dll2.cpp:2161-2165。 - 校验并加载
matchmaking(专用服务器为matchmaking_ds)。签名校验失败时仍会加载,但把客户端置为不能连接安全服务器;拿不到IMatchFramework则Sys_Error:engine/sys_dll2.cpp:2180-2231。 - 非纯服务器时
ClientDLL_Load+ClientDLL_Connect,然后ServerDLL_Load:engine/sys_dll2.cpp:2240-2259。 - 读取 client/server 声明的共享系统列表,合并去重后
AddSystems;再把 engine 自身的工具框架接口加入:engine/sys_dll2.cpp:2261-2330。
Main 在非纯服务器分支中调用 eng->Load(false, …),再进入 s_EngineAPI.MainLoop();MainLoop 返回 true 表示需要重启(RUN_RESTART):engine/sys_dll2.cpp:2398-2425。
8. eng->Load → Sys_InitGame → Host_Init#
CEngine::Load 把 DLL 状态置为 active 并调用 Sys_InitGame:engine/sys_engine.cpp:237-257。Sys_InitGame 依次初始化平台、内存、Host_Init、认证:engine/sys_dll.cpp:1133-1157。Host_Init 中与游戏模块相关的顺序:
| 步骤 | 证据 |
|---|---|
| 控制台、命令缓冲、cvar 等基础设施 | engine/host.cpp:5557-5565 |
网络、游戏事件管理器、sv.Init | engine/host.cpp:5611-5616 |
未加 -nogamedll 时 SV_InitGameDLL(调用 server 的 DLLInit) | engine/host.cpp:5618-5621、engine/sv_main.cpp:1095-1097 |
| HLTV 初始化 | engine/host.cpp:5625 |
客户端:CL_Init、材质系统、Scaleform 全屏/光标、模型加载器、studiorender、匹配框架、VGUI、ClientDLL_Init | engine/host.cpp:5636-5661 |
声音 S_Init,执行 valve.rc、配置文件 | engine/host.cpp:5713、engine/host.cpp:5745-5760 |
client.dll 的 Init 收到的是引擎的 g_GameSystemFactory:engine/cdll_engine_int.cpp:2720。这个工厂依次询问 AppSystem 组、matchmaking、client、GameUI:engine/sys_dll.cpp:1014-1062。
9. 主循环#
CEngineAPI::MainLoop 在退出标志未设时,每轮泵消息(编辑模式走另一套泵),然后 eng->Frame(),编辑模式下再驱动 Hammer:engine/sys_dll2.cpp:1126-1167。eng->Frame() 之后的逻辑见 主循环与 Tick。
约束与边界#
- 启动器按名字加载
vphysics、shaderapidx9、scaleformui等模块,而这些模块要么不在csgo_partner组、要么源码缺失(见 构建与物理组织)。任一AddSystems失败都会让Create返回 false,从而整个启动失败:launcher/launcher.cpp:778-779、appframework/AppSystemGroup.cpp:301-316。 - 签名校验失败的 matchmaking 模块仍被加载,但会触发
Host_DisallowSecureServers:engine/sys_dll2.cpp:2182-2188。 - 本次没有运行启动链;上述顺序来自静态阅读,平台分支(OSX Cocoa、SDL、PS3、X360)只做了存在性确认。