Skip to content

SCE 数据编辑器 Skill ​

选择宿主 ​

按开发入口规则优先复用用户已打开目标项目的可视化编辑器,除非用户主动要求隔离;没有已打开的 GUI 或用户要求隔离时,AI 编辑数据、保存生成与构建优先 Headless,先检查 capability、项目状态和 tools/list。GUI 数据面板的 ui_* 上下文工具仍使用完整编辑器。GUI 和 Headless 不要同时写同一项目;下文的 GUI HTTP 辅助脚本不能替代 Headless 启动与能力检查。

配置生效与扩展字段 ​

JSON 允许保存项目/编辑器的自定义辅助字段;生成器只生成实际声明的字段,未知字段静默跳过是预期行为,不要删除这些扩展内容或将它们当作无效数据。未知字段不会自动成为运行时 C# 属性。已声明字段的值无法生成而被注释,则检查 GDATA001、generationWarningCount 和结构化 diagnostics。增量诊断只覆盖本次处理的文件,完整审计可用 generateAll: true。

修改继承集合后核对本地、继承和有效值;新版设置工具返回 fieldState / fieldStates,不要把 reset 解释成清空继承数组。函数可以是常量或触发器函数引用;图形界面“新建函数...”可创建并绑定,JSON 没有 => 不代表不支持逻辑。

先记录安装版本与双端 API,再做引用、生成、编译和新局验证;build_start / debug_start 已包含保存和生成。详细流程见技能、AI 与表现:从配置到运行证据。

何时使用 ​

当任务涉及以下内容时使用本 Skill:

  • 创建、查询、修改或删除 editor/data/**/*.json 里的 GameData 配置
  • 在触发编辑器中定义自定义数编 Class,或在纯代码项目中使用 [GameDataCategory] / [GameDataNodeType<T,V>]
  • 扩展物品分类等枚举选项,并使其在图形化数据编辑器中可选
  • 使用 data_*、gamedata_*、完整编辑器 ui_* MCP 工具操作数据编辑器
  • 处理 $id、$inherit、Link 字符串路径、继承覆盖、本地字段等数编机制
  • 判断是在定义数编类型、创建编辑器条目,还是注册 runtime-only 条目
  • 修改数据后需要同步 src/DataGenerated/**

先判断是在定义“类型”还是创建“条目” ​

用户诉求维护入口
用现有字段再做一份单位、技能、配置等数据数据编辑器 / editor/data 中创建条目
现有类型缺少项目需要的字段或专用行为,且要用图形化数据编辑器先在触发编辑器定义 Class,并在属性面板“设置为数编类型”
建立独立数据族,且要用图形化数据编辑器先在触发编辑器定义 Class,并在属性面板“设置为数编分类”
新增物品分类等枚举选项,且要在图形化数据编辑器中选择在触发编辑器公共页新建预设值类型,并“继承”要扩展的预设值类型
项目明确采用纯代码类型定义在 src/**/*.cs 手写对应 C# 特性
只在本局临时构造、不需要编辑器维护在统一初始化路径创建 runtime-only GameData

data_* 工具只能维护已经存在于 CLR/schema 中的类型、表和条目。gamedata_list_types 找不到目标类型时,不要通过未知 $type、额外 JSON 字段或随意选择一个通用配置类型来绕过;先完成类型 authoring、代码生成与编译发现。

自定义类型的权威契约见 GameData 数据驱动系统。本 Skill 只保留 AI 执行闭环。

自定义类型执行闭环 ​

  1. 先用 gamedata_list_types / gamedata_get_type_schema 确认内置或项目已有类型确实无法表达需求。
  2. 如果用户要使用图形化数据编辑器,先切到触发编辑器:
    • 在 “共用(Common)” 环境用 “类定义” 新建普通 Class,并添加字段属性
    • 独立根分类在 “属性设置” 勾选 “设置为数编分类”
    • 已有分类的子类型勾选 “设置为数编类型”,依次选择 “节点分类”(根分类 T)和 “节点父类”(直接父类 V)
    • Class 事先不能已有其它父类或名为 Link 的成员,也不要同时设置成分类和节点类型
  3. 在触发编辑器先 “保存”,再执行 “生成代码文件”。确认 src/TriggerGenerated/{env}.cs 中生成了 partial class 与对应的 GameDataCategoryAttribute / GameDataNodeTypeAttribute<T,V>;不要手改生成文件。
  4. 同时编译 Client-Debug 和 Server-Debug,让 source generator 生成并验证类型;共享数编类型不能只存在于单端环境。
  5. 让编辑器重新加载最新项目程序集,再用 gamedata_list_types 和 gamedata_get_type_schema 确认类型与字段已经可见。
  6. 此后才用 data_create_table / data_create_entry 创建 JSON-backed 表和条目,最后调用 data_save_and_generate。

