这里我直接把整条链路补齐成一个“最小但完整”的 Editor Agent 示例,不留“这玩意哪来的”的坑,只给必要结构,不发散。
目标结构(你脑子里应该是这个):
UnityCommands/ ├── pending/ │ └── {id}.json └── result/ └── {id}.json
Editor/ ├── UnityCommandListener.cs ├── UnityCommandExecutor.cs ├── UnityCommandRouter.cs ├── UnityCommandModels.cs └── Commands/ └── SetPlayerSpeedCommand.cs
1️⃣ Command 模型(UnityCommandModels.cs) using System
[Serializable] public class UnityCommand { public string id public string type public string payload }
[Serializable] public class UnityCommandResult { public string id public bool success public string message }
这里的 payload 是字符串,避免 JsonUtility 嵌套限制,后面每个命令自己反序列化。
2️⃣ Listener(UnityCommandListener.cs) using UnityEditor using System.IO
[InitializeOnLoad] public static class UnityCommandListener { static FileSystemWatcher watcher
static UnityCommandListener()
{
var path = Path.GetFullPath("UnityCommands/pending")
Directory.CreateDirectory(path)
watcher = new FileSystemWatcher(path, "*.json")
watcher.NotifyFilter = NotifyFilters.FileName | NotifyFilters.LastWrite
watcher.Created += OnChanged
watcher.EnableRaisingEvents = true
}
static void OnChanged(object sender, FileSystemEventArgs e)
{
EditorApplication.delayCall += () =>
{
UnityCommandExecutor.Execute(e.FullPath)
}
}
}
3️⃣ Executor(UnityCommandExecutor.cs) using System.IO using UnityEditor using UnityEngine
public static class UnityCommandExecutor { public static void Execute(string pendingPath) { if (!File.Exists(pendingPath)) return
var json = File.ReadAllText(pendingPath)
var command = JsonUtility.FromJson<UnityCommand>(json)
var result = UnityCommandRouter.Route(command)
var resultDir = "UnityCommands/result"
Directory.CreateDirectory(resultDir)
var resultPath = $"{resultDir}/{command.id}.json"
File.WriteAllText(resultPath, JsonUtility.ToJson(result, true))
AssetDatabase.Refresh()
}
}
4️⃣ Router(UnityCommandRouter.cs) public static class UnityCommandRouter { public static UnityCommandResult Route(UnityCommand command) { return command.type switch { "set_player_speed" => SetPlayerSpeedCommand.Execute(command), _ => new UnityCommandResult { id = command.id, success = false, message = "Unknown command" } } } }
5️⃣ 一个具体命令实现(Commands/SetPlayerSpeedCommand.cs) using UnityEngine
[System.Serializable] public class SetPlayerSpeedPayload { public float speed }
public static class SetPlayerSpeedCommand { public static UnityCommandResult Execute(UnityCommand command) { var payload = JsonUtility.FromJson(command.payload)
var config = Resources.Load<PlayerConfig>("PlayerConfig")
if (config == null)
{
return new UnityCommandResult
{
id = command.id,
success = false,
message = "PlayerConfig not found"
}
}
config.moveSpeed = payload.speed
return new UnityCommandResult
{
id = command.id,
success = true,
message = "Player speed updated"
}
}
}
6️⃣ AI 侧生成的 pending JSON 示例(真实可用) { "id": "cmd_001", "type": "set_player_speed", "payload": "{"speed":6.5}" }
7️⃣ Unity 生成的 result JSON 示例 { "id": "cmd_001", "success": true, "message": "Player speed updated" }
8️⃣ 这套结构在工程层面的“真实身份”
你现在看到的不是零散脚本,而是:
Listener:消息入口
Executor:事务边界
Router:命令分发表
Command:可独立测试的 Editor 行为
result.json:机器可读反馈
👉 这是一个标准 Editor Command Bus
9️⃣ 你现在已经具备的能力
到这一步,你已经可以:
无限制加新命令(只加一个 class)
让 AI “学会”你的命令协议
把 Unity 当成一个可被 AI 驱动的 IDE
如果你愿意,下一步我可以直接帮你:
把 payload 改成 schema 校验 + 强类型
加 Undo / DryRun / Validation
或把它升级成一个 Unity Editor Package