"""Console commands and CVars. Ops: run {command} — execute editor console command get_cvar {name} set_cvar {name, value} list_cvars {prefix?} — search registered cvars by prefix (best-effort) stat {name, enable?:true} — toggle stat command (`stat fps`, `stat unit`, ...) """ from __future__ import annotations import json import os import traceback try: import unreal # type: ignore except ImportError: unreal = None def _world(): return unreal.EditorLevelLibrary.get_editor_world() def run(args): cmd = args["command"] try: unreal.SystemLibrary.execute_console_command(_world(), cmd) return {"ok": True, "command": cmd} except Exception as e: return {"ok": False, "error": str(e)} def get_cvar(args): name = args["name"] # No direct read API in stable Python; we issue ?-style print and grab from log. try: unreal.SystemLibrary.execute_console_command(_world(), name) # Heuristic: also use ConsoleVariablesEditorFunctionLibrary if available cvl = getattr(unreal, "ConsoleVariablesEditorFunctionLibrary", None) if cvl and hasattr(cvl, "get_console_variable_string_value"): return {"ok": True, "name": name, "value": cvl.get_console_variable_string_value(name)} return {"ok": True, "name": name, "note": "value echoed to Output Log (no direct read API)"} except Exception as e: return {"ok": False, "error": str(e)} def set_cvar(args): name = args["name"] val = args["value"] cmd = f"{name} {val}" try: unreal.SystemLibrary.execute_console_command(_world(), cmd) return {"ok": True, "command": cmd} except Exception as e: return {"ok": False, "error": str(e)} def list_cvars(args): prefix = args.get("prefix") or "" cmd = f"DumpConsoleCommands {prefix}".strip() try: unreal.SystemLibrary.execute_console_command(_world(), cmd) return {"ok": True, "note": "results dumped to log; use read_python_log or grep the project log", "command": cmd} except Exception as e: return {"ok": False, "error": str(e)} def stat(args): name = args["name"] if not name.lower().startswith("stat "): name = "stat " + name try: unreal.SystemLibrary.execute_console_command(_world(), name) return {"ok": True, "command": name} except Exception as e: return {"ok": False, "error": str(e)} OPS = { "run": run, "get_cvar": get_cvar, "set_cvar": set_cvar, "list_cvars": list_cvars, "stat": stat, } def entrypoint(payload_json): try: p = json.loads(payload_json) except Exception as e: return _tee({"ok": False, "error": f"bad json: {e}"}, {}) op = p.get("op"); fn = OPS.get(op) if not fn: return _tee({"ok": False, "error": f"unknown op {op!r}", "available": list(OPS)}, p) try: return _tee(fn(p), p) except Exception as e: return _tee({"ok": False, "error": str(e), "traceback": traceback.format_exc()}, p) def _tee(result, p): txt = json.dumps(result) try: if unreal is not None: sd = unreal.Paths.project_saved_dir() + "MCP/" os.makedirs(sd, exist_ok=True) rid = p.get("__rid") or "last" with open(sd + "last.json", "w", encoding="utf-8") as f: f.write(txt) if rid != "last": with open(sd + f"{rid}.json", "w", encoding="utf-8") as f: f.write(txt) unreal.log("[MCP-CONSOLE] " + txt[:1500]) except Exception: pass return txt