Manico CSGOBetterbots指南:深入解析

bot_stuff.sp篇

un1 powered by Gemini

恭喜你找到了这个宝藏!本指南将带你了解Manico的Betterbots插件。主要围绕bot_stuff.sp这个关键的模块。这里假定被我命名为 bot_stuff_manico_20250813.sp。通过本指南,你可以理解其工作原理,并学会如何自定义这些强大的功能。

2. SourceMod 是什么?

在深入学习插件之前,我们先来简单了解一下 SourceMod。

3. 核心功能解析

这个插件做了很多“不简单”的事情,让我们来一一揭秘。

3.1. 专业级 Bot AI:模拟职业选手行为

插件最引人注目的功能是让机器人模仿职业选手。它通过调整 Bot 的内部参数和决策逻辑来实现:

3.2. 经济管理与武器购买策略

普通的 CS:GO Bot 购买行为很呆板,这个插件大大提升了它们的经济管理能力:

3.3. C4/人质场景 AI 改进

在特殊游戏模式下,Bot 的目标意识更强:

3.4. 投掷物利用

Bot 不再只是随意扔雷,它们变得更具策略性:

3.5. 高级移动与射击策略

Bot 的移动和射击行为更加“人类化”:

3.6. 团队花名册与职业选手模拟

通过自定义命令和配置文件,你可以让 Bot 组成特定的“战队”:

4. 函数实现原理

本节将深入探讨插件中使用的核心 SourceMod 编程概念和函数,了解这些功能是如何实现上述智能表现的。

4.1. 事件钩子 (Event Hooks)

插件通过监听游戏事件来触发相应的 Bot 行为。这是 SourceMod 插件最基本的交互方式。当游戏内发生特定事件(如玩家重生、回合开始)时,插件中预先定义的函数就会被调用。

代码示例:监听游戏事件
public void OnPluginStart()
{
    HookEventEx("player_spawn", OnPlayerSpawn);
    HookEventEx("round_prestart", OnRoundPreStart);
    // ... 其他事件
}

public void OnPlayerSpawn(Event eEvent, const char[] szName, bool bDontBroadcast)
{
    // 当有玩家(包括 Bot)重生时执行
    int client = GetClientOfUserId(eEvent.GetInt("userid"));
    SetPlayerTeammateColor(client); // 设置队员颜色
    // ... 更多重生逻辑
}

4.2. SDK 调用 (SDK Calls)

SDK 调用是 SourceMod 插件与游戏引擎底层 C++ 函数直接交互的一种高级方式。它允许插件执行游戏内部的私有或保护函数,从而实现对游戏行为的深度控制。这些调用通常依赖于一个 .games 配置文件来获取函数在内存中的地址和参数签名。

代码示例:SDK 调用初始化 & 实际使用
public void LoadSDK()
{
    GameData hGameConfig = new GameData("botstuff.games");
    // ... 获取各种偏移量和函数签名
    
    // 示例:获取 Bot 移动函数
    StartPrepSDKCall(SDKCall_Player);
    PrepSDKCall_SetFromConf(hGameConfig, SDKConf_Signature, "CCSBot::MoveTo");
    PrepSDKCall_AddParameter(SDKType_Vector, SDKPass_Pointer);
    PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain);
    g_hBotMoveTo = EndPrepSDKCall(); // 保存函数句柄
    // ... 其他 SDK 调用
}

public void BotMoveTo(int client, float fOrigin[3], RouteType routeType)
{
    SDKCall(g_hBotMoveTo, client, fOrigin, routeType); // 直接调用 Bot 内部移动函数
}

4.3. 动态绕道 (Detours)

动态绕道是一种更强大的 SDK 交互方式。它允许插件“拦截”游戏内部的某个函数调用,在原函数执行之前(Pre-Hook)或之后(Post-Hook),或者完全取代原函数(Supercede),插入自定义的逻辑。

