主题
SCE 触发器编辑器 MCP Skill
概述
此 Skill 提供通过 MCP 协议操作 SCE 编辑器触发器系统的能力。触发器是游戏逻辑的可视化编程系统,支持事件驱动的脚本编写;与普通 LibModule(触发器模块) 并列还有 Validator 校验器模块,可用 MCP 创建其中的静态校验函数(见 trigger_create_validator)。
连接 MCP(优先 pwsh)
先按开发入口规则选择宿主:优先复用用户已打开目标项目的可视化编辑器,除非用户主动要求隔离;没有已打开的 GUI 或用户要求隔离时,AI 编辑触发器并构建优先 Headless,需要图形界面时使用完整编辑器。Headless 通过自己的 HTTP/WebSocket MCP 连接并检查 capability、项目状态与 tools/list;下列脚本是 Trigger/Data 兼容入口。GUI、Headless 和独立触发器宿主不要同时写同一项目。
兼容脚本入口:选用独立 Trigger/Data 宿主时,用此脚本处理 GET /health → 若端口无响应则按工程 docs/.editor-root 定位 TriggerMcpHost.exe 并启动(工程根由 -ProjectRoot 传入,或脚本位于 <工程根>/ai/tools/ 时自动推断为 ai 的父目录;旧版 <工程根>/.cursor/tools/ 仍兼容)→ 轮询至 mapReady: true(独立 Host)→ POST 一次 JSON-RPC tools/call。若端口已有健康 MCP,不会再启第二个实例,直接执行该次调用。每次脚本进程只对应一个工具;需要连续多个工具时,应多次运行脚本(或多次用 MCP),且写操作之间仍须串行、不可并行。
项目根目录:含 project.sce、docs/.editor-root 的 SCE 工程根。脚本路径为 <工程根>/ai/tools/Invoke-SceMcp.ps1(推荐)时不必传 -ProjectRoot,也不必通过 docs/.sdk-version 查找脚本;示例 JSON 同目录:ai/tools/trigger-mcp-call.example.json(与 trigger-mcp-workflow.mdc 一致)。WasiCoreSDK 内模板路径为 docs/ai/tools/,复制到地图工程根 ai/tools/ 后使用。
| 参数 | 说明 |
|---|---|
-ProjectRoot | 可选。覆盖/指定工程根。未传且脚本在 ai/tools/(或兼容的 .cursor/tools/)下时自动推断;脚本在其它路径(如单独复制的 tools/)且需自动起 Host 时再传 |
-RequestJsonPath | 请求 JSON:可选 baseUrl;必须含 tool 与可选 arguments(格式见 ai/tools/trigger-mcp-call.example.json)。优先:AI 先将内容写入临时文件再传此路径,运行结束后删除临时文件 |
-Tool / -ArgumentsJson | 不用 JSON 文件时的单次快捷方式 |
-HealthOnly | 只探测/起 Host 并等到就绪,输出 /health 快照,不调用工具(适合纯预热) |
-Port | 未在 JSON 中指定 baseUrl 时的 MCP 端口,默认 8765 |
-McpMode | 启动宿主时的 --mcp-mode,默认 http |
-HostExtraArgs | 追加给宿主进程的参数(如 --log-file=...) |
推荐流程(AI / 自动化):按 ai/tools/trigger-mcp-call.example.json 的结构把本次调用的 baseUrl(可选)、tool、arguments 写入临时 JSON,用 -RequestJsonPath 调用 ai/tools/Invoke-SceMcp.ps1,在 finally 里 Remove-Item 删除临时文件。
powershell
$MapRoot = "D:\YourSceMap"
$McpScript = Join-Path $MapRoot 'ai\tools\Invoke-SceMcp.ps1'
$TempRequest = Join-Path $env:TEMP ("sce-trigger-mcp-" + [Guid]::NewGuid().ToString("n") + ".json")
$PowerShellExe = Get-Command pwsh -ErrorAction SilentlyContinue | Select-Object -First 1 -ExpandProperty Source
if ([string]::IsNullOrWhiteSpace($PowerShellExe)) {
$PowerShellExe = Get-Command powershell -ErrorAction Stop | Select-Object -First 1 -ExpandProperty Source
}
@'
{ "baseUrl": "http://127.0.0.1:8765/", "tool": "trigger_list_files", "arguments": { "env": "Common" } }
'@ | Set-Content -LiteralPath $TempRequest -Encoding utf8
try {
& $PowerShellExe -NoLogo -NoProfile -ExecutionPolicy Bypass -File $McpScript -RequestJsonPath $TempRequest
} finally {
if (Test-Path -LiteralPath $TempRequest) { Remove-Item -LiteralPath $TempRequest -Force }
}另可改用同目录示例做只读试跑:-RequestJsonPath (Join-Path (Split-Path $McpScript -Parent) 'trigger-mcp-call.example.json')(勿删除仓库内示例文件)。若脚本仍从 docs/ai/tools/(SDK 模板)运行,须传 -ProjectRoot 指向 SCE 地图根。
脚本成功时向 stdout 输出 JSON,字段 mcpBaseUrl、tool、result(来自 MCP 单次 tools/call);RPC 错误会终止并抛错。
在 Cursor 里:若会话已有 trigger_* 且能调通 → 直接用 MCP 工具。若无工具或连接失败 → 先诊断当前宿主连接;只有已选择独立 Trigger/Data 兼容路线且不会与现有项目写入冲突时,才执行上述脚本;要让 Cursor 长期连同一端口,可在工作区根配置 .cursor/mcp.json(url 与 Host 的 --mcp-port / --mcp-mode 一致)并提示 重载 MCP。禁止只交代用户「自己开宿主」而不探测/启动(策略禁 shell 时除外)。
前提
- 端点:完整 SCE 编辑器 MCP、支持目标项目的 Headless MCP,或仅用于触发器/数据兼容操作的 TriggerMcpHost(exe 目录见工程
docs/.editor-root;独立触发器宿主通过ai/tools/Invoke-SceMcp.ps1启动,不要手写TriggerMcpHost.exe命令行)。 - 独立 Host:
trigger_*前须/health里mapReady: true;mapLoadPhase: loading时不要再启第二个实例。部分工具依赖编辑器 UI 时在独立 Host 上可能受限。
当前已注册的 trigger_* 工具(与 MCPServer / TriggerEditorTools.Register 对齐)
以下名称以外没有其它 trigger_* 工具。
| 类别 | 工具名 |
|---|---|
| 列表 / 读取 | trigger_list_files、trigger_get_file、trigger_list_validator_files、trigger_get_validator_file |
| 搜索 / 引用诊断 | trigger_search、trigger_inspect_references |
| 创建 | trigger_create_class、trigger_create_trigger、trigger_create_function、trigger_create_validator、trigger_create_variable、trigger_create_preset、trigger_create_custom_event、trigger_create_folder |
| 重命名 / 删除 / 启用 / 仅改函数体 | trigger_rename、trigger_delete、trigger_set_enabled、trigger_replace_function_body |
| 保存 | trigger_save |
| 只读状态 / API | trigger_get_editor_state、trigger_get_api_schema |
| 校验 | trigger_validate_project |
代码生成:已无独立的 trigger_generate_code 工具。trigger_create_*、trigger_delete、trigger_rename、trigger_set_enabled、trigger_replace_function_body 等写操作在成功返回前会由 MCP 自动将当前模型生成到 src/TriggerGenerated/(与编辑器内「生成代码」一致,含 Validator 子输出)。trigger_save 仍负责把触发器树等持久化到地图工程;与生成是不同步骤。
触发器系统概念
层次结构
生成代码位置(TriggerGenerated):地图库下 src/TriggerGenerated/ 为生成输出目录。按环境生成 common.cs / client.cs / server.cs;Validator 对应 src/TriggerGenerated/Validator/ 下同名的环境文件。上述文件均在 namespace GameEntry 中。
生成代码里的 // path: 注释:若某段生成声明(如 Scope 内静态字段、部分 static 成员等)的紧上方有单行注释 // path: 文件名/文件夹/…/节点名,该字符串即编辑器资源树中对应节点的路径(与 MCP 的 nodePath / parentPath 一致,/ 分隔)。便于在 TriggerGenerated 里反查该生成片段属于哪个模块文件下的哪个节点。
普通 LibModule(触发器模块):编辑树节点类型含 Trigger、Function、Variable、Class、Preset(预设/枚举)、CustomEvent(自定义事件类) 等;触发器本体为 Trigger。
Function/Variable:生成到partial class Scope,即全局静态函数与全局静态字段。Trigger:生成的_Execute、ITrigger与初始化器等写入同一TriggerGenerated环境文件中的partial class Scope(与示例TriggerGenerated/common.cs结构一致)。Class:生成的类型在GameEntry命名空间下直接声明,不嵌套在Scope内。Preset:对应 C#enum,生成在GameEntry下(与Class同类顶层声明,非Scope内)。可用 MCPtrigger_create_preset从枚举源码创建。CustomEvent:须为class 名(主构造参数) : Events.ITriggerEvent<自身>形式,主构造进入模型EventCreator。可用 MCPtrigger_create_custom_event从符合约定的源码创建。
LibModule (文件)
└── Folder (文件夹,可嵌套)
├── Trigger (触发器)
│ ├── Scenes (场景列表)
│ ├── Events (事件列表)
│ ├── Conditions (条件列表)
│ ├── Variables (局部变量)
│ └── Statements (动作语句)
├── Function (全局函数 → partial class Scope 中静态方法)
├── Variable (全局变量 → partial class Scope 中静态字段)
├── Class / Preset / CustomEvent(GameEntry 顶层类型,非 Scope 内)
└── ...Validator 校验器:根同样为 LibModule(独立校验器模块文件),但树内仅允许 Folder 与 Function(无 Trigger、Variable 等)。生成代码在 TriggerGenerated/Validator/ 对应环境文件中,namespace GameEntry 下的 public partial class Validator 内为静态校验方法(见示例 TriggerGenerated/Validator/common.cs)。
LibModule (文件,Validator 模块)
├── Folder (文件夹,可嵌套)
│ ├── Folder (子文件夹,可继续嵌套)
│ └── Function (校验函数 → partial class Validator 中静态方法)
└── Function (根级校验函数,同上)与上述 普通 LibModule(触发器模块) 并列,每个环境有独立的 Validator 模块(上表树)。trigger_list_files 只列出触发器模块侧 LibModule;Validator 树用 trigger_list_validator_files / trigger_get_validator_file 浏览;创建校验函数用 trigger_create_validator。对 Validator 内节点做 trigger_rename / trigger_delete / trigger_set_enabled / trigger_replace_function_body 时须传 scope: "validator"(路径规则与普通库相同:校验器文件名/文件夹/函数名;trigger_replace_function_body 另见 parentPath + functionName 说明)。trigger_search 的 scope 为 trigger(默认)、validator、all;返回项的 tree 为 "trigger" 或 "validator"(与 scope 含义对应,不是字符串 library)。
环境 (Env)
Common: 通用环境(服务端和客户端共享)Client: 客户端专用Server: 服务端专用
多行条件与内联逻辑
更新编辑器后,图形化条件列表可添加“与(多行)”“或(多行)”“非(多行)”,展开为可增删、嵌套的子条件行。它们仅用于 Trigger.Conditions、If.Conditions、While.Conditions 或另一多行组的条件列表,不能填入函数参数、表达式槽位或动作列表。原有内联逻辑表达式继续用于这些表达式位置。
- “与”要求全部子条件成立;“或”要求任意子条件成立;“非”表示
!(A && B && C),对全部子条件的合并结果取反。空组的结果分别为true、false、false;禁用的子条件不参与判断。 - 现有
trigger_create_*/trigger_replace_function_body接收 C# 片段。用A && B && C、A || B || C或!(A && B && C)表达相应逻辑;解析仍产生原有内联逻辑节点,不会自动转换为图形化多行组。 - 当前 MCP 没有直接创建或转换多行组的工具。用户要求逐行的树形布局时,应说明需要在触发编辑器条件选择面板添加对应多行组;不要直接改写
editor/trigger内部 JSON,也不要手改生成的 C# 来改变编辑树。
用 Class 定义图形化数据编辑器的数编类型
数据编辑器只能创建已有 schema 的表和条目;项目要新增字段结构时,图形化路线应先在触发编辑器定义 Class。完整概念与纯代码路线的边界见 GameData 数据驱动系统,条目操作见 数据编辑器 Skill。
面向编辑器 UI 的标准流程:
> 本节的“保存 → 生成代码文件”指用户在完整触发编辑器 UI 中的两个菜单动作。trigger_* MCP 写操作会自动刷新生成代码,随后仍用 trigger_save 持久化模型;不要把两种调用顺序混用。
- 在文件树选择目标环境;双端共享类型默认使用 “共用(Common)”。
- 通过 “类定义” 新建并选中普通 Class,在右侧 “属性设置” 中维护字段。
- 新建根分类时勾选 “设置为数编分类”;新建已有分类的子类型时勾选 “设置为数编类型”。
- “设置为数编类型”会要求依次选择 “节点分类” 和 “节点父类”。前者对应根分类
T,后者对应直接父类V;两者都选好后才能确定。 - 先执行 “保存”,把触发定义持久化到
editor/trigger/**;再执行 “生成代码文件”,刷新src/TriggerGenerated/{common|client|server}.cs。这是两个不同动作。 - 核对生成的
partial class带有GameDataCategoryAttribute或GameDataNodeTypeAttribute<T,V>,再编译项目并回到数据编辑器创建条目。不要手改TriggerGenerated。
设置前不要给 Class 配置其它父类,也不要自己添加名为 Link 的成员;同一个 Class 不要同时设置为数编分类和数编类型。
当前 trigger_* MCP 工具集中没有“切换现有 Class 的数编类型/分类开关”这一独立语义化工具。只有 MCP、没有属性面板自动化能力时,不要直接改 editor/trigger 内部 JSON;应明确让用户在触发编辑器完成上述开关,再继续后续生成与数据条目操作。
路径格式
路径使用 / 分隔,格式为: 文件名/文件夹/节点名
创建类工具中的 parentPath 均可省略。省略时:
trigger_create_function、trigger_create_class、trigger_create_trigger、trigger_create_variable、trigger_create_preset、trigger_create_custom_event** 等**(普通 LibModule / 触发器模块):节点落在当前地图库在对应env下的普通模块根目录(与只传env的trigger_create_function一致)。trigger_create_validator:节点落在该env下的 Validator 模块根目录(不是普通触发器模块根;若该环境无 Validator 模块则工具失败)。
trigger_create_folder 省略 parentPath 时可另传可选 env,不传则按 Common。传了 parentPath 时,trigger_create_validator 的路径须落在 Validator 文件树内(可用 trigger_list_validator_files 确认首段文件名)。
parentPath 的合法根(与 trigger_create_folder 的配合):trigger_create_function / trigger_create_class / trigger_create_trigger / trigger_create_variable / trigger_create_preset / trigger_create_custom_event 等在传入非空 parentPath 时,服务端按「首段 = 当前 env 下资源列表里的 LibModule 文件名」解析(与 trigger_list_files 返回的每个条目的 name / path 一致,例如 GameEntry、MainTriggers);首段必须是已存在的触发器模块文件节点,再向下匹配文件夹。因此 parentPath 的根绝不是「裸文件夹名」——不能把「仅在某个 env 下、省略 parentPath 建出来的库根文件夹」当成与 LibModule 文件并列的根去拼路径。仅传 env、不传 parentPath 的 trigger_create_folder 会把文件夹挂到实现上的环境模块根内容区,该位置不在上述「首段 = LibModule 文件名」的解析链里;接着若把 parentPath 写成该文件夹名单独一段(如 CodexMcpTest_xxx),常见返回为 Cannot add to path: ... in env Common. Must be a file or folder.(与 TriggerEditorTools 中解析逻辑一致)。稳定做法:先 parentPath = 已有 LibModule 文件名(如 GameEntry),再在其下建文件夹,后续一律使用 GameEntry/子文件夹/...。trigger_create_folder 成功响应中的 path 标明服务端为本次文件夹计算的节点路径;下一工具调用的 parentPath 必须以 trigger_list_files 中的文件名为首段——若返回的 path 不含该前缀,不要把返回路径当作 trigger_create_* 可用的根;应以列表中的文件名为根重写路径,或自始即用 parentPath: "GameEntry"(或你工程里实际的文件名)建夹。文件夹仍是编辑器资源树里的管理/分组节点,与 namespace GameEntry 等生成代码布局无逐项对应(参见下文 trigger_create_folder 说明)。
Validator 与 scope:凡按 nodePath 在 Validator 模块内定位节点的写操作(trigger_rename、trigger_delete、trigger_set_enabled),必须 scope: "validator";默认 trigger 仅在普通触发器模块树内解析。trigger_replace_function_body 使用 parentPath 定位父容器,在 Validator 内替换校验函数体时同样须 scope: "validator"(见该工具说明)。
示例:
MainTriggers- 文件MainTriggers/Combat- 文件夹MainTriggers/Combat/OnPlayerAttack- 触发器
代码生成与「等价修改」(MCP 行为)
trigger_create_* / trigger_rename / trigger_delete / trigger_set_enabled / trigger_replace_function_body 等写入类工具在业务成功返回前会由 MCP 自动执行与编辑器「生成代码」等价的流程,将 src/TriggerGenerated/(及 Validator 子目录等)刷新到与当前内存模型一致;成功响应里仍不含 codeGeneration 诊断字段(与旧版显式工具不同)。trigger_save 仍须单独调用,用于把触发器资源写入地图工程(与生成 C# 输出是不同步骤)。
不要直接写触发器模型 JSON:地图工程下的 editor/trigger/<env>/**/*.json 是触发编辑器模型的内部序列化,不是 AI 输出目标,也不是稳定的业务 DSL。创建或修改触发器逻辑时应传 C# 片段给 trigger_create_* / trigger_replace_function_body,再用 trigger_save 和 trigger_validate_project 收尾。
仅函数体(不改名、不改签名):对已有的静态函数或 Class 成员函数,可用 trigger_replace_function_body:在 code 中声明名为 TempFunctionBody 的方法,签名须与目标函数完全一致(static/async、返回类型、参数列表等),工具只替换该节点的函数体;实现上等价于解析片段后写入模型再生成。详见下文 trigger_replace_function_body。
其它节点或整体替换:不能把已有触发器 / 整类 / 变量等的源码当作任意「打补丁」直接替换。典型等价流程仍是:trigger_delete 删除目标节点(必要时先 trigger_get_file 等把树形概要抄出备用,或从 src/TriggerGenerated/ 对照现有生成代码)→ 在外部或对话中改好 code → 用对应的 trigger_create_* 以新 code 重建节点(上述步骤会自动刷新生成目录)→ trigger_save 持久化 → 在 src/TriggerGenerated/ 中核对生成效果是否达到预期。
常见工作流
1. 创建新触发器
1. trigger_list_files - 查看现有文件结构
2. trigger_create_folder - 如需要,创建组织文件夹
3. trigger_create_trigger - 传入 env + 符合约定的 C#(见下文该工具说明)创建触发器(成功即已自动刷新生成目录)
4. trigger_save - 保存触发器数据到地图工程
5. (可选)在 IDE 中打开 src/TriggerGenerated/ 核对生成效果2. 查找并修改触发器
1. trigger_search - 搜索目标触发器
2. trigger_get_file(可选)— 查看文件下节点树概要
3. 轻量修改:**`trigger_rename`**(仅改节点名)、**`trigger_set_enabled`** 等(成功即已自动刷新生成目录)
4. 仅改「已有静态函数 / 类成员函数」的函数体:**`trigger_replace_function_body`**(`code` 内方法名须为 TempFunctionBody,签名与目标一致;成功即已自动刷新生成目录)
5. 改触发器逻辑、整段新建类、或其它无法用语义化节点编辑覆盖的改动:见上文「代码生成与等价修改」(**`trigger_delete`** + **`trigger_create_*`**)
6. trigger_save - 保存更改3. 清理未使用的触发器
1. trigger_search - 搜索候选触发器
2. trigger_inspect_references - 只读确认正向、反向与失效引用
3. trigger_set_enabled - 先禁用测试(成功即已自动刷新生成目录)
4. trigger_delete - 确认后严格删除;自动化重复调用时才显式传 ignoreIfMissing=true
5. 读取 outcome / changed / safeToRetry;unknown 时停止重试并重新检查现场
6. trigger_save - 保存更改3.1 删除 game_entry 默认 GameSystemUI 控件
game_entry 是最小可运行模板,但并非完全没有 UI。当前模板的客户端触发器 游戏开始时初始化 默认调用:
GameSystemUI.Utility.CreateAndEnableMoveControl(...)(创建并启用移动控件)GameSystemUI.Utility.CreateAndEnableAbilityJoyStick(...)(创建并启用技能摇杆)
用户要求去掉模板默认 UI 时:
1. trigger_search / trigger_get_file - 在 Client 环境定位 `GameEntry/游戏开始时初始化`,并查看 `src/TriggerGenerated/client.cs` 确认其当前内容
2. 如果该触发器仍只有上述两条动作:trigger_delete 删除 `GameEntry/游戏开始时初始化`
3. 如果用户已加入其它初始化逻辑:保留其它逻辑,按“代码生成与等价修改”流程删除并重建该触发器,只移除上述两条调用
4. trigger_save - 保存更改
5. trigger_validate_project - 校验项目,并核对 src/TriggerGenerated/client.cs 不再包含这两条调用不要因为模板旧版本或用户口头称呼不同而把它们误写成背包控件;以当前触发器中的方法调用为准。也不要直接修改 editor/trigger/client/游戏开始时初始化.json 或生成的 src/TriggerGenerated/client.cs。
4. 创建校验函数(Validator)
1. trigger_list_validator_files(可选 env)— 确认目标 env 下 Validator 模块与文件名
2. trigger_get_validator_file(可选)— 查看某 Validator 文件下已有文件夹/函数
3. trigger_create_validator — 传入 env、静态函数 code;parentPath 可省略(落到 Validator 根)或指向 Validator 文件树内路径(成功即已自动刷新生成目录)
4. trigger_save — 保存地图数据
5. 若需重命名/删除/禁用 Validator 内函数,或**仅替换校验函数体**:**`trigger_rename`** / **`trigger_delete`** / **`trigger_set_enabled`** / **`trigger_replace_function_body`** 须带 **`scope: "validator"`**;每次写操作成功即自动刷新生成目录,最后仍须 **`trigger_save`** 持久化5. 创建 Preset(枚举预设)或 CustomEvent(自定义事件)
1. trigger_list_files / trigger_get_file(可选)— 确认目标文件与文件夹
2. trigger_create_preset 或 trigger_create_custom_event — 传 env + code(parentPath 可省略);须符合 SKILL 中该工具的形态约定(成功即已自动刷新生成目录)
3. trigger_save — 保存地图数据注意事项
- 保存: 修改后需要调用
trigger_save将触发器数据写入地图工程 - 代码生成: 各写操作(创建、删除、重命名、启用/禁用、替换函数体等)成功返回前 MCP 会自动刷新
src/TriggerGenerated/;无需再调已移除的trigger_generate_code。trigger_delete若在模型改变后生成失败或产生诊断,会返回outcome: "unknown"、safeToRetry: false;此时不要自动重试 - 环境分离: 注意选择正确的环境 (Common/Client/Server)
- 路径准确性: 确保路径准确,区分大小写
- 依赖库: 如果修改了依赖库,需要设置
saveDependLibs: true - MCP 传入的 C#(创建函数/校验函数/变量/类/触发器/预设枚举/自定义事件等,以及
trigger_replace_function_body的code): 这是导入触发器模型的 C# 片段,必须符合各写入工具的声明形态、包装位置、节点约定与可映射语法范围;详见下方 「触发器支持的 C# 语法范围」 与 「传入代码的形态约束」。创建类工具在成功返回前会自动写src/TriggerGenerated/;必须对照生成文件与传入code做人工校验,并在适当时机trigger_save。 - 串行调用: 创建及会修改触发器状态的其它操作(重命名、删除、启用/禁用、替换函数体、保存等)不要并行,须等上一调用返回后再发起下一调用;详见下方 「并发与调用顺序」。
错误处理
JSON-RPC 与 tools/call 结果(两层别混淆)
- JSON-RPC 层:
tools/call正常执行完毕时,RPC 仍多为result对象(不是 JSON-RPC 顶层的error)。只有缺工具名、工具未注册、传输异常等才会走 JSON-RPCerror。 - MCP
tools/call的result体:形如{ "content": [...], "isError"?: boolean }(见MCPToolCallResult)。自动化必须先读isError:isError === true:工具侧判定为失败;再把content[0].text当作 JSON 字符串 解析(见下节「业务失败体」)。isError为false或省略:工具正常返回;content[0].text一般为 JSON 字符串(如{ "success": true, ... }或列表等),按成功路径解析即可。
业务成功体(isError 为假)
content[0].text 解析后常见:
json
{ "success": true, "message": "...", ... }(部分只读工具可能是 JSON 数组,无 success 字段,以具体工具为准。)
业务失败体(isError 为真,trigger_* 与注册表未找到工具)
自 TriggerEditorTools / ToolRegistry / MCPServer 工具异常兜底 起,content[0].text 为 JSON 字符串(UTF-8 文本),结构为:
json
{
"success": false,
"message": "Cannot add to path: ...",
"errorCode": "cannot_add_to_path",
"details": { "parentPath": "...", "env": "Common" }
}message:人类可读说明(与旧版纯文本文案一致或为其超集)。errorCode:稳定机器可读码(可选;逐步覆盖)。常见:cannot_add_to_path(父路径无法解析)、folder_name_already_used、cannot_add_to_parent(如库根拒绝)、tool_not_found、tool_handler_exception。details:附加字段(可选),如parentPath、env、name、tree(Validator)等。
其它 MCP 工具集(如 data_*)若仍返回纯文本 content[0].text,以该工具实现为准;trigger_* 已统一为上述 JSON 失败体。
trigger_delete 写入结果契约
trigger_delete 的成功和失败体都会提供以下字段,自动化不得只看 success:
requestId:本次请求标识;outcome:not_started、committed或unknown;changed:内存模型是否已经改变;safeToRetry:是否允许调用方自动重试;persistence:unchanged或dirty;- 失败时还会提供
errorCode与可选details。
outcome: "unknown" 与 safeToRetry: false 表示节点可能已经删除,但代码生成结果无法确认。停止自动重试,重新调用只读查询、trigger_inspect_references、trigger_get_editor_state 或项目校验确认现场。ignoreIfMissing: true 也不会掩盖错误父路径、非法环境或跨环境歧义。
常见错误:
- MCP 未连接 / 拒绝 / 超时 → 执行
ai/tools/Invoke-SceMcp.ps1(见文首示例,无需docs/.sdk-version);需要 Cursor 长期连接时在工作区根配置mcp.json(与 Host 端口一致)并提示重载。 - 「地图仍在加载」 →
GET /health等到mapReady: true(loading时不要启第二个 Host)。 Trigger editor not available- 编辑器未打开触发器模块Node not found: xxx- 路径不存在Cannot add to path: xxx in env ... Must be a file or folder.— 普通库下parentPath首段不是该env的 LibModule 文件名(须与trigger_list_files一致),或路径无法解析到文件/文件夹;常见于把「仅env、无parentPath的trigger_create_folder」得到的单层文件夹名当作parentPath根。处理见上文 「parentPath的合法根」 与trigger_create_folder。Validator 侧文案为... Validator tree。- 当前地图在指定环境下没有 Validator 模块 - 无法使用
trigger_create_validator(详见工具返回文案)
MCP 工具参考
调用工具之前
trigger_* 仅在端点就绪且地图已加载时有意义;独立 Host 以 /health 的 mapReady 为准。连不上时优先文首 PowerShell 脚本;loading 时轮询 /health,勿重复启 Host。
并发与调用顺序(会修改触发器时)
所有创建类、创建触发器、创建 Preset/CustomEvent、创建文件夹、重命名、删除、启用/禁用、替换函数体(trigger_replace_function_body)(即会改动触发器编辑器内节点与数据结构的 MCP 调用)不得并行:必须等上一个调用完全结束(收到返回)后,再发起下一个。同一时刻只应有一个此类工具在执行。
同理,会修改触发器状态的其它工具(如 重命名、删除、启用/禁用、替换函数体、保存 等)与创建类操作混用时,也应串行调用,避免多路并发导致状态不一致。
只读查询(如 trigger_list_files、trigger_list_validator_files、trigger_get_file、trigger_search 等)在实现允许的前提下可与上述串行要求分开考虑;但若与写操作穿插,仍建议先完成写操作再查询,或严格按「一写一读」顺序,由调用方自行保证。
查询操作
trigger_list_files
列出所有触发器文件。
参数:
env(可选): 环境过滤 - "Common", "Client", "Server"
示例调用:
json
{ "env": "Common" }返回:
json
[
{ "name": "MainTriggers", "path": "MainTriggers", "env": "Common", "nodeCount": 15 },
{ "name": "ClientUI", "path": "ClientUI", "env": "Client", "nodeCount": 8 }
]trigger_get_file
获取文件的详细内容。
参数:
filePath(必需): 文件名
示例调用:
json
{ "filePath": "MainTriggers" }trigger_list_validator_files
列出当前地图在指定环境下的 Validator 校验器模块文件(与普通 trigger_list_files 对称,不包含触发器模块侧 LibModule)。
参数:
env(可选): 环境过滤 - "Common", "Client", "Server";省略则返回三个环境的 Validator 文件
返回: 与 trigger_list_files 相同结构(name、path、env、nodeCount)。
trigger_get_validator_file
获取 Validator 侧某一文件的树形概要(与 trigger_get_file 对称,仅在 GetValidatorFileList 中按文件名查找)。
参数:
filePath(必需): Validator 模块中的文件名(路径首段,与trigger_create_validator的parentPath首段一致)
返回: 与 trigger_get_file 类似;另含 "tree": "validator" 便于区分。
trigger_search
搜索节点。
参数:
query(必需): 搜索关键词nodeType(可选): 与资源树节点 CLR 类型名一致;MCP Schema 枚举为Trigger、Function、Variable、Class、CustomEvent、All(未列入枚举的节点类型如Preset时,可用All再在结果里按type筛选,或以宿主实际校验为准)env(可选): 环境过滤scope(可选):trigger(默认,仅普通触发器模块树)、validator(仅 Validator 模块树)、all(两者;结果总数仍受服务端上限约束,通常最多约 50 条)。勿使用已废弃的library字符串。
返回: 每项除 name、type、path、env 外,含 tree: "trigger" 或 "validator"(scope 为 all 时用于区分)。
示例调用:
json
{ "query": "Player", "nodeType": "Trigger" }json
{ "query": "IsValid", "nodeType": "Function", "scope": "validator", "env": "Common" }trigger_inspect_references
只读检查指定节点或声明的正向、反向与失效引用。该工具不会修改编辑器 dirty 状态或项目文件,适合在删除、重建或排查断裂引用前使用。
定位参数(二选一):
nodePath: 资源树路径,例如MainTriggers/Combat/Target;nodeId: Declaration 稳定 ID,仅适用于声明节点。
其它参数:
env(可选):Common/Client/Server;路径或 ID 跨环境不明确时必须显式指定;scope(可选):trigger(默认)或validator;maxResults(可选): 正向和反向引用各自的返回上限,默认 200。
返回要点:
outgoingReferences/incomingReferences:正向与反向引用;missingReferenceCount与每项的status/reason:区分目标不存在、当前环境不可见、目标已移除或未解析等基础原因;valid:当前扫描范围内是否未发现失效引用;reported*Count可能小于总数,表示结果受maxResults截断。
json
{ "nodePath": "MainTriggers/Combat/Target", "env": "Common", "scope": "trigger" }json
{ "nodeId": "declaration-id", "env": "Server", "maxResults": 100 }当前首版覆盖 Declaration observer、ReferenceExpression 与 ProtoType 的基础诊断;不自动选择候选目标,也不执行引用重绑。
触发器支持的 C# 语法范围
通过 MCP 写入的 code 是导入格式,不是触发器的持久化源码。工具会先解析 C#,再把可识别的声明、语句和表达式映射到触发器编辑器的内部 JSON 模型,最后由模型重新生成 src/TriggerGenerated/ 下的 C#。因此不要把它理解成“完整 C# 源码保存器”,也不要假定触发器 JSON 能表达 C# 全集。
需要同时区分三层结果:
- C# 语法可解析:传入代码能被解析为 C# AST。
- 触发器模型可映射:AST 能被转换成触发器的变量、调用、条件、循环、表达式等模型节点。
- 生成代码可编译且语义正确:从触发器模型再生成的 C# 与原意一致,并能通过目标环境编译。
第 1 层成功不代表第 2、3 层一定成功。复杂或暂未建模的表达式可能退化为 CustomScript,也可能返回解析诊断、生成 未知定义、生成 #error,或生成能编译但语义需要人工核对的代码。
支持等级
| 等级 | 写法 | 处理要求 |
|---|---|---|
| 优先稳定使用 | 局部变量/静态字段声明、赋值、属性访问、方法调用、索引器、new 对象、基础算术/比较/逻辑运算、if / else、for、foreach、普通 return、List<T> / Dictionary<TKey,TValue> / 数组的常用操作 | 可直接作为触发器 C# 输入,仍需核对生成文件 |
| 可用但必须核对生成结果 | 集合初始化器、对象初始化器、LINQ、lambda、switch 表达式、模式匹配、条件访问 ?.、空合并 ??、三元 ?:、out 参数、复杂泛型、async / await | 允许尝试;若生成 CustomScript、重排局部变量或改写表达式,必须对照 src/TriggerGenerated/ 和编译结果确认语义 |
| 不建议直接依赖 | 本地函数、匿名类型、dynamic、反射重度逻辑、表达式树、unsafe、预处理指令、过深嵌套泛型、依赖闭包状态的复杂 lambda、复杂模式匹配组合 | 优先改成命名函数、简单类型、显式循环、字典/列表/配置表或普通方法调用 |
| 必须停下来的异常 | MCP 返回 isError、诊断中出现无法解析/未知符号、生成代码含 未知定义 或 #error、生成代码缺语句/控制流明显变形、编译错误 | 不要继续叠加创建;先报告传入的 code、MCP JSON、生成片段和错误,再简化或修复 |
目标不是为了触发器主动把代码降级成大量重复分支,而是写清晰、可映射、可核对的 C#。遇到不确定语法时,优先写一个最小探针函数,用 MCP 导入、保存、查看生成 C#、编译,再推广到正式逻辑。
LINQ、容器与 BCL API
- LINQ 不是禁用项,但属于“用后必核对”:查询表达式、
System.Linq扩展方法(如Where、Select、OrderBy、ToList、Any、First等)可以尝试按普通 C# 使用;实际能否映射、生成和编译,取决于目标环境的using、程序集引用、类型上下文和触发器模型支持情况。 System.Collections.Generic里的List<T>、Dictionary<TKey,TValue>、HashSet<T>等容器可以按普通 C# 容器使用,包括成员访问、方法调用、索引器、集合初始化器等;常用的Add、Remove、Contains、TryGetValue、Count、下标读写、foreach等应优先用于表达数据结构,而不是展开成重复if。- 当触发器逻辑是“根据 key、id、枚举值或类型查找结果”时,优先用
Dictionary<TKey,TValue>、List<T>、数组、switch表达式或 GameData/配置表建模;不要把数据映射展开成几十到几百行重复的if/else if。 - 网格、棋盘、表格等结构优先用数组或
List<T>表达;需要 JSON/网络序列化的数据使用一维数组加索引辅助方法,避免多维数组[,]。
表达式与语句
- 默认先写普通、清晰的 C#,但以“可映射到触发器模型”为准。字面量、括号、赋值与复合赋值、算术/比较/逻辑运算、一元运算、
++/--、强制转换、as/is、typeof/default等基础表达式通常更稳定。 - 条件访问
?.、空合并??、三元?:、字符串插值、数组/对象/集合初始化、元组、lambda、switch表达式、await等可以尝试,但必须检查生成文件;如生成CustomScript或诊断,应确认该表达式在目标环境可编译且语义未变。 - 编辑器再生成代码时可能调整格式、展开部分写法、重排局部变量,或把某些表达式保存为
CustomScript。这不是天然错误,但必须对照src/TriggerGenerated/核对语义。
如何确认「某系统 / API 是否可用」
trigger_search:在资源树里按query对节点名做子串匹配(触发器 / 校验器下的 Function、Class、Trigger 等)。适合判断地图里是否已有同名或含关键字的节点可作参照;不会扫描函数体里的 API 文本。- 更可靠的依据:①
trigger_create_*/ 编辑器返回的解析诊断;② 在src/TriggerGenerated/或工作区对标识符做全文搜索,看是否已有同类调用;③ 必要时对生成工程做编译验证。API 能否使用通常由目标工程引用、命名空间和类型上下文决定。
传入代码的形态约束(解析与再生成)
通过 MCP 写入的 C#(如 trigger_create_function / trigger_create_validator / trigger_create_variable / trigger_create_class / trigger_create_trigger / trigger_create_preset / trigger_create_custom_event 的 code)会由触发器编辑器解析为内部逻辑,再在保存/生成阶段写回 C#。这些 code 是“导入触发器模型的 C# 片段”,不是直接保存的源码文本;为了让工具知道要创建哪类触发器节点,必须满足各工具的外层声明形态和包装约定,例如函数须能放进 Scope,校验函数须能放进 partial class Validator,自定义事件须满足对应事件类约定。
触发器专用例外:trigger_create_trigger 的 _Execute 是导入触发器模型的包装方法,解析后会拆成 Conditions 与 Statements,最终成功返回由生成器自动补;不要把“触发器动作不手写 return true;”扩展到普通函数、Validator 函数或 Class 方法。普通函数/Validator/Class 方法仍按自身返回类型正常书写 return。
创建类写操作在业务成功返回前会由 MCP 自动刷新 src/TriggerGenerated/;trigger_save 仍用于将触发器树等持久化到地图工程(与生成输出是不同步骤)。必须校验:在资源管理器或 IDE 中打开上述目录下的 common.cs、client.cs、server.cs(按所选 env 关注对应文件;Validator 相关在子目录中)。用本次创建的函数名、校验函数名、变量名、类名、触发器名、枚举名或自定义事件类名搜索,将生成结果与 MCP 传入的 code 对照,确认控制流与表达式是否一致(生成风格可能与手写略有差异,属正常现象)。
遇到解析、再生成或编译失败时,以工具返回的错误或诊断为准。多数情况下应先检查节点路径、声明签名、命名空间、引用、可见性、泛型约束和包装位置;确认为语法或映射问题时再按诊断简化写法。若生成代码包含 未知定义、#error、明显缺失的语句或明显错误的控制流,视为导入失败,停止后续写操作并保留本次传入的 MCP JSON、code 和生成片段用于排查。
语句块结构
- 触发器模型通常会把块内局部变量拆到
Variables表中;再生成 C# 时,局部变量声明可能被移动到块首。 - 不要在局部变量初始化式中依赖前面语句的副作用。如果初始化值依赖前面已经执行过的操作,先声明默认值,再用单独赋值语句写入。
csharp
// ✅ 稳定:声明默认值,依赖顺序的读取放在语句里
var values = new Dictionary<string, int>();
var appleValue = 0;
values.Add("apple", 1);
appleValue = values["apple"];
// ❌ 风险:导入模型后声明可能被提前,初始化式也可能提前执行
var values = new Dictionary<string, int>();
values.Add("apple", 1);
var appleValue = values["apple"];- 再生成代码可能会按编辑器风格重排局部变量、格式或部分表达式。只要生成代码语义一致、编译通过即可;若顺序相关逻辑被改变,必须改写传入代码。
语句可用范围
- 优先使用可直接映射的普通语句:赋值、方法调用、
if/else、for、foreach、return、局部变量声明、对象创建等。 - 复杂语句如果被保存为
CustomScript,不是天然错误,但必须确认生成代码可编译且语义未变。 - 解析失败时按返回信息定位:先确认外层包装和上下文,再按诊断改写。
for 循环
- 可使用常规
for写法,包括i++/++i/i--、复合赋值以及常见循环条件。 - 如果某个复杂循环头触发诊断,再按工具提示拆成更简单的初始化、条件或迭代表达式。
表达式可用范围
- 表达式优先写成触发器模型容易表达的形式:字面量、变量引用、属性/字段访问、方法调用、索引器、算术/比较/逻辑运算、简单
new、简单集合操作。 - LINQ、lambda、条件访问、空合并、三元、字符串插值、强制转换、集合初始化等常见 C# 写法可以尝试,但属于“生成后必须核对”的范围;如工具诊断或编译结果指出上下文缺失,再补引用或改写。
- API 可用性主要取决于生成工程的引用和命名空间。幂运算等库调用可直接使用
System.Math.Pow等标准 API;如目标 API 在触发器模型中不能形成正式节点,可能以CustomScript形式保留。
函数与字段
- 函数(
trigger_create_function与trigger_create_validator):须为public static …,并满足目标环境的返回类型、参数类型、泛型约束和引用要求。函数体按本节的可映射范围书写;需要返回值时必须正常写return。 - 仅替换函数体(
trigger_replace_function_body):code为单方法,方法名必须为TempFunctionBody,且与目标函数签名一致(见该工具说明);其余形态约束与同环境trigger_create_function/trigger_create_validator一致。 - 静态字段(
trigger_create_variable):字段声明须能放进Scope类;初始化式按本节的可映射范围解析。
小结
不要为了触发器主动降级成大量重复 if,也不要假定 C# 全集都能无损变成触发器 JSON。先写清晰、合法、表驱动且容易映射的 C#;再用工具诊断、生成文件和编译结果确认节点创建、再生成与语义。只有在诊断或生成结果明确指出某处无法解析或无法映射时,才有针对性地简化写法。
创建操作
适用于:trigger_create_function、trigger_create_validator、trigger_create_variable、trigger_create_class、trigger_create_trigger、trigger_create_preset、trigger_create_custom_event 中的 code(其中 Preset/CustomEvent 的约定见各自工具小节)。trigger_replace_function_body 的 code 同样须遵守上一节 「传入代码的形态约束(解析与再生成)」(单方法、名为 TempFunctionBody)。类成员、普通函数与 Validator 函数按上文可映射范围书写;触发器 _Execute 的 Conditions / Statements / 自动 return 约定见 trigger_create_trigger 小节;trigger_create_custom_event 另须满足 主构造 + Events.ITriggerEvent<自身> 等解析器硬性约定(见下)。
parentPath 与默认路径(创建)
凡带 parentPath 的创建类工具,该参数一律可选。未传或留空时,多数工具将节点添加到当前地图库在 env 所指环境下的库模块根目录(该环境下的顶层触发器文件列表根,与「只传 env 的 trigger_create_function」一致)。
- 已带
env的工具(如trigger_create_function、trigger_create_class、trigger_create_trigger、trigger_create_preset、trigger_create_custom_event):省略parentPath时用该env的普通库模块根目录。 trigger_create_validator:省略parentPath时,节点添加到该env下的 Validator 模块根目录(与普通 LibModule(触发器模块) 并列的校验器文件树;若当前地图在该环境下没有 Validator 模块,工具会报错)。trigger_create_folder:另带可选env;仅在省略parentPath时使用。若也不传env,则按 Common 环境的库根处理。若要链式调用trigger_create_*,不要依赖「仅env、无parentPath」在库根创建的文件夹作为下一跳的parentPath根;见上文 「parentPath的合法根」 与trigger_create_folder小节的链式示例与path字段说明。
传了 parentPath 时,仍为「文件名/文件夹/…」层级路径;trigger_create_validator 的路径应落在 Validator 文件列表(用 trigger_list_validator_files / trigger_get_validator_file 核对;若不确定路径,可先省略 parentPath 落到 Validator 根再整理)。未在文档里单独写「默认路径」的其它工具,均按普通库模块根目录规则理解即可。
trigger_create_class
根据类源码创建 Class 节点(与 trigger_create_function 一致:parentPath 可选、env 与 code 必填)。成功后 MCP 自动刷新生成代码至 src/TriggerGenerated/;trigger_save 用于持久化地图数据。解析器取源码中首个 class / struct / record 声明,并解析成员与方法体(见 ClassParser.ClassFromSymbolFull)。不要把类型写在 partial class Scope { } 里(与 trigger_create_function 不同;code 会置于 GameEntry 命名空间而非 Scope 内)。
参数:
parentPath(可选): 父节点路径(文件或文件夹)。省略时见上文「parentPath与默认路径」env(必需): 环境,支持 "Common" / "Client" / "Server"code(必需): 类声明源码,例如"public class DamageHelper { public static int Add(int a, int b) { return a + b; } }"。若未写namespace,则自动加上namespace GameEntry;(文件作用域命名空间)。类内成员与方法体须遵守上文 「触发器支持的 C# 语法范围」 与 「传入代码的形态约束(解析与再生成)」。
示例调用:
json
{ "parentPath": "MainTriggers/Utils", "env": "Server", "code": "public class DamageHelper { public static int Add(int a, int b) { return a + b; } }" }json
{ "env": "Common", "code": "public class MyHelper { private static int X() { return 1; } }" }返回(成功时): success、name、path、message(无 codeGeneration 字段;成功返回前已自动刷新生成目录;trigger_save 仍须单独调用以持久化)。
trigger_create_trigger
根据单个触发器的 C# 代码创建 Trigger 节点(与 trigger_create_class 一致:parentPath 可选、env 与 code 必填)。成功后 MCP 自动刷新生成代码;trigger_save 用于持久化。
约定概要:
- 源码中第一个类型声明为
partial class Scope(可带: GameCore.BaseInterface.IGameClass);若code仅含类体成员,工具会自动包进namespace GameEntry;与该Scope声明。 - 类内需要 1 个 static 触发器属性或字段,它的名字就是触发器名。
- 类内需要 2 个同名配套函数:
<触发器名>_Execute和<触发器名>_Initializer。 <触发器名>_Execute是给解析器导入触发器模型用的包装方法;导入后会拆成触发器的 Conditions 与 Statements,不要把它当成普通业务函数手写完整成功/失败返回流。- Conditions 是“允许继续执行的正向条件”。生成代码会把它们合成为
if (!(condition)) return false;。 - Statements 只放真正要执行的动作语句,例如日志、创建单位、修改数据等;不要在动作区手写触发器成功/失败用的
return true;/return false;。 - 触发器生成器会在生成
_Execute时自动补最终return true;。因此 MCP 传入片段里可以不写最终成功返回。 - 如需从代码片段导入 Conditions,可在
_Execute开头使用生成器形态的 guard:if (!(正向条件)) { return false; }。这里的return false;只用于还原 Conditions,不会进入 Statements;不要在后续动作体里再写return false;。 <触发器名>_Initializer只负责给触发器赋值与注册事件。单一事件类型的强类型Events.Trigger<T>使用Register(sender);动态或多事件触发器使用AddEvent<T>(sender)。解析器仍接受旧版单事件AddEvent<T>代码。_Initializer中通常会出现new Events.Trigger<T>(<名>_Execute, false);其中构造函数第二个参数仍须为字面量false。
参数:
parentPath(可选): 父节点路径(文件或文件夹)。省略时见上文「parentPath与默认路径」env(必需): 环境,支持 "Common" / "Client" / "Server"code(必需): 完整片段或仅Scope类体。须遵守上文 「触发器支持的 C# 语法范围」 与 「传入代码的形态约束(解析与再生成)」;_Execute内前置 guard 表达 Conditions,其余动作表达 Statements,不要为了触发器成功/失败手写 return,以工具返回和生成代码为准。
示例调用(推荐形态;仅示意结构,事件类型与注册目标须与当前地图编译集一致):
json
{
"parentPath": "MainTriggers/Input",
"env": "Client",
"code": "private static async System.Threading.Tasks.Task<bool> OnF2KeyDown_Execute(object sender, GameUI.TriggerEvent.EventGameKeyDown e) { if (!(!e.IsRepeat && e.Key == GameCore.Platform.SDL.VirtualKey.F2)) { return false; } Game.Logger.LogInformation(\"F2 key trigger fired.\"); } public static Events.Trigger<GameUI.TriggerEvent.EventGameKeyDown> OnF2KeyDown { get; set; } = null!; public static void OnF2KeyDown_Initializer() { OnF2KeyDown = new Events.Trigger<GameUI.TriggerEvent.EventGameKeyDown>(OnF2KeyDown_Execute, false); OnF2KeyDown.Register(Game.Instance); }"
}上述示例导入后的模型含义是:
- Conditions:
!e.IsRepeat && e.Key == GameCore.Platform.SDL.VirtualKey.F2(正向通过条件) - Statements:
Game.Logger.LogInformation("F2 key trigger fired."); - 生成代码会自动在动作之后追加最终
return true;,日志语句保持可达。
常见错误:
- 不要在触发器动作中手写
return true;。这会进入 Statements,生成器还会再补一个最终成功返回,容易造成后续动作不可达。 - 不要用
if (...) return true;表达过滤条件。过滤条件应进入 Conditions,由生成器生成失败返回。 - 不要把过滤条件写反。按键过滤这类条件应写成允许执行的正向条件,例如
!e.IsRepeat && e.Key == GameCore.Platform.SDL.VirtualKey.F2,而不是e.IsRepeat || e.Key != GameCore.Platform.SDL.VirtualKey.F2。
返回(成功时): success、name、path、message(无 codeGeneration 字段;成功返回前已自动刷新生成目录;trigger_save 仍须单独调用以持久化)。
trigger_create_function
创建新函数。
参数:
parentPath(可选): 父节点路径。省略时见上文「parentPath与默认路径」env(必需): 环境,支持 "Common" / "Client" / "Server"code(必需): 函数代码。代码会被放到Scope类中进行解析,且函数必须是静态函数。须遵守上文 「触发器支持的 C# 语法范围」 与 「传入代码的形态约束(解析与再生成)」;以工具返回和生成代码为准。
示例调用:
json
{ "parentPath": "MainTriggers/Utils", "env": "Server", "code": "public static int CalculateDamage(int a, int b) { return a + b; }" }json
{ "env": "Common", "code": "public static System.Collections.Generic.List<int> BuildValues(int a, int b) { return new System.Collections.Generic.List<int> { System.Math.Max(a, b) }; }" }返回(成功时): success、name、path、message(成功返回前已自动刷新生成目录;trigger_save 仍须单独调用以持久化)。
trigger_create_validator
在 Validator 模块中创建校验函数节点。语义与 trigger_create_function 几乎相同:解析路径用 partial class Validator(而非 Scope),且必须是静态函数。成功后 MCP 自动刷新生成输出(含 Validator 相关文件);trigger_save 用于持久化。
参数:
parentPath(可选): 父节点路径,须指向 Validator 侧的文件或文件夹。省略时添加到当前地图在该env下的 Validator 模块根目录(见上文「parentPath与默认路径」)env(必需): 环境,支持 "Common" / "Client" / "Server"code(必需): 校验函数代码。实现侧会包进GameEntry下的partial class Validator再解析(若code已含partial class Validator则不再嵌套)。须为静态函数,且须遵守上文 「触发器支持的 C# 语法范围」 与 「传入代码的形态约束(解析与再生成)」;以工具返回和生成代码为准。
错误(常见): 当前地图在指定环境下没有 Validator 模块时,会返回明确错误(无法创建)。
示例调用:
json
{ "parentPath": "ValidatorMain/Checks", "env": "Server", "code": "public static bool IsHpValid(int hp) { return hp >= 0; }" }json
{ "env": "Common", "code": "public static bool NonNegative(int x) { return x >= 0; }" }返回(成功时): success、name、path、message(成功返回前已自动刷新生成目录;trigger_save 仍须单独调用以持久化)。
trigger_create_variable
根据代码创建新变量。
参数:
parentPath(可选): 父节点路径。省略时见上文「parentPath与默认路径」env(必需): 环境,支持 "Common" / "Client" / "Server"code(必需): 变量声明代码。代码会被放到Scope类中进行解析,且必须是静态字段,例如"public static int PlayerScore = 0;"。初始化表达式须遵守上文 「触发器支持的 C# 语法范围」 与 「传入代码的形态约束(解析与再生成)」;以工具返回和生成代码为准。
示例调用:
json
{ "parentPath": "MainTriggers/Global", "env": "Common", "code": "public static int PlayerScore = 0;" }返回(成功时): success、name、path、message(成功返回前已自动刷新生成目录;trigger_save 仍须单独调用以持久化)。
trigger_create_preset
扩展已有可扩展枚举:图形化触发编辑器将此操作称为预设值类型的**“继承”,与 [EnumExtension(Extends = typeof(...))] 等价。需要在图形化数据编辑器中选择新增值时,必须建立可保存为触发器 JSON 的 Preset 声明;仅手写 C# 不能替代该声明。两端共用的枚举建议放在公共页**,即 env: "Common"。下方物品分类只是这一通用机制的示例。
例如扩展物品分类(目标类型须能在项目编译环境中解析):
json
{
"env": "Common",
"code": "[GameCore.Extension.EnumExtension(Extends = typeof(GameCore.Struct.ItemCategory))] public enum EGatheringItemCategory { Woodcutting = 2001 }"
}导入后图形化名称为 GatheringItemCategory(去掉源枚举的 E 前缀)。检查其继承目标和生成的 Extends,再调用 trigger_save 持久化、双端编译并加载最新声明,确认数据编辑器可以选择新增项。Extendable = true 对应“是否可被继承”,只表示允许其他类型继续扩展当前类型,不能代替 Extends。若导入报告特性或继承目标无法解析,应修正命名空间、引用或目标声明后重试,不要接受生成普通枚举的结果。完整说明见 枚举扩展。
根据 枚举源码创建 Preset 节点(与 trigger_create_class 一致:parentPath 可选、env 与 code 必填)。成功后 MCP 自动刷新生成代码;trigger_save 用于持久化。解析器取源码中首个 enum 声明(PresetParser / ParsePresetFromCode)。code 会置于 GameEntry 命名空间(若未写 namespace 则自动补 namespace GameEntry;,与 trigger_create_class 相同)。
参数:
parentPath(可选): 父节点路径(文件或文件夹)。省略时见上文「parentPath与默认路径」env(必需): 环境,支持 "Common" / "Client" / "Server"code(必需): 枚举声明源码,须含enum;可用public enum。枚举成员须为带数值常量的 public/protected 字段才会进入预设项(与解析器一致)。
示例调用(与单元测试 Preset_CustomEvent_P.ParsePresetFromCode_Success_ChineseEnumMembers 结构一致,可按项目改名):
json
{
"env": "Common",
"code": "public enum 测试预设值\n{\n 属性A,\n 属性B\n}"
}json
{
"parentPath": "MainTriggers/Data",
"env": "Common",
"code": "public enum MyPreset { OptionA, OptionB }"
}返回(成功时): success、name、path、message(成功返回前已自动刷新生成目录;trigger_save 仍须单独调用以持久化)。
trigger_create_custom_event
根据源码创建 CustomEvent 节点(parentPath 可选、env 与 code 必填)。成功后 MCP 自动刷新生成代码;trigger_save 用于持久化。仅支持下列形态,否则工具返回解析诊断(ParseCustomEventFromCode):
- 源码中第一个类型声明须为
class(不支持interface/struct/record)。 - 类名右侧须有主构造参数列表
(...)(可为()或带参数;多参数时按形参名匹配绑定主构造)。 - 须实现
Events.ITriggerEvent<当前类>,且泛型实参必须为当前类自身。 - 主构造对应的
Function只写入模型的EventCreator,不写入EventCreators(与解析器设计一致)。
code 置于 GameEntry(未写 namespace 时自动补全,与 trigger_create_class 相同)。不要把该类写在 partial class Scope { } 内。
参数:
parentPath(可选): 父节点路径。省略时见上文「parentPath与默认路径」env(必需): 环境,支持 "Common" / "Client" / "Server"code(必需): 自定义事件类源码,须含与主构造参数对应的 public 属性(与生成器/编辑器习惯一致)。
示例调用(与单元测试 Preset_CustomEvent_P.ParseCustomEventFromCode_Success_PrimaryCtorAndProperty 结构一致;事件类型与项目引用须与当前地图编译集一致):
json
{
"env": "Common",
"code": "public class 测试事件(string 新参数) : Events.ITriggerEvent<测试事件>\n{\n public string 新参数 { get; set; } = 新参数;\n}"
}json
{
"parentPath": "MainTriggers/Events",
"env": "Server",
"code": "public class OnCustomSignal(string payload) : Events.ITriggerEvent<OnCustomSignal> { public string Payload { get; set; } = payload; }"
}返回(成功时): success、name、path、message(成功返回前已自动刷新生成目录;trigger_save 仍须单独调用以持久化)。
trigger_create_folder
在资源树中创建 Folder 节点,仅用于编辑器内分组;不改变生成代码中的命名空间或目录结构。成功后 MCP 自动刷新生成代码;trigger_save 仍须单独调用以持久化。
两种挂接位置:
- 省略
parentPath,只传(或默认)env:文件夹挂在当前库在该环境下的环境模块根内容下。此类位置不能稳定地作为后续trigger_create_*的parentPath——若下一调用把parentPath写成仅该文件夹名,通常会失败并返回Cannot add to path: <parentPath> in env <Env>. Must be a file or folder.(首段必须是trigger_list_files中的 LibModule 文件名,见上文 「parentPath的合法根」)。 - 传入
parentPath:父级为已有 LibModule 文件名或该文件下的文件夹路径;与后续创建工具使用的路径模型一致,可链式使用。
成功返回:JSON 中含 path(本次文件夹的节点路径字符串)。给自动化 / AI 的用法:应用 path 判断文件夹落在哪条链上——只有形如 某LibModule文件名/子路径/文件夹名 的 path,才适合直接(或截断到某一级文件夹)作为下一 parentPath。若 path 只有单层名字、且不是 trigger_list_files 里的文件名,不要把它当作 trigger_create_* 的根;应改为 parentPath = "<列表中的文件名>" 后重新建夹或移动整理。
参数:
parentPath(可选): 父节点路径(文件或文件夹)。省略时见上文「parentPath与默认路径」env(可选): 仅在省略parentPath时生效,默认 Commonname(必需): 文件夹名称
示例调用:
json
{ "parentPath": "MainTriggers", "name": "AI" }json
{ "env": "Client", "name": "UIHelpers" }链式创建(推荐):假定 trigger_list_files 中已有 GameEntry(请按你地图实际文件名替换)。串行调用。
- 在文件节点下建夹:
json
{ "parentPath": "GameEntry", "name": "CodexMcpTest_181055" }- 用
GameEntry/…作为父路径继续创建(示例为函数;其它trigger_create_*同理):
json
{ "parentPath": "GameEntry/CodexMcpTest_181055", "env": "Common", "code": "public static int Demo() { return 1; }" }- 按需
trigger_save持久化;可用trigger_search/trigger_get_file核对完整路径(写操作成功时已自动刷新生成目录)。
反例(易失败):{ "env": "Common", "name": "CodexMcpTest_xxx" } 后直接 { "parentPath": "CodexMcpTest_xxx", "env": "Common", ... } —— parentPath 根必须是 LibModule 文件名,不能是仅库根下新建的文件夹名。
修改操作
trigger_rename
重命名普通触发器树或 Validator 树中的节点(不修改节点内 C# 逻辑)。已有函数仅改函数体时优先用 trigger_replace_function_body;其它大范围改逻辑仍见上文「代码生成与等价修改」(trigger_delete + trigger_create_*)。
行为要点(与实现一致):
newName会 Trim;与同一父列表下已有兄弟节点不能重名(与同目录trigger_create_*规则一致);仅大小写或空白变化时若与自身等价则允许。- 父节点须为列表容器;根级 LibModule 文件等无列表父级时不能通过本工具重命名(会返回错误)。
- 成功后 MCP 自动刷新生成代码至
src/TriggerGenerated/;trigger_save仍须单独调用以持久化地图数据。
参数:
nodePath(必需): 节点路径newName(必需): 新名称scope(可选):trigger(默认,普通触发器模块树)或validator(Validator 模块内路径)
示例调用:
json
{ "nodePath": "MainTriggers/Combat/OldName", "newName": "NewName" }json
{ "nodePath": "ValidatorMain/Checks/OldFn", "newName": "NewFn", "scope": "validator" }返回(成功时): success、oldName、newName、path、message
trigger_delete
安全删除节点。默认使用严格模式;目标不存在时仍报错。成功后 MCP 自动刷新生成代码,src/TriggerGenerated/ 与当前树一致(例如已删除符号会从生成代码中移除);trigger_save 仍须单独调用以持久化。
参数:
nodePath(必需): 节点路径scope(可选):trigger(默认,普通触发器模块树)或validator(Validator 模块内路径)env(可选):Common/Client/Server;同一路径跨环境存在时必须指定ignoreIfMissing(可选): 默认false。只有环境、树和父路径都精确有效,且仅末级节点已经不存在时,才返回幂等成功
删除前会检查目标节点的整个子树。若其中声明仍被子树外部引用,工具返回 errorCode: "node_still_referenced" 并拒绝删除;先用 trigger_inspect_references 查看来源。ignoreIfMissing 不会绕过引用保护,也不会把错误父路径、非法环境或歧义路径当作成功。
示例调用:
json
{ "nodePath": "MainTriggers/Combat/UnusedTrigger" }json
{ "nodePath": "ValidatorMain/UnusedFn", "scope": "validator" }自动化需要重复保证“节点不存在”时,使用精确环境与显式幂等参数:
json
{ "nodePath": "MainTriggers/Combat/UnusedTrigger", "env": "Common", "ignoreIfMissing": true }典型结果:
- 实际删除:
outcome: "committed"、changed: true、alreadyAbsent: false、persistence: "dirty"; - 已不存在且精确父路径有效:
outcome: "committed"、changed: false、alreadyAbsent: true、persistence: "unchanged"; - 删除后生成失败或产生诊断:
outcome: "unknown"、changed: true、safeToRetry: false,停止自动重试。
trigger_set_enabled
启用或禁用节点。成功后 MCP 自动刷新生成代码至 src/TriggerGenerated/;trigger_save 仍须单独调用以持久化。
参数:
nodePath(必需): 节点路径enabled(必需): 是否启用scope(可选):trigger(默认)或validator
示例调用:
json
{ "nodePath": "MainTriggers/Debug/TestTrigger", "enabled": false }json
{ "nodePath": "ValidatorMain/SomeCheck", "enabled": false, "scope": "validator" }trigger_replace_function_body
仅替换已有 静态函数或 Class 成员函数的函数体(不改名、不改签名)。服务端用与创建函数相同的方式把 code 包进 partial class Scope(普通触发器模块)、partial class Validator(Validator 模块)或目标 Class 名(类成员方法),解析出首个方法;该方法在源码中必须命名为 TempFunctionBody,且 static / async、返回类型、类型参数个数、参数类型与 params 等须与资源树里 functionName 所指目标函数完全一致,否则工具报错。成功后 MCP 自动刷新生成代码至 src/TriggerGenerated/;trigger_save 仍须单独调用以持久化。
parentPath(必需):父容器路径(首段为 Lib 文件名,与 trigger_create_* 一致):
- Scope 内静态函数(库根或文件夹下):指向该函数所在的文件或文件夹(例如
MainTriggers或MainTriggers/Utils)。 - Class 成员函数:指向包含该方法的 Class 节点(例如
MainTriggers/Helpers/MyClass),不是…/MyClass/方法名的完整节点路径。
functionName(必需):资源树中要改体的函数的真实名称(不是 TempFunctionBody)。
env(必需):Common / Client / Server。
code(必需):单个方法声明片段;方法名须为 TempFunctionBody,函数体为新逻辑。须遵守上文 「传入代码的形态约束(解析与再生成)」。
scope(可选):trigger(默认)或 validator。在 Validator 模块内替换校验函数时须 scope: "validator"。
重载:若同一父列表下存在多个同名重载,工具会用解析出的 TempFunctionBody 签名匹配唯一目标;0 个或多个匹配时会失败。
示例调用(普通库下某静态函数 Calculate,父路径为 MainTriggers/Utils):
json
{
"parentPath": "MainTriggers/Utils",
"functionName": "Calculate",
"env": "Common",
"code": "public static int TempFunctionBody(int a, int b) { return a * b; }"
}示例调用(Validator 内函数 IsNonNegative):
json
{
"parentPath": "ValidatorMain/Checks",
"functionName": "IsNonNegative",
"env": "Server",
"scope": "validator",
"code": "public static bool TempFunctionBody(int x) { return x >= 0; }"
}返回(成功时): success、parentPath、functionName、path(一般为 parentPath/functionName)、scope、message(成功返回前已自动刷新生成目录;trigger_save 仍须单独调用以持久化)。
保存与自动生成
写操作(trigger_create_*、trigger_delete、trigger_rename、trigger_set_enabled、trigger_replace_function_body)在业务成功返回前会由 MCP 自动将当前模型生成到 src/TriggerGenerated/(与编辑器内「生成代码」一致)。不再提供独立的 trigger_generate_code 工具。
trigger_save
保存触发器更改到地图工程(与上述自动生成是不同步骤;修改后仍应适时 trigger_save)。
参数:
saveDependLibs(可选): 是否保存依赖库,默认 false
示例调用:
json
{ "saveDependLibs": false }trigger_get_editor_state
获取编辑器状态。
参数: 无
返回:
json
{
"currentLib": "MainTriggers",
"needsSave": true,
"needsCodeGeneration": true,
"lastCodeGeneration": "2024-01-15T10:30:00Z",
"fileCount": { "Common": 5, "Client": 3, "Server": 2 }
}测试工具(MCP Server)
以下 mcp_* 由 MCP Server 其它模块注册,不属于上文 trigger_* 清单;是否可用取决于宿主是否暴露整套 MCP。
mcp_run_tests
运行完整单元测试套件:
json
{
"category": "trigger",
"verbose": true
}category: "all" | "data" | "trigger"。
返回:
json
{
"summary": "10/12 tests passed",
"totalTests": 12,
"passed": 10,
"failed": 2,
"durationMs": 1234,
"failedTests": [
{ "name": "TestName", "error": "Error message" }
]
}mcp_test_quick
快速验证 MCP 连接:
json
{}返回:
json
{
"summary": "Quick test: 4/4 passed",
"passed": 4,
"failed": 0,
"tests": [
{ "test": "data_list_tables", "status": "PASS" },
{ "test": "trigger_list_files", "status": "PASS" }
]
}