diff --git a/.github/workflows/python-tests.yml b/.github/workflows/python-tests.yml index 0f4315ba4..8d3619cc2 100644 --- a/.github/workflows/python-tests.yml +++ b/.github/workflows/python-tests.yml @@ -66,6 +66,10 @@ jobs: - name: Upload coverage reports uses: codecov/codecov-action@v4 if: always() + # fail_ci_if_error: false does not cover a failed download: v4 crashes on the https + # error before it reads that input. This job gates both release pipelines, and a + # Codecov outage must not stop a release. + continue-on-error: true with: files: ./Server/coverage.xml flags: python diff --git a/MCPForUnity/Editor/Services/Transport/TransportCommandDispatcher.cs b/MCPForUnity/Editor/Services/Transport/TransportCommandDispatcher.cs index becc3bd88..5b0131542 100644 --- a/MCPForUnity/Editor/Services/Transport/TransportCommandDispatcher.cs +++ b/MCPForUnity/Editor/Services/Transport/TransportCommandDispatcher.cs @@ -341,6 +341,19 @@ private static void ProcessCommand(string id, PendingCommand pending) var parameters = command.@params ?? new JObject(); + // An unknown command is the caller's mistake or a version mismatch (a server or + // CLI newer than this package), not an Editor fault: answer it without logging + // an error and a stack trace to the user's console. + if (!CommandRegistry.HasHandler(command.type)) + { + string unknown = $"Unity has no tool or resource named '{command.type}'. If the MCP server " + + "or CLI is newer than the MCP for Unity package in this project, update the package."; + McpLog.Warn(unknown); + pending.TrySetResult(SerializeError(unknown, command.type)); + RemovePending(id, pending); + return; + } + // Block execution of disabled resources var resourceMeta = MCPServiceLocator.ResourceDiscovery.GetResourceMetadata(command.type); if (resourceMeta != null && !MCPServiceLocator.ResourceDiscovery.IsResourceEnabled(command.type)) diff --git a/MCPForUnity/Editor/Tools/CommandRegistry.cs b/MCPForUnity/Editor/Tools/CommandRegistry.cs index e1cab7d9b..e891f3486 100644 --- a/MCPForUnity/Editor/Tools/CommandRegistry.cs +++ b/MCPForUnity/Editor/Tools/CommandRegistry.cs @@ -235,6 +235,11 @@ private static bool RegisterCommandType(Type type, bool isResource) } } + /// + /// True when a tool or resource handler is registered under this name. + /// + public static bool HasHandler(string commandName) => _handlers.ContainsKey(commandName); + /// /// Get a command handler by name /// diff --git a/Server/src/cli/CLI_USAGE_GUIDE.md b/Server/src/cli/CLI_USAGE_GUIDE.md index d3d57f341..28cd25c7e 100644 --- a/Server/src/cli/CLI_USAGE_GUIDE.md +++ b/Server/src/cli/CLI_USAGE_GUIDE.md @@ -607,10 +607,15 @@ unity-mcp audio volume "MusicPlayer" 0.5 ```bash # Control Animator (target or one of its children must have an Animator component) -unity-mcp animation play "Character" "Walk" -unity-mcp animation set-parameter "Character" "Speed" 1.5 --type float -unity-mcp animation set-parameter "Character" "IsRunning" true --type bool -unity-mcp animation set-parameter "Character" "Jump" "" --type trigger +unity-mcp animation animator play "Character" "Walk" +unity-mcp animation animator set-parameter "Character" "Speed" 1.5 --type float +unity-mcp animation animator set-parameter "Character" "IsRunning" true --type bool +unity-mcp animation animator set-parameter "Character" "Jump" "" --type trigger + +# Clips and controllers +unity-mcp animation clip create "Assets/Animations/Bounce.anim" --length 2.0 --loop +unity-mcp animation clip info "Assets/Animations/Walk.anim" +unity-mcp animation controller info "Assets/Animations/Player.controller" ``` ### Camera Commands @@ -815,6 +820,62 @@ unity-mcp code search "TODO|FIXME" "Assets/Scripts/Utils.cs" unity-mcp code search "void Update" "Assets/Scripts/Game.cs" --max-results 20 ``` +### Build Commands + +```bash +unity-mcp build platform # Read the active platform +unity-mcp build platform android # Switch platform +unity-mcp build scenes # Read the build scene list +unity-mcp build run --target windows64 --development +unity-mcp build batch --targets windows64,linux64,webgl +unity-mcp build status # Last build report +unity-mcp build settings product_name --value "My Game" +``` + +### Physics Commands + +```bash +unity-mcp physics ping # Physics system status +unity-mcp physics get-settings +unity-mcp physics raycast --origin "0,5,0" --direction "0,-1,0" --max-distance 10 +unity-mcp physics overlap --shape sphere --position "0,0,0" --size 2 +unity-mcp physics get-rigidbody "Player" +unity-mcp physics simulate --steps 10 # Step physics in edit mode +unity-mcp physics validate # Check the scene for common mistakes +``` + +### Profiler Commands + +```bash +unity-mcp profiler start # Optionally --log-file to record a .raw +unity-mcp profiler status +unity-mcp profiler frame-timing +unity-mcp profiler get-counters --category Render +unity-mcp profiler memory-snapshot # Requires com.unity.memoryprofiler +unity-mcp profiler stop +``` + +### Reflection and Docs Commands + +```bash +unity-mcp reflect search NavMesh # Find Unity types by name +unity-mcp reflect type NavMeshAgent # Member summary +unity-mcp reflect member Physics Raycast # One member in detail +unity-mcp docs get Physics Raycast # Unity documentation page +``` + +### Asset Generation and Blender Commands + +```bash +unity-mcp asset-gen list-models --kind image +unity-mcp asset-gen generate-image --provider fal --prompt "a stone texture" +unity-mcp asset-gen generate-model --provider tripo --mode text --prompt "a red chair" +unity-mcp asset-gen status --job-id abc123 +unity-mcp asset-gen import-model-file --source-path "C:/exports/house.fbx" --output-folder Assets/Models +unity-mcp blender status # Is Blender reachable? +unity-mcp blender import-model --selection-only --target-size 2 +``` + ### Raw Commands For advanced usage, send raw tool calls: diff --git a/Server/tests/test_manifest_tools.py b/Server/tests/test_manifest_tools.py new file mode 100644 index 000000000..c1b919701 --- /dev/null +++ b/Server/tests/test_manifest_tools.py @@ -0,0 +1,24 @@ +"""manifest.json (the MCP bundle manifest) must list every registered tool, and only those. + +The six asset_gen tools shipped without entries because nothing compared the two lists. +""" +import json +from pathlib import Path + +import services.tools as tools_package +from services.registry import get_registered_tools +from utils.module_discovery import discover_modules + + +MANIFEST = Path(__file__).resolve().parents[2] / "manifest.json" + + +def test_manifest_lists_exactly_the_registered_tools(): + # Import every tool module so its @mcp_for_unity_tool decorator runs (see test_tool_annotations). + list(discover_modules(Path(tools_package.__file__).parent, tools_package.__package__)) + registered = {tool["name"] for tool in get_registered_tools()} + listed = [tool["name"] for tool in json.loads(MANIFEST.read_text(encoding="utf-8"))["tools"]] + + assert len(listed) == len(set(listed)), f"manifest.json lists a tool twice: {sorted(listed)}" + assert sorted(registered - set(listed)) == [], "registered tools that manifest.json does not list" + assert sorted(set(listed) - registered) == [], "manifest.json lists tools that are not registered" diff --git a/TestProjects/UnityMCPTests/Assets/Tests/EditMode/Services/TransportCommandDispatcherTests.cs b/TestProjects/UnityMCPTests/Assets/Tests/EditMode/Services/TransportCommandDispatcherTests.cs new file mode 100644 index 000000000..5777348e5 --- /dev/null +++ b/TestProjects/UnityMCPTests/Assets/Tests/EditMode/Services/TransportCommandDispatcherTests.cs @@ -0,0 +1,37 @@ +using System.Collections; +using System.Text.RegularExpressions; +using System.Threading; +using Newtonsoft.Json.Linq; +using NUnit.Framework; +using UnityEngine; +using UnityEngine.TestTools; +using MCPForUnity.Editor.Services.Transport; + +namespace MCPForUnityTests.Editor.Services +{ + [TestFixture] + public class TransportCommandDispatcherTests + { + [UnityTest] + public IEnumerator UnknownCommand_IsAnsweredWithoutAnErrorInTheConsole() + { + // A server or CLI newer than the package sends commands this package does not have. + // That reached the console as a red error with a stack trace, as if the Editor broke. + LogAssert.Expect(LogType.Warning, new Regex("no_such_command.*update the package")); + + var reply = TransportCommandDispatcher.ExecuteCommandJsonAsync( + "{\"type\":\"no_such_command\",\"params\":{}}", CancellationToken.None); + for (int frame = 0; frame < 600 && !reply.IsCompleted; frame++) + { + yield return null; + } + + Assert.IsTrue(reply.IsCompleted, "the dispatcher never answered"); + var response = JObject.Parse(reply.Result); + Assert.AreEqual("error", (string)response["status"]); + StringAssert.Contains("'no_such_command'", (string)response["error"]); + Assert.AreEqual("no_such_command", (string)response["command"]); + Assert.IsNull((string)response["stackTrace"]); + } + } +} diff --git a/TestProjects/UnityMCPTests/Assets/Tests/EditMode/Services/TransportCommandDispatcherTests.cs.meta b/TestProjects/UnityMCPTests/Assets/Tests/EditMode/Services/TransportCommandDispatcherTests.cs.meta new file mode 100644 index 000000000..3b5e50761 --- /dev/null +++ b/TestProjects/UnityMCPTests/Assets/Tests/EditMode/Services/TransportCommandDispatcherTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 708238a7f69e4a669486584a82327553 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/manifest.json b/manifest.json index 6108e46c4..f1117a546 100644 --- a/manifest.json +++ b/manifest.json @@ -37,6 +37,10 @@ "name": "batch_execute", "description": "Execute multiple Unity operations in a single batch" }, + { + "name": "blender_bridge", + "description": "Drive a running Blender through the BlenderMCP addon and bring its results into Unity" + }, { "name": "create_script", "description": "Create new C# scripts" @@ -69,6 +73,18 @@ "name": "find_in_file", "description": "Search for content within Unity project files" }, + { + "name": "generate_audio", + "description": "Generate sound effects and music with AI models and import them as AudioClips" + }, + { + "name": "generate_image", + "description": "Generate 2D images with AI providers and import them as textures or sprites" + }, + { + "name": "generate_model", + "description": "Generate 3D models with AI providers and import them into the project" + }, { "name": "get_sha", "description": "Get SHA hash of script content" @@ -77,6 +93,14 @@ "name": "get_test_job", "description": "Get status of async test job" }, + { + "name": "import_model", + "description": "Import 3D models from the Sketchfab marketplace into the project" + }, + { + "name": "import_model_file", + "description": "Import a 3D model file that is already on disk (FBX, OBJ, glTF) into the project" + }, { "name": "manage_animation", "description": "Manage Unity animation: Animator control, AnimatorController CRUD, and AnimationClip operations" diff --git a/tools/tests/test_python_tests_workflow.py b/tools/tests/test_python_tests_workflow.py new file mode 100644 index 000000000..419f18aa7 --- /dev/null +++ b/tools/tests/test_python_tests_workflow.py @@ -0,0 +1,20 @@ +"""A Codecov outage must not fail the Python test job, which gates both release pipelines.""" +from pathlib import Path +import re + + +WORKFLOW = Path(__file__).resolve().parents[2] / ".github" / "workflows" / "python-tests.yml" + + +def coverage_upload_steps(): + text = WORKFLOW.read_text(encoding="utf-8") + starts = [match.start() for match in re.finditer(r"^ - ", text, re.M)] + [len(text)] + steps = [text[begin:end] for begin, end in zip(starts, starts[1:])] + return [step for step in steps if "codecov/codecov-action@" in step] + + +def test_coverage_upload_cannot_fail_the_job(): + steps = coverage_upload_steps() + assert len(steps) == 1 + # fail_ci_if_error: false does not stop codecov-action v4 crashing on a download error. + assert re.search(r"^ continue-on-error: true$", steps[0], re.M), steps[0] diff --git a/website/docs/guides/cli-examples.md b/website/docs/guides/cli-examples.md index 9872723fa..f1149f4dd 100644 --- a/website/docs/guides/cli-examples.md +++ b/website/docs/guides/cli-examples.md @@ -235,6 +235,48 @@ unity-mcp batch inline '[{"tool": "manage_scene", "params": {...}}]' unity-mcp batch template > commands.json ``` +**Animation** +```bash +unity-mcp animation animator play "Player" "Run" +unity-mcp animation animator set-parameter "Player" "Speed" 1.5 +unity-mcp animation clip create "Assets/Animations/Bounce.anim" --length 2.0 --loop +unity-mcp animation controller info "Assets/Animations/Player.controller" +``` + +**Build** +```bash +unity-mcp build platform [android] # Read or switch platform +unity-mcp build run --target windows64 --development +unity-mcp build status +``` + +**Physics** +```bash +unity-mcp physics raycast --origin "0,5,0" --direction "0,-1,0" +unity-mcp physics simulate --steps 10 +unity-mcp physics validate +``` + +**Profiler** +```bash +unity-mcp profiler start +unity-mcp profiler get-counters --category Render +unity-mcp profiler stop +``` + +**Reflection & Docs** +```bash +unity-mcp reflect type NavMeshAgent +unity-mcp docs get Physics Raycast +``` + +**Asset Generation & Blender** +```bash +unity-mcp asset-gen generate-image --provider fal --prompt "a stone texture" +unity-mcp asset-gen status --job-id abc123 +unity-mcp blender import-model --selection-only --target-size 2 +``` + **Raw Access (Any Tool)** ```bash unity-mcp raw tool_name 'JSON_params' diff --git a/website/docs/guides/cli.md b/website/docs/guides/cli.md index 062dfb524..15117133b 100644 --- a/website/docs/guides/cli.md +++ b/website/docs/guides/cli.md @@ -326,12 +326,16 @@ unity-mcp asset move "Assets/Old.mat" "Assets/Materials/" ### Animation Operations ```bash -# Play animation state -unity-mcp animation play "Player" "Run" - -# Set animator parameter -unity-mcp animation set-parameter "Player" Speed 1.5 -unity-mcp animation set-parameter "Player" IsRunning true +# Animator on a GameObject +unity-mcp animation animator info "Player" +unity-mcp animation animator play "Player" "Run" +unity-mcp animation animator set-parameter "Player" "Speed" 1.5 +unity-mcp animation animator set-parameter "Player" "IsRunning" true --type bool + +# Clips and controllers +unity-mcp animation clip create "Assets/Animations/Bounce.anim" --length 2.0 --loop +unity-mcp animation clip info "Assets/Animations/Walk.anim" +unity-mcp animation controller info "Assets/Animations/Player.controller" ``` ### Audio Operations @@ -467,6 +471,62 @@ unity-mcp texture delete "Assets/Textures/Old.png" [--force] # Patterns: checkerboard, stripes, stripes_h, stripes_v, stripes_diag, dots, grid, brick ``` +### Build Operations + +```bash +unity-mcp build platform # Read the active platform +unity-mcp build platform android # Switch platform +unity-mcp build scenes # Read the build scene list +unity-mcp build run --target windows64 --development +unity-mcp build batch --targets windows64,linux64,webgl +unity-mcp build status # Last build report +unity-mcp build settings product_name --value "My Game" +``` + +### Physics Operations + +```bash +unity-mcp physics ping # Physics system status +unity-mcp physics get-settings +unity-mcp physics raycast --origin "0,5,0" --direction "0,-1,0" --max-distance 10 +unity-mcp physics overlap --shape sphere --position "0,0,0" --size 2 +unity-mcp physics get-rigidbody "Player" +unity-mcp physics simulate --steps 10 # Step physics in edit mode +unity-mcp physics validate # Check the scene for common mistakes +``` + +### Profiler Operations + +```bash +unity-mcp profiler start # Optionally --log-file to record a .raw +unity-mcp profiler status +unity-mcp profiler frame-timing +unity-mcp profiler get-counters --category Render +unity-mcp profiler memory-snapshot # Requires com.unity.memoryprofiler +unity-mcp profiler stop +``` + +### Reflection and Docs + +```bash +unity-mcp reflect search NavMesh # Find Unity types by name +unity-mcp reflect type NavMeshAgent # Member summary +unity-mcp reflect member Physics Raycast # One member in detail +unity-mcp docs get Physics Raycast # Unity documentation page +``` + +### Asset Generation and Blender + +```bash +unity-mcp asset-gen list-models --kind image +unity-mcp asset-gen generate-image --provider fal --prompt "a stone texture" +unity-mcp asset-gen generate-model --provider tripo --mode text --prompt "a red chair" +unity-mcp asset-gen status --job-id abc123 +unity-mcp asset-gen import-model-file --source-path "C:/exports/house.fbx" --output-folder Assets/Models +unity-mcp blender status # Is Blender reachable? +unity-mcp blender import-model --selection-only --target-size 2 +``` + ### Raw Commands For any MCP tool not covered by dedicated commands: @@ -485,33 +545,44 @@ unity-mcp raw manage_packages '{"action": "list_packages"}' | Group | Subcommands | |-------|-------------| -| `instance` | `list`, `set`, `current` | -| `scene` | `hierarchy`, `active`, `load`, `save`, `create`, `build-settings` | -| `code` | `read`, `search` | -| `gameobject` | `find`, `create`, `modify`, `delete`, `duplicate`, `move` | -| `component` | `add`, `remove`, `set`, `modify` | -| `script` | `create`, `read`, `delete`, `edit`, `validate` | -| `shader` | `create`, `read`, `update`, `delete` | -| `editor` | `play`, `pause`, `stop`, `refresh`, `console`, `menu`, `tool`, `add-tag`, `remove-tag`, `add-layer`, `remove-layer`, `tests`, `poll-test`, `custom-tool` | -| `asset` | `search`, `info`, `create`, `delete`, `duplicate`, `move`, `rename`, `import`, `mkdir` | -| `prefab` | `open`, `close`, `save`, `create`, `modify` | -| `material` | `info`, `create`, `set-color`, `set-property`, `assign`, `set-renderer-color` | -| `camera` | `ping`, `list`, `create`, `set-target`, `set-lens`, `set-priority`, `set-body`, `set-aim`, `set-noise`, `add-extension`, `remove-extension`, `ensure-brain`, `brain-status`, `set-blend`, `force`, `release`, `screenshot`, `screenshot-multiview` | -| `graphics` | `ping`, `volume-create`, `volume-add-effect`, `volume-set-effect`, `volume-remove-effect`, `volume-info`, `volume-set-properties`, `volume-list-effects`, `volume-create-profile`, `pipeline-info`, `pipeline-settings`, `pipeline-set-quality`, `pipeline-set-settings`, `bake-start`, `bake-cancel`, `bake-status`, `bake-clear`, `bake-settings`, `bake-set-settings`, `bake-reflection-probe`, `bake-create-probes`, `bake-create-reflection`, `stats`, `stats-memory`, `stats-debug-mode`, `feature-list`, `feature-add`, `feature-remove`, `feature-configure`, `feature-reorder`, `feature-toggle`, `skybox-info`, `skybox-set-material`, `skybox-set-properties`, `skybox-set-ambient`, `skybox-set-fog`, `skybox-set-reflection`, `skybox-set-sun` | -| `packages` | `ping`, `list`, `search`, `info`, `add`, `remove`, `embed`, `resolve`, `status`, `list-registries`, `add-registry`, `remove-registry` | -| `texture` | `create`, `sprite`, `modify`, `delete` | -| `vfx particle` | `info`, `play`, `stop`, `pause`, `restart`, `clear` | -| `vfx line` | `info`, `set-positions`, `create-line`, `create-circle`, `clear` | -| `vfx trail` | `info`, `set-time`, `clear` | -| `vfx` | `raw` (access all 60+ actions) | -| `probuilder` | `create-shape`, `create-poly`, `info`, `raw` (access all 35+ actions) | -| `batch` | `run`, `inline`, `template` | -| `animation` | `play`, `set-parameter` | +| (top level) | `instances`, `raw`, `status` | +| `animation` | `raw` | +| `animation animator` | `crossfade`, `get-parameter`, `info`, `play`, `set-enabled`, `set-parameter`, `set-speed` | +| `animation clip` | `add-curve`, `add-event`, `assign`, `create`, `create-preset`, `info`, `remove-event`, `set-curve`, `set-vector-curve` | +| `animation controller` | `add-blend-tree-child`, `add-layer`, `add-parameter`, `add-state`, `add-transition`, `assign`, `create`, `create-blend-tree-1d`, `create-blend-tree-2d`, `info`, `remove-layer`, `set-layer-weight` | +| `asset` | `create`, `delete`, `duplicate`, `import`, `info`, `mkdir`, `move`, `rename`, `search` | +| `asset-gen` | `generate-audio`, `generate-image`, `generate-model`, `import-model`, `import-model-file`, `list-models`, `status` | | `audio` | `play`, `stop`, `volume` | +| `batch` | `inline`, `run`, `template` | +| `blender` | `check-updates`, `compare-screenshot`, `import-model`, `object-info`, `run-python`, `scene-info`, `screenshot`, `setup-bloom`, `status`, `sync-addon` | +| `build` | `batch`, `cancel`, `platform`, `profiles`, `run`, `scenes`, `settings`, `status` | +| `camera` | `add-extension`, `brain-status`, `create`, `ensure-brain`, `force`, `list`, `ping`, `release`, `remove-extension`, `screenshot`, `screenshot-multiview`, `set-aim`, `set-blend`, `set-body`, `set-lens`, `set-noise`, `set-priority`, `set-target` | +| `code` | `clear-history`, `execute`, `history`, `read`, `replay`, `search` | +| `component` | `add`, `modify`, `remove`, `set` | +| `custom_tool` | `list` | +| `docs` | `get` | +| `editor` | `add-layer`, `add-tag`, `console`, `custom-tool`, `deploy`, `menu`, `pause`, `play`, `poll-test`, `redo`, `refresh`, `remove-layer`, `remove-tag`, `restore`, `stop`, `tests`, `tool`, `undo` | +| `gameobject` | `create`, `delete`, `duplicate`, `find`, `modify`, `move` | +| `graphics` | `bake-cancel`, `bake-clear`, `bake-create-probes`, `bake-create-reflection`, `bake-reflection-probe`, `bake-set-settings`, `bake-settings`, `bake-start`, `bake-status`, `feature-add`, `feature-configure`, `feature-list`, `feature-remove`, `feature-reorder`, `feature-toggle`, `ping`, `pipeline-info`, `pipeline-set-quality`, `pipeline-set-settings`, `pipeline-settings`, `skybox-info`, `skybox-set-ambient`, `skybox-set-fog`, `skybox-set-material`, `skybox-set-properties`, `skybox-set-reflection`, `skybox-set-sun`, `stats`, `stats-debug-mode`, `stats-memory`, `volume-add-effect`, `volume-create`, `volume-create-profile`, `volume-info`, `volume-list-effects`, `volume-remove-effect`, `volume-set-effect`, `volume-set-properties` | +| `instance` | `current`, `list`, `set` | | `lighting` | `create` | +| `material` | `assign`, `create`, `info`, `set-color`, `set-property`, `set-renderer-color` | +| `packages` | `add`, `add-registry`, `embed`, `info`, `list`, `list-registries`, `ping`, `remove`, `remove-registry`, `resolve`, `search`, `status` | +| `physics` | `add-joint`, `apply-force`, `assign-material`, `configure-joint`, `configure-material`, `configure-rigidbody`, `create-material`, `get-collision-matrix`, `get-rigidbody`, `get-settings`, `linecast`, `overlap`, `ping`, `raycast`, `raycast-all`, `remove-joint`, `set-collision-matrix`, `set-settings`, `shapecast`, `simulate`, `validate` | +| `prefab` | `close`, `create`, `hierarchy`, `info`, `modify`, `open`, `save` | +| `probuilder` | `auto-smooth`, `bevel-edges`, `center-pivot`, `create-poly`, `create-shape`, `delete-faces`, `extrude-edges`, `extrude-faces`, `freeze-transform`, `info`, `move-vertices`, `raw`, `repair`, `select-faces`, `set-material`, `set-pivot`, `set-smoothing`, `subdivide`, `validate`, `weld-vertices` | +| `profiler` | `frame-debugger-disable`, `frame-debugger-enable`, `frame-debugger-events`, `frame-timing`, `get-counters`, `memory-compare`, `memory-list`, `memory-snapshot`, `object-memory`, `set-areas`, `start`, `status`, `stop` | +| `reflect` | `member`, `search`, `type` | +| `scene` | `active`, `build-settings`, `close`, `create`, `hierarchy`, `load`, `loaded`, `move-to`, `open-additive`, `save`, `set-active`, `validate` | +| `script` | `create`, `delete`, `edit`, `read`, `validate` | +| `shader` | `create`, `delete`, `read`, `update` | +| `texture` | `create`, `delete`, `modify`, `set-import-settings`, `sprite` | | `tool` | `list` | -| `custom_tool` | `list` | -| `ui` | `create-canvas`, `create-text`, `create-button`, `create-image` | +| `ui` | `create-button`, `create-canvas`, `create-image`, `create-text` | +| `vfx` | `raw` | +| `vfx line` | `clear`, `create-circle`, `create-line`, `info`, `set-positions` | +| `vfx particle` | `clear`, `info`, `pause`, `play`, `restart`, `stop` | +| `vfx trail` | `clear`, `info`, `set-time` | ---