代码示例:动态绕道初始化 & 被绕道函数
public void LoadDetours()
{
    GameData hGameData = new GameData("botstuff.games");
    DynamicDetour hBotSetLookAtDetour = DynamicDetour.FromConf(hGameData, "CCSBot::SetLookAt");
    hBotSetLookAtDetour.Enable(Hook_Pre, CCSBot_SetLookAt); // 在原函数执行前调用 CCSBot_SetLookAt
    // ... 其他 Detours
}

public MRESReturn CCSBot_SetLookAt(int client, DHookParam hParams)
{
    char szDesc[64];
    DHookGetParamString(hParams, 1, szDesc, sizeof(szDesc));

    if (strcmp(szDesc, "Avoid Flashbang") == 0)
    {
        DHookSetParam(hParams, 3, PRIORITY_HIGH); // 修改 Avoid Flashbang 的优先级
        return MRES_ChangedHandled; // 表示已修改参数并处理
    }
    // ... 其他逻辑
}

4.4. 属性操控 (Prop Manipulation)

Source 引擎中的实体(如玩家、武器、C4)都有各种“属性”(Properties),这些属性存储了实体当前的状态和数据。SourceMod 允许插件读取和修改这些属性。

代码示例:获取和设置属性
// 获取玩家的经济 (m_iAccount 是经济属性)
int iAccount = GetEntProp(i, Prop_Send, "m_iAccount");

// 设置 Bot 的士气 (g_iBotMoraleOffset 是一个预先获取的士气属性的偏移量)
SetEntData(i, g_iBotMoraleOffset, -3);

// 获取 Bot 是否在购买区 (m_bInBuyZone 是一个布尔属性)
bool bInBuyZone = !!GetEntProp(i, Prop_Send, "m_bInBuyZone");

4.5. 定时器 (Timers)

定时器允许插件在未来的某个时间点或以一定频率重复执行某个函数。这对于需要持续检查状态或定期执行任务的功能非常有用。

代码示例:创建定时器
public void OnMapStart()
{
    CreateTimer(1.0, Timer_CheckPlayer, _, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE); // 每1秒执行一次
    CreateTimer(0.1, Timer_MoveToBomb, _, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE); // 每0.1秒执行一次
    // ...
}

4.6. 配置数据 (KeyValues & JSON)

插件使用 KeyValues (标准的 Valve 配置文件格式) 和 JSON (一种轻量级的数据交换格式) 来存储和读取外部配置数据。这使得用户无需修改源代码就能自定义插件行为。

代码示例:读取 KeyValues & JSON 文件
public Action Command_Team(int client, int iArgs)
{
    // ...
    KeyValues kv = new KeyValues("Teams");
    if (!kv.ImportFromFile(szPath)) // 从 bot_rosters.txt 读取
    {
        // ... 错误处理
    }
    // ...
}

bool IsProBot(const char[] szName, char[] szCrosshairCode, int iSize)
{
    // ...
    JSONObject jData = JSONObject.FromFile(szPath); // 从 bot_info.json 读取
    if(jData.HasKey(szName))
    {
        JSONObject jInfoObj = view_as(jData.Get(szName));
        jInfoObj.GetString("crosshair_code", szCrosshairCode, iSize);
        // ...
    }
    // ...
}

navmesh 是 Source 引擎游戏中 Bot 寻路和理解地图布局的核心组件。它定义了 Bot 可以在地图上行走、跳跃、蹲伏、躲藏的区域。

代码示例:获取 NavMesh 属性
g_pCurrArea[client] = NavMesh_GetNearestArea(g_fBotOrigin[client]); // 获取 Bot 当前所在区域
if(g_pCurrArea[client] != INVALID_NAV_AREA)
{
    if (g_pCurrArea[client].Attributes & NAV_MESH_WALK) // 检查区域是否有步行属性
        iButtons |= IN_SPEED; // 保持步行
    
    if (g_pCurrArea[client].Attributes & NAV_MESH_RUN) // 检查区域是否有奔跑属性
        iButtons &= ~IN_SPEED; // 取消步行(即奔跑)
}

