CD Code Digest Hub /CS:GO

地图加载与碰撞追踪

6 分钟阅读 5 个章节 1 张图

本页说明一张地图如何从 map de_xxx 命令变成可运行的服务器世界:引擎怎样加载 BSP、建立碰撞模型、把实体字符串交给 server.dll,以及游戏代码最常用的射线追踪 UTIL_TraceLine 最终落到哪里。

相关页面:主循环与 HostState · 实体系统 · 资源与缓存 · 内容工具链

相关源码文件#

  • engine/host_state.cpp、engine/host.cpp:State_NewGame、Host_NewGame
  • engine/sv_main.cpp:CGameServer::SpawnServer、SV_ActivateServer
  • engine/modelloader.cpp:CModelLoader::Map_LoadModel
  • engine/cmodel.cpp:CM_LoadMap、CM_BoxTrace
  • engine/enginetrace.cpp:CEngineTrace::TraceRay
  • game/server/mapentities.cpp:实体字符串解析

1. 新游戏流程#

证据:

  • State_NewGame 在需要时按需加载 server.dll,验证地图有效后调用 Host_NewGame:engine/host_state.cpp:414-454。
  • Host_NewGame 执行游戏类型配置、设置多人标志与监听套接字、SpawnServer、通知插件处理器 LevelInit(实体字符串来自 CM_EntityString())、SV_ActivateServer,最后在非专用服务器上向命令缓冲写入 connect localhost:<port>:engine/host.cpp:6193-6345。
  • SpawnServer 释放旧世界与状态、分配 edict、进入 ss_loading、按名字加载世界模型(失败则 ss_dead),再建字符串表、预缓存世界:engine/sv_main.cpp:2897-2934、engine/sv_main.cpp:2989、engine/sv_main.cpp:3042-3072、engine/sv_main.cpp:3119-3130、engine/sv_main.cpp:3170-3188。
  • SV_ActivateServer 回调游戏的 ServerActivate、切换为 ss_active、创建实体基线:engine/sv_main.cpp:2568-2587。

监听服务器上的本地客户端随后像远程客户端一样经历签入流程(见 网络通道与协议)。

2. BSP 加载#

Map_LoadModel 给加载过程开 4 分钟看门狗,标记已加载,并在 CMapLoadHelper 的初始化/关闭之间调用 Map_LoadModelGuts:engine/modelloader.cpp:5048-5083。Map_LoadModelGuts 先读取 LUMP_TEXINFO 并校验尺寸,然后首先加载碰撞模型 CM_LoadMap,再加载顶点等渲染数据:engine/modelloader.cpp:5088-5124。CM_LoadMap 的定义见 engine/cmodel.cpp:334。

地图中预置的实体由 BSP 的实体字符串驱动创建(玩家、武器、投射物等则在运行时动态创建):LevelInit 调用 MapEntity_ParseAllEntities,按 classname 通过工厂创建实体、解析键值、再统一 Spawn/Activate(详见 实体系统):game/server/gameinterface.cpp:1192-1275、game/server/mapentities.cpp:520-569。

3. 碰撞追踪#

游戏代码的 UTIL_TraceLine 构造 Ray_t 与过滤器后调用 enginetrace->TraceRay:game/shared/util_shared.h:309-317。引擎为服务端与客户端各暴露一个 IEngineTrace 实现:engine/enginetrace.cpp:240-244。

CEngineTrace::TraceRay 的顺序:

  1. 清空结果,对世界(BSP 刷子)执行 CM_BoxTrace;起点在固体内或过滤器只要求世界时提前返回:engine/enginetrace.cpp:2786-2846。
  2. 把射线截断到世界命中点,然后用空间分区 EnumerateElementsAlongRay 收集沿线实体,按过滤器类型决定是否包含静态道具:engine/enginetrace.cpp:2853-2892。
  3. 对候选实体逐个 ClipRayToEntity:engine/enginetrace.cpp:1452。

BSP 层的盒体追踪与点内容查询入口:engine/cmodel.cpp:3194、engine/cmodel.cpp:3253、engine/cmodel.cpp:719。

约束与边界#

  • 物理模拟(IPhysics/vphysics)与碰撞追踪是两套系统:追踪由引擎 cmodel 与空间分区完成,刚体物理由缺失源码的 vphysics 模块完成(见 构建与物理组织)。
  • 本页只讲加载与碰撞。区域门户、PVS 在渲染中的使用与静态道具管理器见 引擎世界渲染;PVS 由离线工具 vvis 计算,BSP lump 的生成见 地图编译器。BSP 各 lump 的二进制格式本身仍未逐项展开。