mcpField
U
unity-editor

unity-editor

github.com/besty0728开发1.9k94 次安装今天更新
代码仓库

关于 unity-editor

unity-editor 是一组用于观察和控制 Unity Editor 的技能,适合检查场景变更、运行时状态和编辑器操作。它提供变更日志与 Play Mode 控制,并避免解析原始场景 YAML。

主要功能

  1. 01读取场景与文件变更日志
  2. 02查看编辑器上下文和状态
  3. 03控制 Play Mode 与逐帧推进
  4. 04检查 GameObject 运行时状态
  5. 05选择对象、撤销和重做
  6. 06执行菜单项并查询标签与图层

适用场景

  1. 01恢复工作时先检查 Unity 中的持久化变更
  2. 02运行场景并查看对象组件状态
  3. 03逐帧推进 Play Mode 以验证行为
  4. 04查找编辑器菜单命令或当前选择

MCP 相关

README 未说明其与 MCP 的关系。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/besty0728/unity-skills --skill unity-editor

安装后在 Claude Code 中输入/unity-editor确认已加载。

详细介绍

**调用本模块中的任何技能前:**如果你准备根据技能名称或描述猜测参数后调用技能,请停止——先阅读此文件(或通过 GET /skills/recommend?includeSchema=true 获取其 schema)。如果你已经从 recommend/schema 获取了参数定义,则可直接进行 dryRun。

触发条件

  • 读取持久化场景/文件变更
  • 操控 Play 模式
  • 检查运行时状态
  • 执行菜单项
  • 读取持久化场景/文件变更、操控 Play Mode、检查运行时状态、执行菜单项

Unity Editor 技能

观察并操控 Unity Editor,无需解析场景 YAML。

运行模式

  • Approval:本模块 Mixed —— editor_get_changes / editor_get_selection / editor_get_context / editor_get_state / editor_get_tags / editor_get_layers / editor_playmode_inspect 标 SkillMode.SemiAuto,可直接执行;其余 editor_select / editor_undo / editor_redo / editor_playmode_step 默认 FullAuto,Approval 模式下需 grant。
  • Auto / Bypass:FullAuto 直接执行。
  • 含 NeverInSemi 高危 skill:editor_play / editor_play_capture / editor_stop / editor_pause(标 MayEnterPlayMode = true);editor_run_scenario(标 MayEnterPlayMode = true、MayTriggerReload = true、RiskLevel = "high");editor_execute_menu(标 MayTriggerReload = true —— Assets/Refresh、Assets/Reimport All 之类的菜单项会触发域重载)。这些在 Approval 和 Auto 下都返 MODE_FORBIDDEN,仅 Bypass 或 Allowlist 命中可调;grant 流程对它们不适用,不要尝试。

不要(常见幻觉):

  • editor_run 不存在 → 使用 editor_play 进入 Play 模式
  • editor_compile / editor_recompile 不存在 → 使用 debug_force_recompile
  • editor_save 不存在 → 使用菜单路径为 "File/Save" 的 editor_execute_menu
  • editor_execute_menu 需要精确的菜单路径——拼写错误会导致静默失败

路由:

  • 检查编译情况 → 使用 debug 模块的 debug_check_compilation
  • 查看控制台错误 → 使用 debug 模块的 debug_get_errors
  • 保存场景 → 使用 scene_save(scene 模块)或菜单路径为 "File/Save" 的 editor_execute_menu
  • 文件监视报告变更时,或 AI 在用户编辑 Unity 后恢复运行时 → 在读取 .unity YAML 前调用 editor_get_changes
  • 如果 editor_get_changes.dropped=true → 已超出 500 条目的保留窗口;使用 scene_context / scene_diff 重建上下文

技能概览

技能描述
editor_play进入 Play 模式
editor_play_capture观察运行时错误,可选择截图,然后退出
editor_stop退出 Play 模式
editor_pause切换暂停状态
editor_playmode_step将 Play Mode 前进 N 帧(异步任务)
editor_playmode_inspect检查 GameObject 的实时运行时状态(变换、组件字段)
editor_run_scenario将 invoke / read / assert / wait 步骤作为一个异步验证任务运行(参见“运行时验证场景”)
editor_select选择 GameObject
editor_get_selection获取所选对象
editor_get_context获取完整的编辑器上下文(所选对象、资源、场景)
editor_get_changes根据游标读取持久化场景/文件变更
editor_undo撤销上一个操作
editor_redo重做上一个操作
editor_get_state获取编辑器状态
editor_execute_menu执行菜单项
editor_get_tags获取所有标签
editor_get_layers获取所有层
console_set_pause_on_error出错时暂停 Play 模式(console 模块)