4.8. 机器人模仿 (BotMimic)

BotMimic 是一个 SourceMod 扩展,允许记录和回放玩家的动作,以供 Bot 模仿。这在实现复杂、精确的动作(如预设投掷物)时非常有用。

代码示例:播放 BotMimic 录像
if(view_as(GetEntData(client, g_iBotLookAtSpotStateOffset)) == LOOK_AT_SPOT && fSpeed == 0.0 && (GetEntityFlags(client) & FL_ONGROUND))
    BotMimic_PlayRecordFromFile(client, g_szReplay[g_iDoingSmokeNum[client]]);

5. 哪些参数可以自己改变?

这个插件的一大优势就是其高度的可配置性。小白用户也能通过修改几个简单的文件来实现强大的自定义功能!

5.1. 爆头率修改:让 Bot 瞄准更精准

如果你想调整 Bot 的爆头率,使其更具挑战性或更符合你的需求,可以通过修改插件的源代码来实现。以下是你需要关注和修改的部分:

重要提示: 修改源代码需要重新编译插件。在进行任何修改之前,建议备份原始的 .sp 文件。

文件路径: addons/sourcemod/scripting/bot_stuff_manico_20250813.sp

修改位置: 找到函数 public void SelectBestTargetPos(int client, float fTargetPos[3])

在这个函数内部,你会找到一个 switch(iDefIndex) 结构,它根据 Bot 当前所持的武器类型来决定瞄准策略。我们需要修改其中的几行代码。

代码片段:爆头率控制核心
public void SelectBestTargetPos(int client, float fTargetPos[3])
{
    if(IsValidClient(g_iTarget[client]) && IsPlayerAlive(g_iTarget[client]))
    {
        int iBone = LookupBone(g_iTarget[client], "head_0");
        int iSpineBone = LookupBone(g_iTarget[client], "spine_3");
        if (iBone < 0 || iSpineBone < 0)
            return;
        
        // 这一行决定了 Bot 最终瞄准身体(true)还是头部(false)
        bool bShootSpine = false; 

        float fHead[3], fBody[3], fBad[3];
        GetBonePosition(g_iTarget[client], iBone, fHead, fBad);
        GetBonePosition(g_iTarget[client], iSpineBone, fBody, fBad);
        
        fHead[2] += 4.0; // 稍微抬高头部瞄准点
        
        if (BotIsVisible(client, fHead, false, -1))
        {
            if (BotIsVisible(client, fBody, false, -1))
            {
                if (!IsValidEntity(g_iActiveWeapon[client])) return;
                
                int iDefIndex = GetEntProp(g_iActiveWeapon[client], Prop_Send, "m_iItemDefinitionIndex");
                
                switch(iDefIndex)
                {
                    // 步枪、冲锋枪、霰弹枪、机枪等常见武器的定义索引
                    // 7: AK47, 8: AUG, 10: Famas, 13: GalilAR, 14: M4A4, 16: M4A1-S, 17: MAC-10, 19: P90
                    // 23: MP5SD, 24: UMP-45, 25: XM1014, 26: Bizon, 27: MAG-7, 28: MP9, 29: Nova
                    // 33: Negev, 34: M249, 35: Sawed-Off, 39: SG553, 60: Glock (默认Bot拿Glock也会走到这里)
                    case 7, 8, 10, 13, 14, 16, 17, 19, 23, 24, 25, 26, 27, 28, 29, 33, 34, 35, 39, 60:
                    {
                        float fTargetDistance = GetVectorDistance(g_fBotOrigin[client], fHead);
                        // ******** 这是核心修改点 (对于大部分武器) ********
                        // 原始代码: if (IsItMyChance(70.0) && fTargetDistance < 2000.0)
                        // 这意味着在 2000 单位距离内,Bot 有 70% 的机会瞄准身体(bShootSpine = true)。
                        // 换言之,默认爆头率是 30% (100% - 70%)。

                        // 要提高爆头率:
                        // 1. 降低 IsItMyChance() 中传入的百分比值。
                        //    例如,改为 IsItMyChance(50.0) -> 50% 爆头率
                        //    改为 IsItMyChance(20.0) -> 80% 爆头率
                        //    改为 IsItMyChance(0.0)  -> 100% 爆头率 (如果头部可见且在距离内)
                        
                        if (IsItMyChance(70.0) && fTargetDistance < 2000.0) // <-- 在这里修改数字 (默认 70.0)
                            bShootSpine = true;
                    }
                    // 狙击枪 (AWP: 9, SSG08: 38), 左轮 (11)
                    // 提醒:Deagle (1) 原始代码中未被明确包含在此处,建议将其添加到狙击枪的策略中
                    case 1, 9, 11, 38: // <-- 如果需要,在此处添加 '1' (Deagle 的 iDefIndex)
                    {
                        // ******** 这是狙击枪/沙鹰等武器的修改点 ********
                        // 原始代码: bShootSpine = true;
                        // 这意味着这些武器默认总是瞄准身体(0% 爆头率)。

                        // 如果想让这些武器也能爆头:
                        // 1. 设置为 false,强制 100% 爆头率 (如果头部可见)
                        //    bShootSpine = false; 
                        // 2. 使用 IsItMyChance() 设置爆头概率
                        //    bShootSpine = !IsItMyChance(X.0); // X 为不爆头的几率
                        //    例如:bShootSpine = !IsItMyChance(50.0); // 50% 爆头率

                        bShootSpine = true; // <-- 在这里修改
                    }
                }
            }
        }
        else
        {
            //Head wasn't visible, check other bones.
            for (int b = 0; b <= sizeof(g_szBoneNames) - 1; b++)
            {
                iBone = LookupBone(g_iTarget[client], g_szBoneNames[b]);
                if (iBone < 0)
                    return;
                
                GetBonePosition(g_iTarget[client], iBone, fHead, fBad);
                
                if (BotIsVisible(client, fHead, false, -1))
                    break;
                else
                    fHead[2] = 0.0;
            }
        }
        
        if(bShootSpine)
            fTargetPos = fBody;
        else
            fTargetPos = fHead;
    }
}

