Skip to content

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
只读状态 / APItrigger_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 内)。可用 MCP trigger_create_preset 从枚举源码创建。
  • CustomEvent:须为 class 名(主构造参数) : Events.ITriggerEvent<自身> 形式,主构造进入模型 EventCreator。可用 MCP trigger_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 持久化模型;不要把两种调用顺序混用。

  1. 在文件树选择目标环境;双端共享类型默认使用 “共用(Common)”。
  2. 通过 “类定义” 新建并选中普通 Class,在右侧 “属性设置” 中维护字段。
  3. 新建根分类时勾选 “设置为数编分类”;新建已有分类的子类型时勾选 “设置为数编类型”。
  4. “设置为数编类型”会要求依次选择 “节点分类” 和 “节点父类”。前者对应根分类 T,后者对应直接父类 V;两者都选好后才能确定。
  5. 先执行 “保存”,把触发定义持久化到 editor/trigger/**;再执行 “生成代码文件”,刷新 src/TriggerGenerated/{common|client|server}.cs。这是两个不同动作。
  6. 核对生成的 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 — 保存地图数据

注意事项 ​

  1. 保存: 修改后需要调用 trigger_save 将触发器数据写入地图工程
  2. 代码生成: 各写操作(创建、删除、重命名、启用/禁用、替换函数体等)成功返回前 MCP 会自动刷新 src/TriggerGenerated/;无需再调已移除的 trigger_generate_code。trigger_delete 若在模型改变后生成失败或产生诊断,会返回 outcome: "unknown"、safeToRetry: false;此时不要自动重试
  3. 环境分离: 注意选择正确的环境 (Common/Client/Server)
  4. 路径准确性: 确保路径准确,区分大小写
  5. 依赖库: 如果修改了依赖库,需要设置 saveDependLibs: true
  6. MCP 传入的 C#(创建函数/校验函数/变量/类/触发器/预设枚举/自定义事件等,以及 trigger_replace_function_body 的 code): 这是导入触发器模型的 C# 片段,必须符合各写入工具的声明形态、包装位置、节点约定与可映射语法范围;详见下方 「触发器支持的 C# 语法范围」 与 「传入代码的形态约束」。创建类工具在成功返回前会自动写 src/TriggerGenerated/;必须对照生成文件与传入 code 做人工校验,并在适当时机 trigger_save。
  7. 串行调用: 创建及会修改触发器状态的其它操作(重命名、删除、启用/禁用、替换函数体、保存等)不要并行,须等上一调用返回后再发起下一调用;详见下方 「并发与调用顺序」。

错误处理 ​

JSON-RPC 与 tools/call 结果(两层别混淆) ​

  • JSON-RPC 层:tools/call 正常执行完毕时,RPC 仍多为 result 对象(不是 JSON-RPC 顶层的 error)。只有缺工具名、工具未注册、传输异常等才会走 JSON-RPC error。
  • 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" 便于区分。


搜索节点。

参数:

  • 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# 全集。

需要同时区分三层结果:

  1. C# 语法可解析:传入代码能被解析为 C# AST。
  2. 触发器模型可映射:AST 能被转换成触发器的变量、调用、条件、循环、表达式等模型节点。
  3. 生成代码可编译且语义正确:从触发器模型再生成的 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 仍须单独调用以持久化。

两种挂接位置:

  1. 省略 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 的合法根」)。
  2. 传入 parentPath:父级为已有 LibModule 文件名或该文件下的文件夹路径;与后续创建工具使用的路径模型一致,可链式使用。

成功返回:JSON 中含 path(本次文件夹的节点路径字符串)。给自动化 / AI 的用法:应用 path 判断文件夹落在哪条链上——只有形如 某LibModule文件名/子路径/文件夹名 的 path,才适合直接(或截断到某一级文件夹)作为下一 parentPath。若 path 只有单层名字、且不是 trigger_list_files 里的文件名,不要把它当作 trigger_create_* 的根;应改为 parentPath = "<列表中的文件名>" 后重新建夹或移动整理。

参数:

  • parentPath (可选): 父节点路径(文件或文件夹)。省略时见上文「parentPath 与默认路径」
  • env (可选): 仅在省略 parentPath 时生效,默认 Common
  • name (必需): 文件夹名称

示例调用:

json
{ "parentPath": "MainTriggers", "name": "AI" }
json
{ "env": "Client", "name": "UIHelpers" }

链式创建(推荐):假定 trigger_list_files 中已有 GameEntry(请按你地图实际文件名替换)。串行调用。

  1. 在文件节点下建夹:
json
{ "parentPath": "GameEntry", "name": "CodexMcpTest_181055" }
  1. 用 GameEntry/… 作为父路径继续创建(示例为函数;其它 trigger_create_* 同理):
json
{ "parentPath": "GameEntry/CodexMcpTest_181055", "env": "Common", "code": "public static int Demo() { return 1; }" }
  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" }
  ]
}