Bot
CS:GO 的 Bot 是伪装成玩家的服务端实体:CCSBot 继承自 CCSPlayer,它不走网络,而是每帧自己构造一条 CUserCmd,直接交给玩家层的 ProcessUsercmds(跳过了引擎解码与游戏层的命令校验),之后与真人共用同一条命令执行路径。这意味着 Bot 受同样的移动、武器、规则约束。
相关页面:Bot 决策:感知、瞄准、档案与沟通 · 导航网格 · 玩家 · 输入与预测 · 主循环与 Tick · 投掷物与 C4
相关源码文件#
- 通用模板:
game/shared/cstrike15/bot/bot.h、game/shared/cstrike15/bot/bot.cpp、game/shared/cstrike15/bot/bot_manager.cpp、game/shared/cstrike15/bot/bot_profile.cpp - CS 实现:
game/server/cstrike15/bot/(40 个文件),核心为game/server/cstrike15/bot/cs_bot.h、game/server/cstrike15/bot/cs_bot_update.cpp、game/server/cstrike15/bot/cs_bot_manager.cpp、game/server/cstrike15/bot/cs_bot_statemachine.cpp、states/*.cpp
注意区分:仓库中还有通用的
game/server/NextBot框架,但 CS:GO 服务端工程没有引用它;CS:GO Bot 使用的是CBot<CCSPlayer>这一套(本次在server_cstrike15_inc.vpc中未检索到NextBot)。
1. 类型结构#
template <class PlayerType> class CBot : public PlayerType:提供移动/开火等“按键”原语,要求子类实现轻量的Upkeep与重量的Update:game/shared/cstrike15/bot/bot.h:134-156、game/shared/cstrike15/bot/bot.h:159-193。class CCSBot : public CBot< CCSPlayer >:game/server/cstrike15/bot/cs_bot.h:462;实体类名cs_bot:game/server/cstrike15/bot/cs_bot.cpp:21。
2. 每帧驱动#
证据:
EndGameFrame中调用TheBots->StartFrame(),注释说明放在物理模拟之后,以免可见性检查重复计算骨骼:game/shared/cstrike15/cs_gamerules.cpp:9886-9893;EndGameFrame本身在GameFrame末尾调用:game/server/gameinterface.cpp:1507-1512。CCSBotManager::StartFrame:暂停或不允许 Bot 时返回;调用通用StartFrame;半场换边期间之外维护 Bot 数量:game/server/cstrike15/bot/cs_bot_manager.cpp:300-320。CBotManager::StartFrame:对每个 Bot 每帧Upkeep;当(tickcount + entindex) % g_BotUpdateSkipCount == 0时ResetCommand + Update(把重计算错开到不同 tick);最后UpdatePlayer:game/shared/cstrike15/bot/bot_manager.cpp:103-153。UpdatePlayer:冻结时清零按键与速度;用当前视角、前后/侧向/竖直速度与按键位BuildUserCmd,做玩家避让,然后ProcessUsercmds( &m_userCmd, 1, 1, 0, false )把命令排队:game/shared/cstrike15/bot/bot.h:860-889。
因此 Bot 的命令同样在下一次 Physics_RunThinkFunctions 中由 PlayerRunCommand 执行(见 输入与预测)。
3. 行为:状态机#
BotState 只有 OnEnter/OnUpdate/OnExit/GetName:game/server/cstrike15/bot/cs_bot.h:56-63。具体状态包括空闲(行动选择中枢,注释说明 Bot 不会停留在该状态)、搜寻、攻击、调查声音、购买、移动、取包、下包、拆包、捡人质、隐藏、逃离炸弹、跟随、使用实体、开门、逃离火焰:game/server/cstrike15/bot/cs_bot.h:66-442,各状态实现在 states/ 目录。
SetState 退出正在进行的攻击、调用旧状态 OnExit 与新状态 OnEnter 并记录时间戳:game/server/cstrike15/bot/cs_bot_statemachine.cpp:23-56。CCSBot::Update 在做完卡住检测、反应队列、威胁评估(必要时切到 Attack)、武器选择等通用逻辑后,调用当前状态的 OnUpdate:game/server/cstrike15/bot/cs_bot_update.cpp:232、game/server/cstrike15/bot/cs_bot_update.cpp:311、game/server/cstrike15/bot/cs_bot_update.cpp:373、game/server/cstrike15/bot/cs_bot_update.cpp:475-480、game/server/cstrike15/bot/cs_bot_update.cpp:880。轻量的 Upkeep(源码注释称“lightweight maintenance, invoked frequently”)每个 tick 都运行,负责平滑瞄准与视角弹簧,网格生成中或死亡时直接返回:game/shared/cstrike15/bot/bot.h:155-156、game/server/cstrike15/bot/cs_bot_update.cpp:29-142。Update 内各阶段的完整顺序、感知与开火判定见 Bot 决策。
Bot 通过游戏事件感知世界,例如 C4 每次 C4Think 都触发 bomb_beep 让 Bot“听到”:game/shared/cstrike15/weapon_c4.cpp:403-410;烟雾弹引爆时向 Bot 管理器登记烟雾半径,用于视线判断:game/shared/cstrike15/smokegrenade_projectile.cpp:177。事件如何分发到每个 Bot、各声源的可闻距离见 Bot 决策。导航网格在每个 GameFrame 更新:game/server/gameinterface.cpp:1472;其结构、加载与寻路见 导航网格。
4. 数量管理#
| ConVar | 含义 | 证据 |
|---|---|---|
bot_quota(默认 10) | 目标 Bot 数 | game/server/cstrike15/bot/cs_bot_init.cpp:63 |
bot_quota_mode | normal:固定数量;fill:真人 + Bot = quota;match:Bot = quota × 真人数 | game/server/cstrike15/bot/cs_bot_init.cpp:64 |
MaintainBotQuota 根据模式计算期望数量,没有真人也没有旁观者时期望为 0:game/server/cstrike15/bot/cs_bot_manager.cpp:1435-1497。手动添加走 BotAddCommand:game/server/cstrike15/bot/cs_bot_manager.cpp:1035。离线模式下 Bot 难度相关 ConVar 由游戏模式表限定(见 比赛模式)。
约束与边界#
- 本页只覆盖类型结构、每帧驱动、状态机框架与数量管理。视觉/听觉与反应队列、瞄准与开火、
BotProfile.db格式及字段作用、路径跟随与卡住恢复、购买、语音聊天与无线电、炸弹/人质等战术事件响应见 Bot 决策;Bot 语音与玩家无线电共用的响应规则与场景播放见 场景与响应规则;导航网格的数据结构、.nav格式与加载、分阶段生成、A* 寻路见 导航网格。注意game/shared/cstrike15/bot/nav_path.cpp未被编入 CS:GO 服务端,实际编译的是内容几乎相同的cs_nav_path.cpp:game/server/server_cstrike15_inc.vpc:345-356。 .nav、BotProfile.db、BotChatter.db都属于内容,不在仓库中。缺少.nav时,添加 Bot 会在 PC 上触发一次自动生成(主机平台直接拒绝),生成期间不允许 Bot 加入:game/server/cstrike15/bot/cs_bot_manager.cpp:1037-1060。- 仍未展开:
game/server/NextBot框架(CS:GO 未使用)、投掷物的目标选择与投掷状态机、人质护送与跟随细节、合作模式(Guardian / Coop Mission)专用逻辑。