通过这种方式,你可以精确调整 Bot 的爆头率,使其更符合你的期望,无论是变得更强还是更弱。

5.2. configs/bot_rosters.txt (团队花名册)

这个文件允许你定义自定义的 Bot 战队,并指定他们的成员和团队 Logo。

文件路径与示例内容:addons/sourcemod/configs/bot_rosters.txt
"Teams"
{
    "Astralis"
    {
        "players"       "dupreeh,Xyp9x,device,gla1ve,Magisk"
        "logo"          "valve_astralis" // 团队Logo的代码,可以在CS:GO Wiki或游戏中找到
    }
    "NaVi"
    {
        "players"       "s1mple,ZywOo,NiKo,sh1ro,jL" // 这里可以列出 bot_info.json 中定义的职业选手名字
        "logo"          "valve_navi"
    }
    "MyCustomTeam" // 你自己的自定义团队
    {
        "players"       "Bot01,Bot02,Bot03,Bot04,Bot05" // 任意 Bot 名字,除非在 bot_info.json 中有定义,否则就是普通 Bot
        "logo"          "" // 如果不设置,可以留空
    }
}

使用方法: 在游戏中打开控制台,输入 team <TeamName> <t|ct>
例如:team NaVi t 会将 NaVi 战队的 Bot 加入 T 方。
team Astralis ct 会将 Astralis 战队的 Bot 加入 CT 方。

5.3. configs/bot_nades.txt (预设投掷物)

这个文件允许你为不同的地图定义 Bot 在特定位置投掷特定手雷的动作。