如果用户明确选择纯代码开发,则不要继续上述图形化闭环:在具名 namespace 的 src/**/*.cs 中手写 [GameDataCategory] / [GameDataNodeType<T,V>] 的 public partial class,并在统一 GameData 初始化路径用 new GameData...(link) 注册具体条目。不要显式继承生成器负责的基类,不要手写 Link 构造器或生成接口,也不要再为同一条目创建 JSON-backed 定义。

如果当前 AI 工具只有 data_*,没有触发编辑器属性面板或能等价修改触发模型的能力,不要退化为手写 editor/trigger JSON,也不要擅自切换到纯代码路线;明确请用户在触发编辑器完成上述两个开关之一,再继续创建条目。触发器工具的保存和生成边界见 触发器编辑器 Skill。

优先选择 MCP ​

可扩展枚举与图形化选项 ​

当用户要扩展 ItemCategory 等可扩展枚举,并在数据编辑器的选项中使用时,先在触发编辑器公共页(Common)声明预设值类型,将其**“继承”**设置为目标预设值类型,再添加预设值。公共页让两端共用声明;保存后的权威源是触发器 JSON。仅手写 [EnumExtension] C# 并编译成功,不能替代图形化声明。

“继承”对应 EnumExtension.Extends;“是否可被继承”对应 Extendable,后者不能替代继承目标。通过 trigger_create_preset 导入时按 触发器 MCP Skill 创建并 trigger_save,确认生成代码仍包含目标 Extends,双端编译、加载最新声明后再用 data_* 选择新增值。不要用未知分类字符串、注释或手改 DataGenerated 掩盖声明缺失。图形化操作说明见 枚举扩展。

公共模板与基础定义 ​

创建样例单位、技能、Buff 或物品时,先用 data_list_templates 查 GameSparkCore 的适用模板并读取实际字段。通过 $inherit 继承,保留样例自己的模型、技能链和数值覆盖;基础生命值、单位属性、伤害类型等引用 GameSparkCore 的声明。通用能力缺少模板时应在公共库补充;不要从其它样例私有模板复制一套基础定义。该优先策略不限制项目自定义类型或专用数据。

模板表的 tableType 为 ScopeDataTemplate,普通实例表为 ScopeData。旧参数 Template 在新版 MCP 中作为兼容别名转换。创建后用 data_list_templates 验证可发现性,并保留编辑器生成的稳定 $id。

迁移继承后检查集合合并语义:模板已有的 Health/Mana 不要在本地 VitalProperties 再添加一次;保留有意覆盖,必要时使用正式删除/覆盖表达式。先 data_save_and_generate 加 validate;游戏项目需要运行验证时用正常 debug_start 编译双端并检查新局,依赖库或只验证编译时走下面的纯构建流程。不要手工改 Metadata、EntryInfo 或 DataGenerated 来掩盖源数据问题。

依赖库数据生成与编译 ​

在 GUI 或 Headless 中打开目标库,分别用 editor_get_context 或 headless_get_project_state 确认路径,再发现 build_start 的实际 schema。调用后使用返回的 build_id 查询 build_wait / build_status,以 succeeded 终态确认生成、双端 Debug 编译和 AppBundle 部署完成;失败时按同一 ID 读取 build_diagnostics,修复源数据、触发器或代码再重试。build_start_timeout 时先用返回的 operation_id 查询状态,避免重复任务。

此流程不启动游戏。依赖库直接调试会返回 dependency_library_requires_test_project;行为测试改用引用它的游戏项目,或已配置测试地图的菜单路线。不要用 debug_start_no_compile 绕过这个限制。仅需保存和生成数据时使用 data_save_and_generate。详细流程见只生成与编译。

如果编辑器或 MCP Host 正在运行,优先用 MCP:

  • ui_* 读取当前数据编辑器上下文;这需要完整 Editor MCP
  • data_* 读写 DataManager 表、条目、字段、继承状态
  • gamedata_* 查询 GameData 类型 schema,或生成 src/DataGenerated

Invoke-SceMcp.ps1 是 Trigger/Data 兼容 HTTP MCP 单次 tools/call 入口,可以调用 data_*、gamedata_*、trigger_* 等可由 TriggerMcpHost fallback 支持的工具。脚本在地图工程根的 ai/tools/ 下时可自动推断工程根;如果从 SDK 模板 docs/ai/tools/ 运行,需要传 -ProjectRoot 指向地图工程根。