技能

editor_play

进入 Play 模式。警告:退出时,Play 模式期间所做的任何未保存场景变更都将丢失。

返回:{success, mode, jobId} —— mode="playing";返回的 jobId 来自 AsyncJobService,调用方可据此轮询 entering_play_mode 的完成状态。

editor_play_capture

进入 Play Mode,观察错误 durationSeconds 秒(默认值为 10,范围为 1–300),可选择捕获 Game View,然后退出。返回一个 Job,其结果包含 healthy、错误汇总、stoppedEarly 和 screenshotPath。

editor_stop

退出播放模式。

返回:{success, mode} — mode="stopped"。

editor_pause

切换暂停状态。

返回:{success, paused} — paused 是新的布尔状态。

editor_playmode_step

使用 EditorApplication.Step 将播放模式向前推进 frames 帧(1–100,默认值为 1)。Unity 会在步进过程中自动进入暂停状态。要求播放模式已处于活动状态——请先调用 editor_play 或 editor_play_capture,否则会返回结构化错误(error + hint + suggestedSkills: ["editor_play", "editor_play_capture"])。同一时间只能有一个步进任务在运行;如果上一个任务仍在运行时再次调用,会返回一条包含活动 jobId 的错误。

参数类型必填默认值描述
framesint否1要推进的帧数,限制在 1–100

以异步任务运行,而非同步运行:EditorApplication.Step() 只会在之后的 Editor tick 中生效,因此该技能每次只发出一次 Step() 调用,通过观察 Time.frameCount 增加来确认步进已生效,然后才发出下一次调用——未确认就连续调用 Step() 并不可靠。调用本身会立即返回:{success, status: "accepted", jobId, framesRequested}。

使用返回的 jobId 轮询 job_status,直到 status="completed";此时其 details 包含 {framesRequested, framesCompleted, frameCount, isPaused}。不要使用 job_wait——与 playmode/play_capture 一样,此任务的进度依赖 EditorApplication.update tick,而 job_wait 的阻塞循环运行在这些 tick 所在的同一主线程上,因此无法观察进度;它只会白白耗尽整个超时时间。如果退出播放模式,或 Unity 在 10s 内未能推进帧,任务会以 failed_exited_play_mode / failed_step_timeout 失败。

editor_playmode_inspect

检查 GameObject 的实时运行时状态:变换(位置/旋转/缩放)、activeSelf/activeInHierarchy,以及(给出 componentType 时)该组件的公共字段和属性(复用与 component_get_properties 相同的反射辅助程序,而非重新实现)。可在播放模式下使用,包括暂停时;也可在编辑模式下使用,此时返回编辑器时的值——请检查响应中的 isPlaying/isPaused,以了解这些值反映的是哪种状态。

参数类型必填描述
namestring否*对象名称
instanceIdint否*实例 ID(首选)
pathstring否*对象路径
componentTypestring否组件类型名称;设置后还会返回其公共字段/属性

*必须提供一个标识符

返回:{success, gameObject, entityId, instanceId, path, activeSelf, activeInHierarchy, transform: {position, localPosition, rotation, localScale}, isPlaying, isPaused, component}。如果省略 componentType,component 为 null;如果找不到该类型或该组件未附加,则为错误对象;否则为 {gameObject, component, fullTypeName, properties, fields}(形状与 component_get_properties 相同)。

editor_select

选择一个 GameObject。

参数类型必填描述
namestring否*对象名称
instanceIdint否*实例 ID(首选)
pathstring否*对象路径

*必须提供一个标识符

editor_get_selection

获取当前选中的对象。

返回:{count, objects: [{name, instanceId}]}

editor_get_context

获取完整的编辑器上下文,包括选中内容、资源和场景信息。