文件路径与示例内容:addons/sourcemod/configs/bot_nades.txt
"Nades"
{
    "de_dust2" // 地图名称
    {
        "SmokeMid" // 自定义名称
        {
            "position"          "-57.070797 2139.697498 -16.030310" // Bot 走到这个位置
            "lookat"            "-141.040186 2115.118945 90.729111" // Bot 瞄准这个点进行投掷
            "nadedefindex"      "43" // 投掷物 ID:43为烟雾弹 (smokegrenade)
            "replay"            "dust2_mid_smoke.rec" // BotMimic 录像文件名 (位于 /addons/sourcemod/data/botmimic/ 目录)
            "timestamp"         "10.0" // 每多少秒可以重复投掷一次(此功能在此插件中被 RoundEnd 重置)
            "team"              "T" // 哪个队伍的 Bot 投掷
        }
        "MolotovShort"
        {
            "position"          "142.123 200.456 0.0"
            "lookat"            "150.789 220.123 50.0"
            "nadedefindex"      "44" // 44为燃烧弹 (molotov) / 48为燃烧瓶 (incgrenade)
            "replay"            "dust2_short_molotov.rec"
            "timestamp"         "15.0"
            "team"              "T"
        }
    }
    "de_mirage"
    {
        "SmokeCTSpawn"
        {
            "position"          "-123.456 789.012 10.0"
            "lookat"            "-130.000 800.000 60.0"
            "nadedefindex"      "43"
            "replay"            "mirage_ct_smoke.rec"
            "timestamp"         "12.0"
            "team"              "CT"
        }
    }
}

重要提示: 要使用此功能,你服务器上必须安装 BotMimic 插件。
录制 .rec 文件需要一些技巧:作为人类玩家,在游戏中启用 BotMimic 录制,运行到指定 position,瞄准 lookat 点并完成投掷动作,然后停止录制,将文件命名为 replay 中指定的名称。

5.4. data/bot_info.json (职业选手信息)

这个 JSON 文件存储了插件中识别的“职业 Bot”的具体设置,主要是他们的准星代码。注意以下是伪代码,实际格式看文件。

文件路径与示例内容:addons/sourcemod/data/bot_info.json
{
    "s1mple": {
        "crosshair_code": "CSGO-s1mple-crosshair-code-here" // 实际的准星代码
    },
    "ZywOo": {
        "crosshair_code": "CSGO-ZywOo-crosshair-code-here"
    },
    "NiKo": {
        "crosshair_code": "CSGO-NiKo-crosshair-code-here"
    },
    "sh1ro": {
        "crosshair_code": "CSGO-sh1ro-crosshair-code-here"
    },
    "donk": {
        "crosshair_code": "CSGO-donk-crosshair-code-here"
    },
    "m0NESY": {
        "crosshair_code": "CSGO-m0NESY-crosshair-code-here"
    }
}

注意: s1mple, ZywOo, NiKo, sh1ro, jL, donk, m0NESY 这几个名字的 Bot 被插件硬编码了额外的“超能力”:他们的 g_fLookAngleMaxAccel 被设置为 20000.0g_fReactionTime 被设置为 0.0g_fAggression 被设置为 1.0。这意味着他们的瞄准速度极快,反应时间为零,并且极具攻击性。 其他在 bot_info.json 中定义但不在上述列表中的 Bot,其 ReactionTime, AggressionLookAngleMaxAccel 将会是随机且较高的数值,但不如硬编码的这些Bot那么极端。

5.5. 插件内置变量(修改源代码)

虽然不推荐小白直接修改源代码,但如果你想进行更深度的自定义,可以找到以下与 Bot 行为相关的布尔变量,并尝试修改它们的初始化值。

相关代码行:在 OnClientPostAdminCheck 函数中
public void OnClientPostAdminCheck(int client)
{
    // ...
    g_bUseUSP[client] = IsItMyChance(75.0); // CT Bot 有75%几率倾向使用 USP
    g_bUseM4A1S[client] = IsItMyChance(50.0); // CT Bot 有50%几率倾向使用 M4A1-S
    g_bUseCZ75[client] = IsItMyChance(20.0); // Bot 有20%几率倾向购买 CZ75
    // ...
}

