内容
# gmod-mcp
一个 [MCP](https://modelcontextprotocol.io) 服务器,允许 AI 代理**直接控制 Garry's Mod 游戏**。
一个小型 C++ DLL(`core.dll`)被注入到游戏中:
- **桥接 Lua 运行环境** — 运行 Lua,读取结构化的游戏状态(玩家,武器,瞄准,附近的实体),检查 VGUI 面板树;
- **捕获截图** — 通过 GMod 的 `render.Capture` 从每帧渲染过程中(无需创建 Direct3D 设备,因此注入不会破坏渲染器);
- **在引擎级别注入输入** — 移动,视角,射击,跳跃,VGUI 点击和输入 — 通过 `CreateMove`/`CUserCmd` 模型和 `gui`/`input` 库,因此**你的真实鼠标和键盘永远不会被触碰**;
- **运行控制台命令** 通过引擎控制台(`ClientCmd_Unrestricted`)— `map`,`connect`,`disconnect`,cvars,所有无限制;
- **捕获控制台输出** — 引擎 `Msg`/`Warning`/`Error` 和 Lua `print`。
> 已编译并验证针对 **Garry's Mod x86-64(64 位)分支**(`gmod.exe`,`bin/win64`)。参见 [分支和位数](#分支和位数)。
## 架构
```
Claude(AI 代理)
│ MCP stdio
▼
server/ (TypeScript MCP 服务器) ──shells out──► injector.exe (查找 gmod.exe,LoadLibrary-注入 core.dll)
│ 命名管道 \\.\pipe\gmod_mcp (长度前缀的 JSON)
▼
core.dll (注入,x64)
├─ ipc_server 管道服务器线程
├─ command_queue 移交给主线程
├─ pump 窗口子类 + C 函数,代理从 PostRender 调用;排空
│ 队列在主线程(无 D3D 设备 — 无崩溃)
├─ lua_bridge CreateInterface("LUASHARED003") → ILuaInterface(每帧重新解析
│ 以便其在地图更改时存活);注册 _mcp_native_pump
├─ engine_console IVEngineClient::ClientCmd_Unrestricted(地图/连接/cvars)
├─ console_log tier0 LoggingSystem 监听器(x64)/ spew 函数(旧版)
└─ bootstrap.lua 游戏内代理:输入,状态,VGUI,render.Capture 截图,
PostRender pump 钩子(热重载)
```
参见 [`docs/protocol.md`](docs/protocol.md) 获取线路协议。
## 先决条件
- Windows,**Garry's Mod** (x86-64 分支 — 参见下文)
- **Visual Studio 2022** (桌面 C++ / MSVC x64)+ Windows SDK
- **premake5** (`premake5.exe` 在 PATH 上)
- **Node.js ≥ 18**
第三方依赖项在 `core/third_party/` 下(`garrysmod_common` 和 `minhook` 作为子模块;`json.hpp` 和 `stb_image_write.h` 作为单个标头)。
克隆后:
```sh
git submodule update --init --recursive
```
## 构建
```powershell
# 原生(core.dll + injector.exe)-> build/bin/Release/
premake5 vs2022
# 打开"x64 Native Tools"提示符,或运行 vcvars64.bat,然后:
msbuild build/gmod-mcp.sln /p:Configuration=Release /p:Platform=x64 /m
# MCP 服务器
cd server
npm install
npm run build
```
输出位于 `build/bin/Release/`:`core.dll`,`injector.exe`,以及 `bootstrap.lua` 的副本(桥梁在运行时从 DLL 旁边加载它)。
## 运行
1. 启动 Garry's Mod(x86-64 分支)。
2. 将 MCP 服务器连接到您的客户端。示例(`claude_desktop_config.json` / Claude Code / Cursor):
```json
{
"mcpServers": {
"gmod": {
"command": "node",
"args": ["E:/path/to/gmod-mcp/server/dist/index.js"]
}
}
}
```
服务器自动发现 `injector.exe` 在 `build/bin/Release|Debug` 下;如果您移动了它,请使用 `GMOD_MCP_INJECTOR` 环境变量覆盖。
3. 请求代理调用 `gmod_status`,然后 `gmod_inject`。一旦注入并且您**在地图上**,所有工具都已启用。
## 工具
| 工具 | 功能 |
| ------------------------ | ----------------------------------------------------------------- |
| `gmod_status` | 游戏是否启动?DLL 是否注入?管道是否存活?Lua 领域? |
| `gmod_inject` | 将 `core.dll` 注入正在运行的游戏 |
| `gmod_reload_agent` | 热重载 `bootstrap.lua`(无需重启) |
| `gmod_lua_run` | 在客户端领域运行 Lua;返回打印输出 + 返回值 |
| `gmod_get_state` | 结构化玩家/世界快照 |
| `gmod_console_log` | 最近的控制台输出(引擎 + Lua `print`) |
| `gmod_console_command` | 通过引擎控制台运行**任何**命令(无限制):`map`,`connect`,`disconnect`,cvars |
| `gmod_screenshot` | 通过 render.Capture 截图(PNG/JPEG,可选区域 x/y/w/h) |
| `gmod_screenshot_panel`| 截图一个 VGUI 面板(按子字符串 / x,y / 聚焦)+ 填充 |
| `gmod_input` | 保持/清除按钮和模拟移动(-1..1) |
| `gmod_input_clear` | 释放所有合成输入 |
| `gmod_look` | 瞄准一个角度(平滑或瞬时;绝对/相对) |
| `gmod_press` | 点击一个按钮一次 |
| `gmod_dump_vgui` | 转储 VGUI 面板树(类/名称/矩形/文本) |
| `gmod_cursor` | 移动游戏内光标 / 点击 VGUI 面板 |
| `gmod_type` | 在 VGUI 文本输入中输入 |
## 开发工作流程
- **仅 Lua 更改**(`bootstrap.lua`):编辑,将其复制到 `core.dll` 旁边,然后调用 `gmod_reload_agent`(或仅重新加载 — 代理在菜单→地图切换时重新读取)。无需重建,无需重启。
- **原生更改**(`core.dll`):DLL 文件在加载时被锁定,无法在 Windows 加载器锁下进行干净的热卸载。**重启游戏**,然后重建并再次调用 `gmod_inject`。(`injector.exe eject` 存在但无法完全卸载正在运行的 DLL。)
- 包含 `server/probe.mjs` / `server/verify_ingame.mjs` 以进行快速检查。
## 分支和位数
注入器针对 `gmod.exe`,并更喜欢已加载 `lua_shared.dll` 的进程 — x86-64 分支运行 Chromium(CEF)辅助子进程,这些子进程共享 `gmod.exe` 名称,只有真正的游戏进程托管引擎。`core.dll` 和 `injector.exe` 是 **x64**;它们不会注入 32 位游戏。32 位分支需要 x86 构建(代码与位数无关;仅项目平台不同)— 当前未生成。
## 故障排除
**仅在游戏到达主菜单时注入**(`gmod_status` → `running:true`)。注入器拒绝针对仍在加载的进程 — 注入早期/CEF 子进程如果尚未加载 `lua_shared.dll` 可能会导致启动崩溃。
**`gmod_screenshot` 返回错误 / 黑色帧。** 截图使用 `render.Capture`,仅在渲染过程中有效,如果 **退出菜单打开** 或在 **主菜单**(无客户端渲染过程)时返回空值。关闭菜单,或使用 `gmod_dump_vgui` 检查菜单 UI。
**工具在地图加载后立即返回 "lua 接口未就绪"。** 客户端 Lua 状态在 `map` 上重新创建;桥梁重新解析它,并在帧或两个帧内自动重新加载代理 — 重试,或调用 `gmod_reload_agent`。
> 设计注意:泵永远不会创建 Direct3D 设备。它通过窗口子类和代理在 PostRender 中调用的 C 函数驱动主线程,因此注入不会破坏渲染器。
## 安全性和范围
**适用于单人游戏和您自己的服务器**。将注入多人游戏服务器与反作弊软件可能会导致封禁 — 那是您自己的责任。启动器警告但不阻止。保持的输入会自动过期(一个掉落的代理不会让您永远卡在墙上),并且 `gmod_input_clear` 会释放所有内容。
## 许可证
在 [MIT 许可证](LICENSE) 下许可。
**无保证,无责任。** 本软件按“原样”提供,不附带任何形式的保证,明确或暗示。我不提供 **任何保证**,也不承担 **任何责任或义务**,因使用本软件而产生的任何损害,包括但不限于游戏封禁、崩溃、数据丢失或其他损害。您完全自行承担风险使用本软件。