参数类型必填默认值描述
includeComponentsbool否false包含组件列表
includeChildrenbool否false包含子对象信息

返回值:

  • selectedGameObjects:层级视图中的对象(instanceId、path、tag、layer)
  • selectedAssets:项目窗口中的资源(GUID、path、type、isFolder)
  • activeScene:当前场景信息(name、path、isDirty)
  • focusedWindow:当前聚焦的编辑器窗口名称
  • isPlaying、isCompiling:编辑器状态
editor_get_changes

读取持久化变更日志 Library/UnitySkills/editor_changes.jsonl。日志记录场景对象/组件/属性摘要,以及跨域重载导入、删除和移动的资源路径。它不会解析或返回原始 .unity YAML。

参数类型必填默认值描述
sincelong否0上次响应的游标;0 表示读取保留的历史记录
typesstring否all逗号分隔的 scene、file、undo 或 lifecycle
sourcestring否alleditor/manual、rest 或 all
limitint否100要返回的最新条目数,范围为 1-500

返回值: {hasChanges, cursor, oldestSeq, dropped, truncated, changes}。保存 cursor 以供下次调用。dropped=true 表示较早的变更已超出 500 条日志的保留范围,因此需要重建完整的场景上下文。

editor_undo

撤销上一个操作。

editor_redo

重做上一个已撤销的操作。

editor_get_state

获取当前编辑器状态。

返回值:{isPlaying, isPaused, isCompiling, timeSinceStartup, unityVersion, platform}

editor_execute_menu

执行菜单命令。

参数类型必填描述
menuPathstring是菜单项路径

常用菜单路径:

菜单路径操作
File/Save保存当前场景
File/Build Settings...打开构建设置
Edit/Play切换播放模式
GameObject/Create Empty创建空对象
Window/General/Console打开控制台
Assets/Refresh刷新资源
editor_get_tags

获取所有可用标签。

返回值:{tags: [string]}

editor_get_layers

获取所有可用层。

返回值:{layers: [{index, name}]}

出错时暂停

出错时暂停由控制台模块提供,而非编辑器模块。

使用 console/SKILL.md 中的 console_set_pause_on_error。


使用示例

import unity_skills

# Check editor state before operations
state = unity_skills.call_skill("editor_get_state")
if state['isCompiling']:
    print("Wait for compilation to finish")

# On resume or after file-watch notification, inspect semantic changes first.
changes = unity_skills.call_skill("editor_get_changes", since=last_cursor)
last_cursor = changes["cursor"]

# Get full context (useful for understanding current state)
context = unity_skills.call_skill("editor_get_context", includeComponents=True)
for obj in context['selectedGameObjects']:
    print(f"Selected: {obj['name']} (ID: {obj['instanceId']})")

# Select and operate on object
unity_skills.call_skill("editor_select", name="Player")
selection = unity_skills.call_skill("editor_get_selection")

# Safe experimentation with undo
unity_skills.call_skill("gameobject_delete", name="TestObject")
unity_skills.call_skill("editor_undo")  # Restore if needed

# Execute menu command
unity_skills.call_skill("editor_execute_menu", menuPath="File/Save")

# Step through Play Mode frame-by-frame and assert state changed
import time

# Enter Play Mode with a generous observation window so there's time left to step
capture = unity_skills.call_skill("editor_play_capture", durationSeconds=30)
while True:
    capture_status = unity_skills.call_skill("job_status", jobId=capture["jobId"])
    if capture_status["currentStage"] not in ("entering_play_mode", "domain_reload_recovery"):
        break  # Play Mode has been entered; capture_status["currentStage"] == "observing"
    time.sleep(0.2)

before = unity_skills.call_skill("editor_playmode_inspect", name="Player")["transform"]["position"]

step = unity_skills.call_skill("editor_playmode_step", frames=3)
while True:
    step_status = unity_skills.call_skill("job_status", jobId=step["jobId"])  # not job_wait, see above
    if step_status["status"] in ("completed", "failed"):
        break
    time.sleep(0.1)

after = unity_skills.call_skill("editor_playmode_inspect", name="Player")["transform"]["position"]
assert after != before, "Player did not move after 3 frames"
print(step_status["details"]["frameCount"], step_status["details"]["isPaused"])