5.6. 控制台变量 (Cvars)

插件会读取和影响一些 CS:GO 内置的控制台变量。

6. 安装与使用 (小白必看!)

按照以下步骤,即使是小白也能轻松安装和使用这个强大的 Bot 增强插件。

6.1. 前置条件

  1. SourceMod & MetaMod: 确保你的 CS:GO 服务器已经安装了最新版本的 SourceModMetaMod:Source。这是 SourceMod 插件运行的基础。
  2. 其他插件: 请参考Manico's Edition,确保安装所有依赖插件。

6.2. 插件安装

  1. 将提供的 bot_stuff_manico_20250813.sp 文件编译成 .smx 文件。如果你不熟悉编译,可以直接下载已经编译好的 .smx 文件(通常在插件发布页面会提供)。

    如何编译:.sp 文件放在 addons/sourcemod/scripting/ 文件夹中。在服务器控制台或本地客户端启动 CS:GO,并确保 SourceMod 正常加载。然后输入 sm_compile bot_stuff_manico_20250813.sp。如果成功,会在 addons/sourcemod/plugins/ 目录下生成 bot_stuff_manico_20250813.smx

  2. 将编译好的 bot_stuff_manico_20250813.smx 文件上传到你 CS:GO 服务器的 csgo/addons/sourcemod/plugins/ 目录下。

6.3. 配置文件夹设置

以下文件夹的存在,是让插件能够加载自定义数据。如果你正确安装了,他们应该已经存在。如果没有,请按照以下步骤创建和配置。

  1. csgo/addons/sourcemod/configs/ 目录下创建 bot_rosters.txt 文件(参照上文 5.2 章节)。
  2. csgo/addons/sourcemod/configs/ 目录下创建 bot_nades.txt 文件(参照上文 5.3 章节)。
  3. csgo/addons/sourcemod/data/ 目录下创建 bot_info.json 文件(参照上文 5.4 章节)。
  4. csgo/addons/sourcemod/gamedata/ 目录下创建 botstuff.games 文件。这个文件通常由插件作者提供;如果没有,插件将无法正常工作,因为它需要知道游戏内部函数的内存地址。你可能需要从插件的 GitHub 仓库或发布页面下载此文件。

    通常,.games 文件是针对特定游戏版本编译的。虽然游戏不再更新了,但一些插件是在老的游戏版本编译的,所以上古版本可能会失效或导致服务器崩溃。

  5. 如果你使用 bot_nades.txt 中的 "replay" 功能,确保在 csgo/addons/sourcemod/data/botmimic/ 目录下放置对应的 .rec 文件。你需要自己录制这些文件。

6.4. 使用 team 命令

安装并配置好插件后,就可以在服务器上愉快地玩耍了!

  1. 重启服务器或刷新插件: 上传文件后,重启你的 CS:GO 服务器,或者在服务器控制台输入 sm plugins refresh 来加载新插件。
  2. 添加 Bot: 在游戏中打开控制台(通常是 ` 键),输入 bot_kick all 清除现有 Bot。
  3. 使用自定义的 team 命令来加载你预设的 Bot 团队:
    • team <团队名称> <t|ct>
    • 例如:team NaVi t
    • 例如:team Astralis ct
    • 例如:team MyCustomTeam t
  4. 观察你的 Bot 们在游戏中表现出惊人的智能行为!

7. 常见问题与排查

8. 总结

通过这份详尽的指南,你现在应该对 bot_stuff_manico_20250813.sp 插件的功能、实现原理以及如何自定义它有了全面的了解。这个插件极大地提升了 CS:GO Bot 的智能水平,让它们表现得更像人类玩家,无论是经济管理、策略移动、还是精准射击和投掷,都能带来更具挑战性和趣味性的游戏体验。

尽情享受你的Bot吧!如果在自定义过程中有任何疑问,可以参考本文档或寻求 SourceMod 社区的帮助。