如果要调用 ui_*,或需要 editor_get_context、tools/list schema 发现和完整编辑器诊断,使用 Invoke-SceEditorMcp.ps1:

powershell
.\ai\tools\Invoke-SceEditorMcp.ps1 -Context -Pretty
.\ai\tools\Invoke-SceEditorMcp.ps1 -Tool ui_get_editor_state -ArgumentsJson '{}' -Pretty

推荐调用方式:写一个临时 JSON,包含 baseUrl、tool、arguments,用 -RequestJsonPath 调脚本,最后删除临时文件。

powershell
$MapRoot = "D:\YourSceMap"
$McpScript = Join-Path $MapRoot 'ai\tools\Invoke-SceMcp.ps1'
$TempRequest = Join-Path $env:TEMP ("sce-data-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": "data_list_tables", "arguments": {} }
'@ | 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 }
}

成功返回时先看外层 result.isError。业务结果通常在 result.content[0].text,多数是 JSON 字符串。写操作不要并行;连续修改时等上一个工具返回后再调用下一个。

自然语言一键做完整地图 ​

MCP 工具必须保持通用。即使用户说“做一张某某玩法地图”,也不要新增玩法专用工具;AI 应该把自然语言拆成通用 plan,再调用通用 MCP:

  1. 读取上下文:ui_get_editor_state、data_list_tables、gamedata_list_types、trigger_get_api_schema
  2. 数据侧一键创建:workflow_create_map_from_plan
  3. 触发侧创建逻辑:trigger_create_folder、trigger_create_class、trigger_create_function、trigger_create_trigger
  4. 保存与生成:优先 data_save_and_generate;需要拆步时用 data_save、gamedata_generate_code、trigger_save
  5. 项目校验:gamedata_validate_project、trigger_validate_project

自然语言只负责描述目标玩法;MCP 参数里用通用字段表达:

  • contentRoot:本玩法的数据目录名,例如 AutoBattle1v1
  • tables:需要的 GameData 表规格
  • entries:单位、技能、配置、GameMode、生成器等条目规格
  • links / attachments:条目之间的字段引用和追加挂接
  • gameMode:玩法入口配置
  • save、generateCode、validate:是否保存、生成和校验

示例骨架:

json
{
  "tool": "workflow_create_map_from_plan",
  "arguments": {
    "contentRoot": "AutoBattle1v1",
    "entries": [
      {
        "kind": "unit",
        "entryName": "Footman",
        "displayName": "Footman",
        "stats": { "maxHp": 420, "attack": 18, "moveSpeed": 270 }
      },
      {
        "kind": "spawner",
        "entryName": "FootmanSpawner",
        "displayName": "Footman Spawner",
        "spawnEntries": ["Footman"],
        "spawnIntervalSeconds": 15,
        "spawnCount": 2
      },
      {
        "kind": "config",
        "entryName": "EconomyConfig",
        "category": "Config",
        "fields": { "InitialGold": 500, "IncomeIntervalSeconds": 10, "IncomeGold": 50 }
      }
    ],
    "gameMode": {
      "entryName": "AutoBattleMode",
      "displayName": "Auto Battle 1v1",
      "players": [{ "id": 1 }, { "id": 2 }],
      "teams": [{ "id": 1 }, { "id": 2 }]
    },
    "save": true,
    "generateCode": true,
    "validate": true
  }
}

如果某个玩法需要“兵营、商店、刷怪点、波次、经济”等概念,优先用 workflow_create_spawner、普通 kind: "config" 条目和 links 表达。不要把玩法名写进 MCP 工具名。

工具速查 ​

类别工具
UI 上下文ui_get_editor_state、ui_get_current_table、ui_get_selected_entry、ui_get_selected_field
表与条目查询data_list_tables、data_get_table、data_list_entries、data_get_entry
表与条目创建data_create_table、data_create_entry
模板与批量创建data_list_templates、data_create_from_template
字段级修改data_get_field、data_set_field、data_set_fields、data_insert_field、data_move_field、data_remove_field
继承与本地覆盖data_get_inherit、data_get_local_data、data_get_base_data、data_get_field_status、data_reset_field、data_reset_entry
GameData 类型与生成gamedata_list_types、gamedata_get_type_schema、gamedata_get_generated_symbols、gamedata_generate_code
Link、资源与引用data_list_link_candidates、data_find_references、data_resolve_entry_links、data_validate_links、resource_search
项目校验gamedata_validate_entry、gamedata_validate_project
制作人工作流workflow_create_content_folder、workflow_create_unit、workflow_create_ability、workflow_attach_ability_to_unit、workflow_create_spawner、workflow_create_game_mode、workflow_create_map_from_plan
触发器配合trigger_get_api_schema、trigger_create_folder、trigger_create_class、trigger_create_function、trigger_create_trigger、trigger_save、trigger_validate_project
删除与移动data_delete_entry、data_delete_table、data_move_table
保存与生成data_save、data_save_and_generate、gamedata_generate_code

