From 4441e67b10c520515bcc6683c8e6db25d9118f3d Mon Sep 17 00:00:00 2001 From: JOY Date: Wed, 20 May 2026 22:16:10 +0700 Subject: [PATCH] chore: add FunPlay Unity MCP setup --- .../funplay-unity-mcp-workflow/SKILL.md | 196 ++++++++++++++++++ Unity/.funplay/skills/manifest.json | 6 + Unity/AGENTS.md | 34 +++ Unity/Packages/manifest.json | 1 + Unity/Packages/packages-lock.json | 10 + 5 files changed, 247 insertions(+) create mode 100644 Unity/.codex/skills/funplay-unity-mcp-workflow/SKILL.md create mode 100644 Unity/.funplay/skills/manifest.json create mode 100644 Unity/AGENTS.md diff --git a/Unity/.codex/skills/funplay-unity-mcp-workflow/SKILL.md b/Unity/.codex/skills/funplay-unity-mcp-workflow/SKILL.md new file mode 100644 index 0000000..7436213 --- /dev/null +++ b/Unity/.codex/skills/funplay-unity-mcp-workflow/SKILL.md @@ -0,0 +1,196 @@ +--- +name: funplay-unity-mcp-workflow +description: Efficient workflow for using Unity MCP to edit, import, compile, inspect, and test Unity projects. +platform: codex +--- + + +# Unity MCP Workflow + +Use this skill when Codex or another AI agent is working in a Unity project and needs to verify code, prefabs, UI, Play Mode behavior, screenshots, scene hierarchy, console logs, domain reloads, or MCP connection issues. + +## Operating Loop + +1. Establish context. + - Confirm the Unity project root and active scene. + - Check that Unity MCP is reachable before assuming Editor state. + - Inspect hierarchy, prefab paths, selected objects, and relevant component references through MCP. + - If the user names an object, verify the real Unity object path before editing. +2. Choose the edit surface. + - Edit source files with normal repo tools, then trigger Unity recompilation. + - Edit scene objects through Unity APIs, mark the scene dirty, and save the scene. + - Edit prefab assets with `PrefabUtility.LoadPrefabContents`, `PrefabUtility.SaveAsPrefabAsset`, and `PrefabUtility.UnloadPrefabContents`. + - If the user is looking at an open scene instance, update the visible scene instance as well as the prefab asset when appropriate. +3. Execute changes. + - Prefer one well-guarded `execute_code` batch over many fragile UI clicks. + - Use null guards for every object lookup and return explicit missing-path messages. + - Return concise before/after values from snippets. + - Save only the assets or scenes intentionally modified. +4. Validate. + - Read back the changed objects through MCP. + - For file edits, call `request_recompile`, then `wait_for_compilation`, then inspect console or compilation errors. + - For runtime behavior, enter Play Mode or inspect live objects when needed. + - Report exactly what was verified and what still requires device, store, network, or manual validation. + +## Tool Exposure + +- With the default `core` profile, rely on the focused workflow tools: `execute_code`, recompilation, Play Mode control, hierarchy, console logs, screenshots, input simulation, and performance inspection. +- With the default `full` profile, prefer specific MCP tools for simple scene, asset, GameObject, component, prefab, camera, UI, package, animation, file, or visual-feedback operations. +- If Tool Exposure is customized and a named tool is unavailable, adapt to the exposed tool list and report which expected tool is missing. + +## MCP Call Pattern + +If native MCP tools are not directly available, probe the local HTTP endpoint: + +```bash +curl -sS -m 1 -X POST http://127.0.0.1:8765/mcp \ + -H 'Content-Type: application/json' \ + -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' +``` + +For multi-line `execute_code` calls over curl, generate JSON with a real encoder instead of hand-escaping C#: + +```bash +node - <<'NODE' +const code = String.raw` +using UnityEngine; + +public class InspectSomething +{ + public static string Run() + { + var obj = GameObject.Find("PracticeInGameUiRoot"); + return obj != null ? obj.name : "not found"; + } +} +`; +const payload = { + jsonrpc: "2.0", + id: 1, + method: "tools/call", + params: { name: "execute_code", arguments: { code } } +}; +process.stdout.write(JSON.stringify(payload)); +NODE +``` + +## Unity C# Patterns + +Use fully qualified types if the snippet environment or injected project code makes `using` statements unreliable: + +```csharp +var root = UnityEngine.GameObject.Find("PracticeInGameUiRoot"); +var rect = root.GetComponent(); +``` + +Use Unity null semantics for `UnityEngine.Object` references: + +```csharp +if (image == null) +{ + return "Image missing"; +} +``` + +For prefab edits: + +```csharp +var path = "Assets/MyGame/UI/Prefabs/PF_PracticeInGameUiRoot.prefab"; +var prefab = UnityEditor.PrefabUtility.LoadPrefabContents(path); +try +{ + var target = prefab.transform.Find("SafeArea/SwingCancelZone"); + if (target == null) + { + return "SwingCancelZone not found in prefab"; + } + + var rect = target.GetComponent(); + var before = rect.anchoredPosition; + rect.anchoredPosition = new UnityEngine.Vector2(-76f, 448f); + + UnityEditor.EditorUtility.SetDirty(rect); + UnityEditor.PrefabUtility.SaveAsPrefabAsset(prefab, path); + UnityEditor.AssetDatabase.SaveAssets(); + return "Prefab saved: pos " + before + " -> " + rect.anchoredPosition; +} +finally +{ + UnityEditor.PrefabUtility.UnloadPrefabContents(prefab); +} +``` + +For scene edits: + +```csharp +var obj = UnityEngine.GameObject.Find("PracticeInGameUiRoot/SafeArea/SwingCancelZone"); +if (obj == null) +{ + return "Scene object not found"; +} + +var rect = obj.GetComponent(); +var before = rect.sizeDelta; +UnityEditor.Undo.RecordObject(rect, "Update cancel zone"); +rect.sizeDelta = new UnityEngine.Vector2(220f, 116f); +UnityEditor.EditorUtility.SetDirty(rect); +UnityEditor.SceneManagement.EditorSceneManager.MarkSceneDirty(obj.scene); +UnityEditor.SceneManagement.EditorSceneManager.SaveScene(obj.scene); +return "Scene saved: size " + before + " -> " + rect.sizeDelta; +``` + +## Recompile And Reload + +After external C# or asset file edits: + +1. If Unity is in Play Mode, call `exit_play_mode` first - `request_recompile` is rejected during play because Unity does not run script compilation or domain reloads while playing. +2. Call `request_recompile`. +3. Call `wait_for_compilation`. +4. Read console or compilation errors before continuing. +5. If a domain reload drops the request, call `get_reload_recovery_status` when available, re-scan the MCP endpoint if needed, then continue from `wait_for_compilation`. + +Do not treat a disconnected request as a successful compile. + +After `enter_play_mode`, the HTTP server is briefly unreachable while Unity reloads the domain. Before issuing the next tool call, poll a cheap endpoint such as `tools/list` (or `get_reload_recovery_status` if exposed) until you get a response - do not assume the connection survives the Play Mode transition. + +## Verification Checklist + +Use readback snippets that print exact values, not only `success`: + +```csharp +var all = UnityEngine.Resources.FindObjectsOfTypeAll(); +UnityEngine.Transform target = null; +for (int i = 0; i < all.Length; i++) +{ + if (all[i].name == "SwingCancelZone") + { + target = all[i]; + break; + } +} + +if (target == null) +{ + return "SwingCancelZone not found"; +} + +var rect = target.GetComponent(); +return "path=" + target.name + "; pos=" + rect.anchoredPosition + "; size=" + rect.sizeDelta; +``` + +For UI work, verify prefab or scene hierarchy, sprite references, anchors, sorting order, active state, text fit, and button listeners. A populated `Content` hierarchy does not prove the user can see the UI. + +For gameplay or network work, verify object identity, ownership, live instance existence, transform values, animation state, visibility, and whether client-side filters are discarding valid data. + +## Failure Handling + +- If MCP is unreachable, say so and fall back only to safe filesystem inspection or code edits. Do not claim scene, prefab, or runtime verification without Unity readback. +- If an object lookup fails, inspect hierarchy and prefab contents instead of inventing a path. +- If multiple matching objects exist, print their paths and choose the one matching the user-visible UI or current scene. +- If compile errors appear after a change, fix them before Play Mode validation. +- When Unity and text files disagree for serialized scene or prefab state, trust Unity readback and inspect the asset path. + +## Metadata + +- Original skill id: `unity-mcp-workflow` +- Source repository: `https://github.com/FunplayAI/funplay-unity-mcp` diff --git a/Unity/.funplay/skills/manifest.json b/Unity/.funplay/skills/manifest.json new file mode 100644 index 0000000..23db3a7 --- /dev/null +++ b/Unity/.funplay/skills/manifest.json @@ -0,0 +1,6 @@ +{ + "platforms": [ + "codex" + ], + "optionalSkills": [] +} \ No newline at end of file diff --git a/Unity/AGENTS.md b/Unity/AGENTS.md new file mode 100644 index 0000000..c297bd2 --- /dev/null +++ b/Unity/AGENTS.md @@ -0,0 +1,34 @@ + + +# Funplay Unity MCP Project Guidance + +This file is managed by Funplay MCP for Unity. + +## Installed project skills + +- `funplay-unity-mcp-workflow` - Efficient workflow for using Unity MCP to edit, import, compile, inspect, and test Unity projects. + +## Codex workflow rules + +- Prefer project-local Funplay skills under `.codex/skills/`. +- Use `execute_code` as the primary Unity automation tool. For new snippets, implement `IFunplayCommand` and use `ctx.RegisterObjectCreation` / `RegisterObjectModification` / `DestroyObject` so changes participate in Undo automatically. +- Inspect Unity objects through MCP before changing user-named scene or prefab targets. Carry the returned `instanceId` into follow-up calls (`find_method=by_id`) instead of re-resolving by name. +- Tool returns are structured JSON (`{success, message, data}` / `{success: false, code, error, data}`). Branch on `code`, not free-form text. +- Set component fields with `set_component_property(ies)` - it picks up `[SerializeField] private` fields and accepts Object references as `{"fileID": }` or `{"assetPath": "Assets/..."}`. +- Read editor state through dedicated tools (`get_selection`, `get_prefab_stage`, `get_tags`, `get_layers`, `get_build_settings`); use `execute_menu_item` before falling back to ad-hoc `execute_code`. +- Save only the scene or prefab assets intentionally modified, then read back exact values. +- With default `core` exposure, use the focused workflow tools. With default `full` exposure, prefer specific MCP tools for simple editor operations. +- `execute_code` refreshes the asset database and waits for compilation before running. For other tools that depend on freshly compiled code, still call `request_recompile` after external script edits. +- `request_recompile` is rejected while Unity is in Play Mode. Call `exit_play_mode` first, then retry. +- After `enter_play_mode`, the HTTP server briefly drops while Unity reloads the domain. Poll `tools/list` or `get_reload_recovery_status` until it responds again before issuing the next tool call. +- If recompilation triggers a domain reload, call `get_reload_recovery_status`. +- Avoid changing `Library/`, `Temp/`, `Logs/`, or `obj/`. + +## Project + +- Project root: `D:\Projects\Second-Spawn\Unity` +- Product name: `Second Spawn` + +## Notes + +- Re-run `Funplay > Project Skills` after changing selected skills or platforms. diff --git a/Unity/Packages/manifest.json b/Unity/Packages/manifest.json index 1f5221e..8bde39e 100644 --- a/Unity/Packages/manifest.json +++ b/Unity/Packages/manifest.json @@ -1,6 +1,7 @@ { "dependencies": { "com.coplaydev.unity-mcp": "https://github.com/CoplayDev/unity-mcp.git?path=/MCPForUnity#main", + "com.gamebooom.unity.mcp": "https://github.com/FunplayAI/funplay-unity-mcp.git", "com.unity.ai.assistant": "2.8.0-pre.1", "com.unity.ai.inference": "2.6.1", "com.unity.ai.navigation": "2.0.12", diff --git a/Unity/Packages/packages-lock.json b/Unity/Packages/packages-lock.json index b2962c6..5cc3183 100644 --- a/Unity/Packages/packages-lock.json +++ b/Unity/Packages/packages-lock.json @@ -10,6 +10,16 @@ }, "hash": "b92c05a25820cfc9f59ce4094eb46aaec8632ea2" }, + "com.gamebooom.unity.mcp": { + "version": "https://github.com/FunplayAI/funplay-unity-mcp.git", + "depth": 0, + "source": "git", + "dependencies": { + "com.unity.nuget.newtonsoft-json": "3.2.1", + "com.unity.inputsystem": "1.7.0" + }, + "hash": "b600f4e2b1d3a80a2558f4ce804055d120877952" + }, "com.unity.2d.sprite": { "version": "1.0.0", "depth": 1,