feat: establish mech extraction prototype with bilingual UI
Track Unity source, scenes, editable assets, licenses, tools and QA evidence. Exclude generated caches, Windows builds and raw runtime logs.
This commit is contained in:
@@ -0,0 +1 @@
|
||||
[{"tool":"manage_build","arguments":{"action":"build","target":"windows64","output_path":"D:/vibeCoding/unityRouge/Builds/Windows/x64/Prototype/Ironspore.exe","scenes":"Assets/Scenes/Bootstrap.unity,Assets/Scenes/MechTestRange.unity,Assets/Scenes/WarzonePrototype.unity","development":"true","scripting_backend":"mono"}}]
|
||||
@@ -0,0 +1 @@
|
||||
[{"tool":"manage_build","arguments":{"action":"status"}}]
|
||||
@@ -0,0 +1 @@
|
||||
[{"tool":"execute_code","arguments":{"action":"execute","code":"UnityEngine.Application.runInBackground = true; UnityEditor.EditorWindow.GetWindow(System.Type.GetType(\"UnityEditor.GameView,UnityEditor\")).Focus(); return MCPForUnity.Editor.Tools.ManageScene.HandleCommand(Newtonsoft.Json.Linq.JObject.Parse(\"{\\\"action\\\":\\\"screenshot\\\",\\\"fileName\\\":\\\"hangar.png\\\",\\\"outputFolder\\\":\\\"Docs/QA/Prototype/Screenshots\\\"}\"));"}}]
|
||||
@@ -0,0 +1,4 @@
|
||||
[
|
||||
{"tool":"manage_packages","arguments":{"action":"get_package_info","package":"com.unity.inputsystem"}},
|
||||
{"tool":"refresh_unity","arguments":{"mode":"force","scope":"all","compile":"request","wait_for_ready":false}}
|
||||
]
|
||||
@@ -0,0 +1 @@
|
||||
[{"tool":"read_console","arguments":{"action":"get","types":["error","warning"],"count":15,"include_stacktrace":false}}]
|
||||
@@ -0,0 +1,4 @@
|
||||
[
|
||||
{"tool":"manage_scene","arguments":{"action":"get_active"}},
|
||||
{"tool":"manage_packages","arguments":{"action":"add_package","package":"[email protected]"}}
|
||||
]
|
||||
@@ -0,0 +1,4 @@
|
||||
[
|
||||
{"tool":"manage_editor","arguments":{"action":"stop"}},
|
||||
{"tool":"execute_code","arguments":{"action":"execute","code":"var importer=UnityEditor.AssetImporter.GetAtPath(\"Assets/Game/Art/Models/Mechs/Mech_Scout_A.fbx\") as UnityEditor.ModelImporter; importer.globalScale=100; importer.SaveAndReimport(); UnityEditor.AssetDatabase.ImportAsset(\"Assets/Game/UI/GameTheme.tss\",UnityEditor.ImportAssetOptions.ForceUpdate); var theme=UnityEditor.AssetDatabase.LoadMainAssetAtPath(\"Assets/Game/UI/GameTheme.tss\"); return new { themeType=theme==null ? \"null\" : theme.GetType().FullName, input=UnityEditor.AssetDatabase.LoadMainAssetAtPath(\"Assets/Game/Input/GameInput.inputactions\").GetType().FullName };"}}
|
||||
]
|
||||
@@ -0,0 +1 @@
|
||||
[{"tool":"execute_code","arguments":{"action":"execute","code":"var result = Ironspore.Editor.PrototypeBuilder.Generate(); var assets = UnityEditor.AssetDatabase.LoadAllAssetsAtPath(\"ProjectSettings/ProjectSettings.asset\"); var so = new UnityEditor.SerializedObject(assets[0]); var prop = so.FindProperty(\"activeInputHandler\"); var before = prop.intValue; prop.intValue = 2; so.ApplyModifiedPropertiesWithoutUndo(); UnityEditor.AssetDatabase.SaveAssets(); return new { result = result, inputBackendBefore = before, inputBackendAfter = prop.intValue, model = UnityEditor.AssetDatabase.LoadAssetAtPath<UnityEngine.GameObject>(\"Assets/Game/Prefabs/Mechs/Mech_Scout_A.prefab\").GetComponentsInChildren<UnityEngine.Renderer>().Length };"}}]
|
||||
@@ -0,0 +1 @@
|
||||
[{"tool":"execute_code","arguments":{"action":"execute","code":"var model=UnityEngine.GameObject.Find(\"HangarChassis_1\"); var renderers=model.GetComponentsInChildren<UnityEngine.Renderer>(); var b=new UnityEngine.Bounds(model.transform.position,UnityEngine.Vector3.zero); foreach(var r in renderers)b.Encapsulate(r.bounds); var g=Ironspore.GameSession.Active; return new { bounds=b.ToString(), rootScale=model.transform.localScale.ToString(), first=renderers[0].transform.lossyScale.ToString(), firstCenter=renderers[0].bounds.center.ToString(), theme=g.uiPanel!=null, cameras=UnityEngine.Object.FindObjectsByType<UnityEngine.Camera>().Length };"}}]
|
||||
@@ -0,0 +1 @@
|
||||
[{"tool":"execute_code","arguments":{"action":"execute","code":"var d=Ironspore.GameSession.Active.GetComponent<UnityEngine.UIElements.UIDocument>(); var e=UnityEngine.UIElements.UQueryExtensions.Q<UnityEngine.UIElements.VisualElement>(d.rootVisualElement,null,\"crosshair\"); return new { bounds=e.worldBound.ToString(), parent=e.parent.worldBound.ToString(), visible=e.visible, childBounds=e[0].worldBound.ToString(), color=e[0].resolvedStyle.backgroundColor.ToString() };"}}]
|
||||
@@ -0,0 +1 @@
|
||||
[{"tool":"manage_build","arguments":{"action":"build","target":"windows64","output_path":"D:/vibeCoding/unityRouge/Builds/Windows/x64/Localization/Ironspore.exe","scenes":"Assets/Scenes/Bootstrap.unity,Assets/Scenes/MechTestRange.unity,Assets/Scenes/WarzonePrototype.unity","development":"true","scripting_backend":"mono"}}]
|
||||
@@ -0,0 +1 @@
|
||||
[{"tool":"execute_code","arguments":{"action":"execute","code":"UnityEngine.Application.runInBackground = true; UnityEditor.EditorWindow.GetWindow(System.Type.GetType(\"UnityEditor.GameView,UnityEditor\")).Focus(); return MCPForUnity.Editor.Tools.ManageScene.HandleCommand(Newtonsoft.Json.Linq.JObject.Parse(\"{\\\"action\\\":\\\"screenshot\\\",\\\"fileName\\\":\\\"hangar-initial.png\\\",\\\"outputFolder\\\":\\\"Docs/QA/Localization/Screenshots\\\"}\"));"}}]
|
||||
@@ -0,0 +1 @@
|
||||
[{"tool":"execute_code","arguments":{"action":"execute","code":"return Ironspore.Editor.LocalizationBuilder.Configure();"}}]
|
||||
@@ -0,0 +1 @@
|
||||
[{"tool":"execute_code","arguments":{"action":"execute","code":"return new { methods = typeof(UnityEngine.TextCore.Text.FontAsset).GetMethods().Where(x => x.Name == \"CreateFontAsset\" || x.Name == \"TryAddCharacters\").Select(x => x.ToString()).ToArray(), properties = typeof(UnityEngine.UIElements.PanelTextSettings).GetProperties().Select(x => x.ToString()).ToArray(), weights = typeof(UnityEngine.TextCore.Text.FontAsset).GetProperties().Where(x => x.Name.Contains(\"Weight\") || x.Name.Contains(\"Atlas\") || x.Name.Contains(\"sourceFont\")).Select(x => x.ToString()).ToArray(), font = UnityEditor.AssetDatabase.LoadAssetAtPath<UnityEngine.Font>(\"Assets/ThirdParty/Adobe/NotoSansSC/NotoSansSC-VF.ttf\") != null };"}}]
|
||||
@@ -0,0 +1 @@
|
||||
[{"tool":"execute_code","arguments":{"action":"execute","code":"var asm = typeof(UnityEditor.Editor).Assembly; var type = asm.GetType(\"UnityEditor.GameView\"); var view = UnityEditor.EditorWindow.GetWindow(type); var flags = System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Static; var enumType = asm.GetType(\"UnityEditor.GameViewSizeGroupType\"); var values = System.Enum.GetValues(enumType).Cast<object>().Select(x => x.ToString() + \"=\" + (int)x).ToArray(); var groups = type.GetProperties(flags).Where(x => x.Name.ToLower().Contains(\"group\")).Select(x => x.Name + \"=\" + x.GetValue(view, null)).ToArray(); return string.Join(\"; \", values) + \" | \" + string.Join(\"; \", groups) + \" | render=\" + type.GetProperty(\"targetRenderSize\",flags).GetValue(view,null) + \" | selected=\" + type.GetProperty(\"selectedSizeIndex\",flags).GetValue(view,null) + \" | screen=\" + UnityEngine.Screen.width + \"x\" + UnityEngine.Screen.height;"}}]
|
||||
@@ -0,0 +1 @@
|
||||
[{"tool":"execute_code","arguments":{"action":"execute","code":"var asm = typeof(UnityEditor.Editor).Assembly; var sizes = asm.GetType(\"UnityEditor.GameViewSizes\"); var singleton = typeof(UnityEditor.ScriptableSingleton<>).MakeGenericType(sizes); var instance = singleton.GetProperty(\"instance\").GetValue(null, null); var group = sizes.GetMethod(\"GetGroup\").Invoke(instance, new object[] { System.Enum.ToObject(asm.GetType(\"UnityEditor.GameViewSizeGroupType\"), 0) }); return new { sizeConstructors = asm.GetType(\"UnityEditor.GameViewSize\").GetConstructors(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).Select(x => x.ToString()).ToArray(), groupMethods = group.GetType().GetMethods().Select(x => x.ToString()).Where(x => x.Contains(\"Size\")).ToArray(), sizeProperties = typeof(UnityEditor.EditorWindow).Assembly.GetType(\"UnityEditor.GameView\").GetProperties(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic).Where(x => x.Name.Contains(\"Size\")).Select(x => x.ToString()).ToArray() };"}}]
|
||||
@@ -0,0 +1 @@
|
||||
[{"tool":"manage_packages","arguments":{"action":"add_package","package":"[email protected]"}}]
|
||||
@@ -0,0 +1 @@
|
||||
[{"tool":"manage_packages","arguments":{"action":"status","job_id":"$package"}}]
|
||||
@@ -0,0 +1,4 @@
|
||||
[
|
||||
{"tool":"manage_editor","arguments":{"action":"stop"}},
|
||||
{"tool":"manage_packages","arguments":{"action":"search_packages","query":"com.unity.localization"}}
|
||||
]
|
||||
@@ -0,0 +1 @@
|
||||
[{"tool":"refresh_unity","arguments":{"mode":"force","scope":"all","compile":"request","wait_for_ready":true}}]
|
||||
@@ -0,0 +1 @@
|
||||
[{"tool":"execute_code","arguments":{"action":"execute","code":"return Ironspore.Editor.LocalizationSmoke.Begin();"}}]
|
||||
@@ -0,0 +1,4 @@
|
||||
[
|
||||
{"tool":"read_console","arguments":{"action":"clear"}},
|
||||
{"tool":"manage_editor","arguments":{"action":"play"}}
|
||||
]
|
||||
@@ -0,0 +1 @@
|
||||
[{"tool":"execute_code","arguments":{"action":"execute","code":"return Ironspore.Editor.RecoverySmoke.Begin();"}}]
|
||||
@@ -0,0 +1,4 @@
|
||||
[
|
||||
{"tool":"manage_editor","arguments":{"action":"stop"}},
|
||||
{"tool":"refresh_unity","arguments":{"mode":"force","scope":"all","compile":"request","wait_for_ready":false}}
|
||||
]
|
||||
@@ -0,0 +1 @@
|
||||
[{"tool":"execute_code","arguments":{"action":"execute","code":"UnityEditor.AssetDatabase.SaveAssets(); UnityEditor.EditorApplication.delayCall += () => UnityEditor.EditorApplication.OpenProject(\"D:/vibeCoding/unityRouge\"); return \"Restart scheduled to activate the Input System backend.\";"}}]
|
||||
@@ -0,0 +1 @@
|
||||
[{"tool":"execute_code","arguments":{"action":"execute","code":"return Ironspore.Editor.RouteSmoke.Validate();"}}]
|
||||
@@ -0,0 +1 @@
|
||||
[{"tool":"execute_code","arguments":{"action":"execute","code":"return Ironspore.Editor.PrototypeSmoke.Begin();"}}]
|
||||
@@ -0,0 +1 @@
|
||||
[{"tool":"execute_code","arguments":{"action":"execute","code":"Ironspore.GameSession.Active.StartTrial(); return \"Driving range started\";"}}]
|
||||
@@ -0,0 +1 @@
|
||||
[{"tool":"manage_editor","arguments":{"action":"stop"}}]
|
||||
@@ -0,0 +1 @@
|
||||
[{"tool":"get_test_job","arguments":{"job_id":"$test","include_failed_tests":true,"include_details":true}}]
|
||||
@@ -0,0 +1 @@
|
||||
[{"tool":"run_tests","arguments":{"mode":"EditMode"}}]
|
||||
@@ -0,0 +1,4 @@
|
||||
[
|
||||
{"tool":"read_console","arguments":{"action":"get","types":["error","warning"],"count":10,"include_stacktrace":false}},
|
||||
{"tool":"execute_code","arguments":{"action":"execute","code":"return MCPForUnity.Editor.Tools.ManageScene.HandleCommand(Newtonsoft.Json.Linq.JObject.Parse(\"{\\\"action\\\":\\\"screenshot\\\",\\\"fileName\\\":\\\"view.png\\\",\\\"outputFolder\\\":\\\"Docs/QA/Prototype/Screenshots\\\"}\"));"}}
|
||||
]
|
||||
@@ -0,0 +1,88 @@
|
||||
"""Call the installed Unity MCP server through the standard MCP SDK.
|
||||
|
||||
Run with the Python environment belonging to the installed MCP for Unity server.
|
||||
Scene mutations and builds stay inside the Unity MCP tools.
|
||||
"""
|
||||
import argparse
|
||||
import asyncio
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from mcp import ClientSession, StdioServerParameters
|
||||
from mcp.client.stdio import stdio_client
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
sys.stdout.reconfigure(encoding="utf-8")
|
||||
|
||||
|
||||
def unpack(result):
|
||||
data = getattr(result, "structuredContent", None)
|
||||
if data is None:
|
||||
texts = [x.text for x in result.content if x.type == "text"]
|
||||
try:
|
||||
data = json.loads("\n".join(texts))
|
||||
except json.JSONDecodeError:
|
||||
data = {"text": "\n".join(texts)}
|
||||
payload = data.get("result", data) if isinstance(data, dict) else data
|
||||
failed = isinstance(payload, dict) and payload.get("success") is False
|
||||
return {"isError": bool(result.isError or failed), "result": data}
|
||||
|
||||
|
||||
async def run(args):
|
||||
executable = Path.home() / ".local/share/unity-mcp/.venv/Scripts/mcp-for-unity.exe"
|
||||
logs = ROOT / "Logs/MCP"
|
||||
logs.mkdir(parents=True, exist_ok=True)
|
||||
params = StdioServerParameters(command=str(executable), args=["--transport", "stdio", "--default-instance", ROOT.name])
|
||||
with (logs / "server.log").open("w", encoding="utf-8") as errlog:
|
||||
async with stdio_client(params, errlog=errlog) as (read, write):
|
||||
async with ClientSession(read, write) as session:
|
||||
await session.initialize()
|
||||
project = await session.read_resource("mcpforunity://project/info")
|
||||
project_text = "\n".join(x.text for x in project.contents if hasattr(x, "text"))
|
||||
if str(ROOT).replace("\\", "/").lower() not in project_text.replace("\\\\", "/").replace("\\", "/").lower():
|
||||
raise RuntimeError("MCP target is not the workspace: " + project_text)
|
||||
if args.list:
|
||||
available = await session.list_tools()
|
||||
wanted = args.list.split(",")
|
||||
out = [t.model_dump() for t in available.tools if t.name in wanted or args.list == "all"]
|
||||
elif args.resource:
|
||||
res = await session.read_resource(args.resource)
|
||||
out = [x.text for x in res.contents if hasattr(x, "text")]
|
||||
else:
|
||||
commands = json.loads(Path(args.file).read_text(encoding="utf-8-sig"))
|
||||
if isinstance(commands, dict):
|
||||
commands = [commands]
|
||||
out = []
|
||||
jobs_path = logs / "jobs.json"
|
||||
jobs = json.loads(jobs_path.read_text(encoding="utf-8")) if jobs_path.exists() else {}
|
||||
for command in commands:
|
||||
arguments = command.get("arguments", {})
|
||||
job_reference = arguments.get("job_id", "")
|
||||
if job_reference.startswith("$"):
|
||||
arguments["job_id"] = jobs[job_reference[1:]]
|
||||
result = unpack(await session.call_tool(command["tool"], arguments))
|
||||
out.append(result)
|
||||
print(json.dumps({"tool": command["tool"], **result}, ensure_ascii=False), flush=True)
|
||||
payload = result["result"]
|
||||
while isinstance(payload, dict) and isinstance(payload.get("result"), dict) and "data" not in payload:
|
||||
payload = payload["result"]
|
||||
job_id = payload.get("data", {}).get("job_id") if isinstance(payload, dict) and isinstance(payload.get("data"), dict) else None
|
||||
if job_id:
|
||||
category = "test" if command["tool"] in ("run_tests", "get_test_job") else "build" if command["tool"] == "manage_build" else "package"
|
||||
jobs[category] = job_id
|
||||
jobs_path.write_text(json.dumps(jobs), encoding="utf-8")
|
||||
if result["isError"]:
|
||||
break
|
||||
(logs / "last-result.json").write_text(json.dumps(out, ensure_ascii=False, indent=2), encoding="utf-8")
|
||||
if args.list or args.resource:
|
||||
print(json.dumps(out, ensure_ascii=False, indent=2), flush=True)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--list")
|
||||
parser.add_argument("--resource")
|
||||
parser.add_argument("--file")
|
||||
args = parser.parse_args()
|
||||
asyncio.run(asyncio.wait_for(run(args), timeout=58))
|
||||
@@ -0,0 +1,31 @@
|
||||
IRONSPORE / 机甲搜打撤灰盒原型
|
||||
Windows x64 · 键盘与鼠标
|
||||
|
||||
启动同目录的 Ironspore.exe。请保留整个文件夹,包括 Ironspore_Data、
|
||||
UnityPlayer.dll、MonoBleedingEdge 和 ThirdPartyNotices。
|
||||
|
||||
主页右下角「语言 / Language」切换简体中文和 English,选择即时生效,
|
||||
重启后保留。可用鼠标选择;列表内 Tab / Shift+Tab 切换选项,
|
||||
Enter / Space 确认,Esc 或点击外部收起。
|
||||
|
||||
WASD 移动,鼠标瞄准;左键主武器,右键精瞄。
|
||||
V 切换越肩 / 第一人称,Shift 推进,Space 跳跃 / 轻型升空。
|
||||
Q 副武装,F 主动防护,E 交互,Tab 货仓,Esc 暂停。
|
||||
货仓选择最多两组后,返回驾驶并原地按住 G 3 秒发送回收舱。
|
||||
每次出击仅一个回收舱;整机撤离需到橙色平台呼叫运输机,等待抵达后按 E 登机。
|
||||
驾驶试验场使用独立存档,可先试用底盘和配装。
|
||||
|
||||
Launch Ironspore.exe from this folder. Keep the complete folder together.
|
||||
The bottom-right Language button switches Simplified Chinese and English instantly.
|
||||
Your language choice is remembered across restarts. Tab / Shift+Tab navigates
|
||||
the language list, Enter / Space confirms, and Esc or an outside click closes it.
|
||||
|
||||
WASD: move; mouse: aim; LMB/RMB: fire/precision aim; V: perspective;
|
||||
Shift: boost; Space: jump/lift; Q: secondary; F: shield; E: interact;
|
||||
Tab: cargo; hold G while standing still: send selected cargo; Esc: pause.
|
||||
|
||||
This is a gameplay prototype. Full combat balance, final art and performance
|
||||
benchmarks are part of later development.
|
||||
|
||||
Font: Noto Sans SC. Copyright © 2014-2021 Adobe.
|
||||
SIL Open Font License 1.1 and source metadata are in ThirdPartyNotices/NotoSansSC/.
|
||||
Reference in New Issue
Block a user