data_update_entry 是危险工具:它会用完整 JSON 覆盖条目的本地数据。普通修改优先使用 data_set_field 或 data_set_fields。

data_save_and_generate 是修改数编后的首选收口工具:它会保存当前 DataManager 状态、可选校验项目、生成 src/DataGenerated,并返回保存状态、校验摘要、生成结果和文件变更摘要。完整编辑器已加载项目但数据编辑器面板未打开时,工具会自动加载当前项目的 DataManager;如果编辑器没有加载任何项目,会以 no_project_loaded 明确失败。只有需要先预览内存态生成、或刻意不保存源数据时,才单独调用 gamedata_generate_code 并设置 saveData。

标准工作流 ​

1. 用户说“当前选中”或“这里” ​

  1. ui_get_editor_state
  2. 需要条目时调用 ui_get_selected_entry
  3. 需要字段时调用 ui_get_selected_field
  4. 再用返回的 entryId / fieldPath 调 data_get_entry、data_get_field_status 或字段级写入工具

如果 editorOpen 为 false,说明当前会话拿不到数据编辑器 UI;改用 data_list_tables / data_list_entries 根据路径和类型定位。

2. 修改已有条目字段 ​

  1. data_get_entry 读取目标条目,确认 metaType、$inherit 与当前值
  2. gamedata_get_type_schema 查询该 metaType 的权威字段 schema
  3. 对继承字段先用 data_get_field_status 判断是 local、inherited 还是 default
  4. 小改用 data_set_field,多字段改动用 data_set_fields
  5. 运行时需要更新 ScopeData.* 时调用 data_save_and_generate
  6. 只需要保存源数据、不需要刷新运行时代码时调用 data_save

3. 创建新条目 ​

  1. data_list_tables 找到目标表,或用 data_get_table 确认表路径和类型
  2. gamedata_list_types / gamedata_get_type_schema 确认要创建的 GameData 类型和字段
  3. 找一个相近条目或模板:data_list_entries 后 data_get_entry
  4. 用 data_create_entry 创建,entryData 只放必要的 $type、$inherit 和少量初始字段
  5. 用 data_set_fields 补齐本地覆盖字段
  6. 需要刷新运行时代码时调用 data_save_and_generate;否则调用 data_save

不要为了复刻模板而把继承来的字段全部写成本地字段;这会破坏模板继承的维护价值。

普通 Link 字段在 JSON 中是字符串路径,不是 {"$ref": ...}。

  1. gamedata_get_type_schema 确认字段是否是 link,或看字段 schema 里的 jsonType: "link" / linkTargetType
  2. data_list_link_candidates 传 entryIdOrPath 和 fieldPath 获取合法候选
  3. 从候选的 value 中选择要写入的字符串
  4. 用 data_set_field 或 data_set_fields 写入
  5. 若要删除或替换目标条目,先对目标调用 data_find_references

常见 Link 字符串:

  • 同一蓝图文件内引用其他节点:$this.EntryName
  • 同库跨蓝图引用:相对逻辑路径或 $GameDataRule.DefaultDisplayInfo.Root
  • 跨库稳定引用:$id.EntryName

5. 处理继承与本地覆盖 ​

  1. data_get_inherit 查看继承链
  2. data_get_base_data 查看继承来的基础数据
  3. data_get_local_data 查看本地覆盖
  4. data_get_field_status 判断具体字段来源
  5. 想恢复继承值时用 data_reset_field
  6. 想清空全部本地覆盖时才用 data_reset_entry

data_remove_field 是删除本地字段;如果字段有继承值,通常应使用 data_reset_field。

6. 删除或移动前先查引用 ​

删除条目、删除表、移动表或替换 Link 目标前,先运行:

text
data_find_references -> 确认 referenceCount 为 0 或逐项处理引用 -> 再删除/移动 -> data_save_and_generate?

data_find_references 是字符串引用扫描,能发现常见 entryId、$this.EntryName、路径后缀和表路径引用。复杂脚本引用仍需要配合代码搜索。