最佳实践

  1. 在执行播放模式操作前检查编辑器状态
  2. 不要在播放模式下修改场景(变更会丢失)
  3. 使用撤销功能安全地进行试验
  4. 恢复后,在读取场景文件前调用 editor_get_changes
  5. 使用 editor_get_context 获取用于批量操作的 instanceId
  6. 菜单命令必须与路径完全一致

精确签名

精确的名称、参数、默认值和返回值由 GET /skills/schema 或 unity_skills.get_skill_schema() 定义,而非本文件。

常见错误

完整的传输层错误代码(COMPILING/RATE_LIMIT 等)→ ../../references/protocol-error-codes.md

错误触发条件修复方法
TARGET_NOT_FOUND找不到请求的 GameObject 或菜单项(例如,Menu item not found or failed)。使用 gameobject_find / scene_get_hierarchy 验证对象,或检查菜单路径拼写是否完全正确后重试。
SKILL_ERROR播放模式状态发生冲突,例如 Already in play mode、Not in play mode,或已有活动的逐帧步进任务。使编辑器状态符合技能要求:先进入/退出播放模式,或等待现有的步进任务完成。

运行时验证场景

editor_run_scenario 接受 steps(JSON 数组字符串,1–100 个条目)、executionMode(默认值为 play,也可显式指定 edit)和 timeoutSeconds(1–600,默认值为 60)。它会返回一个已持久化的 run_scenario 任务。至少需要一个 assert 或 wait_condition。DryRun 会验证结构和步骤技能元数据,但不会进入 Play Mode 或调用代码;每个实际步骤仍会通过 SkillRouter,并遵循其自身权限。调用步骤目前仅接受 component_invoke_method;其他会改变生命周期的技能和嵌套场景均会被拒绝。

步骤形式:

  • {"kind":"invoke","skill":"component_invoke_method","args":{...}}:调用一次并等待其任务完成。调用参数中的 executionMode 应与场景一致。
  • {"kind":"read","skill":"component_get_properties","args":{...}}:运行声明为 ReadOnly 的技能,并保留其结果。
  • {"kind":"assert","expected":42,"select":"returnValue","tolerance":0.01}:比较上一步的结果;也可以提供 ReadOnly skill 和 args,立即读取。select 是相对于响应数据的可选 JSONPath。即使 expected 为 null,路径不存在也会导致失败。数值容差会递归应用于匹配的数组或对象。
  • {"kind":"wait_frames","frames":2} 或 {"kind":"wait_seconds","seconds":0.5}:等待期间不会阻塞 Editor。帧数等待使用实际的 Play 帧计数器;秒数等待使用墙上时钟时间。暂停的 Play Mode 无法推进帧数等待,Edit Mode 的帧数等待应为零。
  • {"kind":"wait_condition","skill":"component_get_properties","args":{...},"select":"...","expected":true}:重复进行 ReadOnly 观察,直到匹配或场景期限到期。

从 Edit Mode 启动的场景会进入 Play Mode,并在之后退出。从 Play Mode 启动的场景会保持该模式。场景会临时启用 Application.runInBackground,并在成功、失败或取消时恢复其原始值。在进入或退出 Play Mode 时发生域重载,会恢复生命周期清理;已经分派的调用会被中断,不会重放。任意调用都属于高风险操作,不保证支持 Undo 或原子性。

持续轮询任务,直到其进入终止状态。只有在断言成功、没有运行时 Error/Exception/Assert 日志且日志覆盖完整时,resultData.passed 才为 true。steps 包含 actual、expected、tolerance 和 passed;logWindow 和 compilation 会保留证据。运行时错误、日志覆盖缺失、编译待处理、异常、目标缺失和超时都会导致验证失败。取消或超时不保证任意用户代码已停止。在场景外修复源代码,等待编译和重载完成,然后显式提交新的验证任务;绝不要悄悄重放失败的调用。

对于 AI 客户端有限次数的“编译 → 场景 → 修复 → 重跑”循环,请使用运行时验证与有界修复。随附的辅助程序接受调用方提供的修复回调,并将修复次数限制为最多三次、耗时不超过三十分钟。

评论

支持 Markdown