类型定义与条目来源边界 ​

数编类型与数编条目是两层来源:

  • 类型结构来自触发编辑器定义生成的 src/TriggerGenerated/**,或纯代码项目维护的 src/**/*.cs;数据编辑器和 JSON 不能动态发明 CLR 类型

  • 静态数编条目有两种合法来源,应与所选类型 authoring 路线成套使用:

    • 图形化路线:editor/data/** 源数据,包括直接编辑 JSON 和通过 data_* MCP 修改
    • 纯代码路线:src/**/*.cs 代码注册,例如 OnGameDataInitialization 中 new GameDataUnit(...)

同一个静态 GameData 条目只能选择一种来源。不要把 JSON-backed 条目做成薄壳,再在代码里对 ScopeData.GameDataXxx.*.Data 做静态补丁。定义条目的 CLR 类型与用 JSON 创建该类型的条目并不冲突;前者定义 schema,后者提供具体值。

src/DataGenerated/** 只是生成投影,用来确认 ScopeData.* 名称和生成结果,不是主要维护入口。

编辑器派生元数据文件 ​

editor/data/** 里并不是所有 JSON 都是可手工维护的源数据。AI 修改数编时只把业务蓝图文件当作源数据,例如 ScopeData/**/SomeData.json 或 ScopeDataTemplate/**/SomeTemplate.json。

  • Metadata.json 是编辑器生成的文件级元数据,记录蓝图文件 ID、类型和文件引用依赖等索引信息。
  • EntryInfo.json 是编辑器生成的条目级缓存,记录 $hash、Name、DisplayName、Icon 等注册缓存字段,供数据编辑器列表、代码生成和检索使用。
  • 这些文件反映源数据的派生状态,不是新增条目、改字段、修 link 的 authoring 入口。
  • 不要为了“补齐”“整理”“修复引用”而手动编辑、复制或重写 Metadata.json / EntryInfo.json。
  • 如果这些文件在 data_save、data_save_and_generate、编辑器保存或 gamedata_generate_code 后产生 diff,通常应视为生成结果;如果是 AI 手改造成的 diff,应还原后让编辑器/MCP 重新保存生成。

$id 规则 ​

  • 这里的 $id 指 JSON 顶层蓝图文件 ID,不是 MCP 的 tableId 或 entryId
  • $id 标识整个蓝图文件,不是 Entry Name
  • AI 直接创建新的 JSON 文件且不确定 $id 格式时,优先省略 $id
  • 编辑器会在加载/保存时自动补合法且唯一的 $id
  • 已存在的 $id 不要轻易修改,因为其他蓝图文件可能通过 $id.EntryName 引用它

推荐顺序:

  1. 先创建新文件,不写 $id
  2. 让编辑器加载或保存一次,自动补全 $id
  3. 再读取实际 $id
  4. 最后再填写其他蓝图文件里的跨蓝图引用

直接写 JSON 时的最低约束 ​

只有 MCP 不可用、需要批量离线修改、或用户明确要求直接改 JSON 时,才直接编辑 editor/data/**/*.json。

  • 一个 JSON 文件对应一个蓝图文件;文件内有 Root、OtherEntry 等 Entry
  • Root、OtherEntry 等键名是 Entry Name
  • 同一蓝图内引用优先 $this.EntryName
  • 同库跨蓝图引用优先相对逻辑路径
  • 跨库稳定引用优先 $id.EntryName
  • $inherit 也是字符串路径
  • Metadata.json、EntryInfo.json、src/DataGenerated/** 是派生结果,不要手动维护

正确顺序通常是:修改源数据 -> 让编辑器或 MCP 保存 -> 运行现有生成链刷新派生物;MCP 场景优先用 data_save_and_generate 一步完成保存与生成。

常见错误 ​

  • 新建 JSON 时手写了错误格式的 $id
  • 修改已有 $id,却没有同步更新 $id.EntryName 引用
  • 把 data_get_entry 返回的展示性元数据当作源字段写回
  • 直接用 data_update_entry 全量覆盖,误删本地字段或继承关系
  • 给 Link 字段写 {"$ref": ...},而不是写字符串路径
  • 从 DataGenerated 反推错误模式,对 .Data 做静态 patch
  • schema 中没有类型或字段时,硬写未知 $type / 额外 JSON 字段
  • 纯代码路线忘记给自定义类型加 partial,或手写了生成器负责的父类和构造器
  • 同一个条目一部分放在 JSON,一部分又放进 OnGameDataInitialization