unreal-engine-mcp-server 0.4.7 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +26 -0
- package/.env.production +38 -7
- package/.eslintrc.json +0 -54
- package/.eslintrc.override.json +8 -0
- package/.github/ISSUE_TEMPLATE/bug_report.yml +94 -0
- package/.github/ISSUE_TEMPLATE/config.yml +8 -0
- package/.github/ISSUE_TEMPLATE/feature_request.yml +56 -0
- package/.github/copilot-instructions.md +478 -45
- package/.github/dependabot.yml +19 -0
- package/.github/labeler.yml +24 -0
- package/.github/labels.yml +70 -0
- package/.github/pull_request_template.md +42 -0
- package/.github/release-drafter-config.yml +51 -0
- package/.github/workflows/auto-merge.yml +38 -0
- package/.github/workflows/ci.yml +38 -0
- package/.github/workflows/dependency-review.yml +17 -0
- package/.github/workflows/gemini-issue-triage.yml +172 -0
- package/.github/workflows/greetings.yml +27 -0
- package/.github/workflows/labeler.yml +17 -0
- package/.github/workflows/links.yml +80 -0
- package/.github/workflows/pr-size-labeler.yml +137 -0
- package/.github/workflows/publish-mcp.yml +13 -7
- package/.github/workflows/release-drafter.yml +23 -0
- package/.github/workflows/release.yml +112 -0
- package/.github/workflows/semantic-pull-request.yml +35 -0
- package/.github/workflows/smoke-test.yml +36 -0
- package/.github/workflows/stale.yml +28 -0
- package/CHANGELOG.md +338 -31
- package/CONTRIBUTING.md +140 -0
- package/GEMINI.md +115 -0
- package/Public/Plugin_setup_guide.mp4 +0 -0
- package/README.md +189 -128
- package/claude_desktop_config_example.json +7 -6
- package/dist/automation/bridge.d.ts +50 -0
- package/dist/automation/bridge.js +452 -0
- package/dist/automation/connection-manager.d.ts +23 -0
- package/dist/automation/connection-manager.js +107 -0
- package/dist/automation/handshake.d.ts +11 -0
- package/dist/automation/handshake.js +89 -0
- package/dist/automation/index.d.ts +3 -0
- package/dist/automation/index.js +3 -0
- package/dist/automation/message-handler.d.ts +12 -0
- package/dist/automation/message-handler.js +149 -0
- package/dist/automation/request-tracker.d.ts +25 -0
- package/dist/automation/request-tracker.js +98 -0
- package/dist/automation/types.d.ts +130 -0
- package/dist/automation/types.js +2 -0
- package/dist/cli.js +32 -5
- package/dist/config.d.ts +26 -0
- package/dist/config.js +59 -0
- package/dist/constants.d.ts +16 -0
- package/dist/constants.js +16 -0
- package/dist/graphql/loaders.d.ts +64 -0
- package/dist/graphql/loaders.js +117 -0
- package/dist/graphql/resolvers.d.ts +268 -0
- package/dist/graphql/resolvers.js +746 -0
- package/dist/graphql/schema.d.ts +5 -0
- package/dist/graphql/schema.js +437 -0
- package/dist/graphql/server.d.ts +26 -0
- package/dist/graphql/server.js +117 -0
- package/dist/graphql/types.d.ts +9 -0
- package/dist/graphql/types.js +2 -0
- package/dist/handlers/resource-handlers.d.ts +20 -0
- package/dist/handlers/resource-handlers.js +180 -0
- package/dist/index.d.ts +33 -18
- package/dist/index.js +130 -619
- package/dist/resources/actors.d.ts +17 -12
- package/dist/resources/actors.js +56 -76
- package/dist/resources/assets.d.ts +6 -14
- package/dist/resources/assets.js +115 -147
- package/dist/resources/levels.d.ts +13 -13
- package/dist/resources/levels.js +25 -34
- package/dist/server/resource-registry.d.ts +20 -0
- package/dist/server/resource-registry.js +37 -0
- package/dist/server/tool-registry.d.ts +23 -0
- package/dist/server/tool-registry.js +322 -0
- package/dist/server-setup.d.ts +20 -0
- package/dist/server-setup.js +71 -0
- package/dist/services/health-monitor.d.ts +34 -0
- package/dist/services/health-monitor.js +105 -0
- package/dist/services/metrics-server.d.ts +11 -0
- package/dist/services/metrics-server.js +105 -0
- package/dist/tools/actors.d.ts +163 -9
- package/dist/tools/actors.js +356 -311
- package/dist/tools/animation.d.ts +135 -4
- package/dist/tools/animation.js +510 -411
- package/dist/tools/assets.d.ts +75 -29
- package/dist/tools/assets.js +265 -284
- package/dist/tools/audio.d.ts +102 -42
- package/dist/tools/audio.js +272 -685
- package/dist/tools/base-tool.d.ts +17 -0
- package/dist/tools/base-tool.js +46 -0
- package/dist/tools/behavior-tree.d.ts +94 -0
- package/dist/tools/behavior-tree.js +39 -0
- package/dist/tools/blueprint.d.ts +208 -126
- package/dist/tools/blueprint.js +685 -832
- package/dist/tools/consolidated-tool-definitions.d.ts +5462 -1781
- package/dist/tools/consolidated-tool-definitions.js +829 -496
- package/dist/tools/consolidated-tool-handlers.d.ts +2 -1
- package/dist/tools/consolidated-tool-handlers.js +198 -1027
- package/dist/tools/debug.d.ts +143 -85
- package/dist/tools/debug.js +234 -180
- package/dist/tools/dynamic-handler-registry.d.ts +13 -0
- package/dist/tools/dynamic-handler-registry.js +23 -0
- package/dist/tools/editor.d.ts +30 -83
- package/dist/tools/editor.js +247 -244
- package/dist/tools/engine.d.ts +10 -4
- package/dist/tools/engine.js +13 -5
- package/dist/tools/environment.d.ts +30 -0
- package/dist/tools/environment.js +267 -0
- package/dist/tools/foliage.d.ts +65 -99
- package/dist/tools/foliage.js +221 -331
- package/dist/tools/handlers/actor-handlers.d.ts +3 -0
- package/dist/tools/handlers/actor-handlers.js +227 -0
- package/dist/tools/handlers/animation-handlers.d.ts +3 -0
- package/dist/tools/handlers/animation-handlers.js +185 -0
- package/dist/tools/handlers/argument-helper.d.ts +16 -0
- package/dist/tools/handlers/argument-helper.js +80 -0
- package/dist/tools/handlers/asset-handlers.d.ts +3 -0
- package/dist/tools/handlers/asset-handlers.js +496 -0
- package/dist/tools/handlers/audio-handlers.d.ts +3 -0
- package/dist/tools/handlers/audio-handlers.js +166 -0
- package/dist/tools/handlers/blueprint-handlers.d.ts +4 -0
- package/dist/tools/handlers/blueprint-handlers.js +358 -0
- package/dist/tools/handlers/common-handlers.d.ts +14 -0
- package/dist/tools/handlers/common-handlers.js +56 -0
- package/dist/tools/handlers/editor-handlers.d.ts +3 -0
- package/dist/tools/handlers/editor-handlers.js +119 -0
- package/dist/tools/handlers/effect-handlers.d.ts +3 -0
- package/dist/tools/handlers/effect-handlers.js +171 -0
- package/dist/tools/handlers/environment-handlers.d.ts +3 -0
- package/dist/tools/handlers/environment-handlers.js +170 -0
- package/dist/tools/handlers/graph-handlers.d.ts +3 -0
- package/dist/tools/handlers/graph-handlers.js +90 -0
- package/dist/tools/handlers/input-handlers.d.ts +3 -0
- package/dist/tools/handlers/input-handlers.js +21 -0
- package/dist/tools/handlers/inspect-handlers.d.ts +3 -0
- package/dist/tools/handlers/inspect-handlers.js +383 -0
- package/dist/tools/handlers/level-handlers.d.ts +3 -0
- package/dist/tools/handlers/level-handlers.js +237 -0
- package/dist/tools/handlers/lighting-handlers.d.ts +3 -0
- package/dist/tools/handlers/lighting-handlers.js +144 -0
- package/dist/tools/handlers/performance-handlers.d.ts +3 -0
- package/dist/tools/handlers/performance-handlers.js +130 -0
- package/dist/tools/handlers/pipeline-handlers.d.ts +3 -0
- package/dist/tools/handlers/pipeline-handlers.js +110 -0
- package/dist/tools/handlers/sequence-handlers.d.ts +3 -0
- package/dist/tools/handlers/sequence-handlers.js +376 -0
- package/dist/tools/handlers/system-handlers.d.ts +4 -0
- package/dist/tools/handlers/system-handlers.js +506 -0
- package/dist/tools/input.d.ts +19 -0
- package/dist/tools/input.js +89 -0
- package/dist/tools/introspection.d.ts +103 -40
- package/dist/tools/introspection.js +425 -568
- package/dist/tools/landscape.d.ts +54 -93
- package/dist/tools/landscape.js +284 -409
- package/dist/tools/level.d.ts +66 -27
- package/dist/tools/level.js +647 -675
- package/dist/tools/lighting.d.ts +77 -38
- package/dist/tools/lighting.js +445 -943
- package/dist/tools/logs.d.ts +3 -3
- package/dist/tools/logs.js +5 -57
- package/dist/tools/materials.d.ts +91 -24
- package/dist/tools/materials.js +194 -118
- package/dist/tools/niagara.d.ts +149 -39
- package/dist/tools/niagara.js +267 -182
- package/dist/tools/performance.d.ts +27 -13
- package/dist/tools/performance.js +203 -122
- package/dist/tools/physics.d.ts +32 -77
- package/dist/tools/physics.js +175 -582
- package/dist/tools/property-dictionary.d.ts +13 -0
- package/dist/tools/property-dictionary.js +82 -0
- package/dist/tools/sequence.d.ts +85 -60
- package/dist/tools/sequence.js +208 -747
- package/dist/tools/tool-definition-utils.d.ts +59 -0
- package/dist/tools/tool-definition-utils.js +35 -0
- package/dist/tools/ui.d.ts +64 -34
- package/dist/tools/ui.js +134 -214
- package/dist/types/automation-responses.d.ts +115 -0
- package/dist/types/automation-responses.js +2 -0
- package/dist/types/env.d.ts +0 -3
- package/dist/types/env.js +0 -7
- package/dist/types/responses.d.ts +249 -0
- package/dist/types/responses.js +2 -0
- package/dist/types/tool-interfaces.d.ts +898 -0
- package/dist/types/tool-interfaces.js +2 -0
- package/dist/types/tool-types.d.ts +183 -19
- package/dist/types/tool-types.js +0 -4
- package/dist/unreal-bridge.d.ts +24 -131
- package/dist/unreal-bridge.js +364 -1506
- package/dist/utils/command-validator.d.ts +9 -0
- package/dist/utils/command-validator.js +68 -0
- package/dist/utils/elicitation.d.ts +1 -1
- package/dist/utils/elicitation.js +12 -15
- package/dist/utils/error-handler.d.ts +2 -51
- package/dist/utils/error-handler.js +11 -87
- package/dist/utils/ini-reader.d.ts +3 -0
- package/dist/utils/ini-reader.js +69 -0
- package/dist/utils/logger.js +9 -6
- package/dist/utils/normalize.d.ts +3 -0
- package/dist/utils/normalize.js +56 -0
- package/dist/utils/path-security.d.ts +2 -0
- package/dist/utils/path-security.js +24 -0
- package/dist/utils/response-factory.d.ts +7 -0
- package/dist/utils/response-factory.js +27 -0
- package/dist/utils/response-validator.d.ts +3 -24
- package/dist/utils/response-validator.js +130 -81
- package/dist/utils/result-helpers.d.ts +4 -5
- package/dist/utils/result-helpers.js +15 -16
- package/dist/utils/safe-json.js +5 -11
- package/dist/utils/unreal-command-queue.d.ts +24 -0
- package/dist/utils/unreal-command-queue.js +120 -0
- package/dist/utils/validation.d.ts +0 -40
- package/dist/utils/validation.js +1 -78
- package/dist/wasm/index.d.ts +70 -0
- package/dist/wasm/index.js +535 -0
- package/docs/GraphQL-API.md +888 -0
- package/docs/Migration-Guide-v0.5.0.md +684 -0
- package/docs/Roadmap.md +53 -0
- package/docs/WebAssembly-Integration.md +628 -0
- package/docs/editor-plugin-extension.md +370 -0
- package/docs/handler-mapping.md +242 -0
- package/docs/native-automation-progress.md +128 -0
- package/docs/testing-guide.md +423 -0
- package/mcp-config-example.json +6 -6
- package/package.json +67 -28
- package/plugins/McpAutomationBridge/Config/FilterPlugin.ini +8 -0
- package/plugins/McpAutomationBridge/McpAutomationBridge.uplugin +64 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/McpAutomationBridge.Build.cs +189 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridgeGlobals.cpp +22 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridgeGlobals.h +30 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridgeHelpers.h +1983 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridgeModule.cpp +72 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridgeSettings.cpp +46 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridgeSubsystem.cpp +581 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_AnimationHandlers.cpp +2394 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_AssetQueryHandlers.cpp +300 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_AssetWorkflowHandlers.cpp +2807 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_AudioHandlers.cpp +1087 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_BehaviorTreeHandlers.cpp +488 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_BlueprintCreationHandlers.cpp +643 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_BlueprintCreationHandlers.h +31 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_BlueprintGraphHandlers.cpp +1184 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_BlueprintHandlers.cpp +5652 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_BlueprintHandlers_List.cpp +152 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_ControlHandlers.cpp +2614 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_DebugHandlers.cpp +42 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_EditorFunctionHandlers.cpp +1237 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_EffectHandlers.cpp +1701 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_EnvironmentHandlers.cpp +2145 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_FoliageHandlers.cpp +954 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_InputHandlers.cpp +209 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_InsightsHandlers.cpp +41 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_LandscapeHandlers.cpp +1164 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_LevelHandlers.cpp +762 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_LightingHandlers.cpp +634 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_LogHandlers.cpp +136 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_MaterialGraphHandlers.cpp +494 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_NiagaraGraphHandlers.cpp +278 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_NiagaraHandlers.cpp +625 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_PerformanceHandlers.cpp +401 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_PipelineHandlers.cpp +67 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_ProcessRequest.cpp +735 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_PropertyHandlers.cpp +2634 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_RenderHandlers.cpp +189 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_SCSHandlers.cpp +917 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_SCSHandlers.h +39 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_SequenceHandlers.cpp +2670 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_SequencerHandlers.cpp +519 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_TestHandlers.cpp +38 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_UiHandlers.cpp +668 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_WorldPartitionHandlers.cpp +346 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpBridgeWebSocket.cpp +1330 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpBridgeWebSocket.h +149 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpConnectionManager.cpp +783 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Public/McpAutomationBridgeSettings.h +115 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Public/McpAutomationBridgeSubsystem.h +796 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Public/McpConnectionManager.h +117 -0
- package/scripts/check-unreal-connection.mjs +19 -0
- package/scripts/clean-tmp.js +23 -0
- package/scripts/patch-wasm.js +26 -0
- package/scripts/run-all-tests.mjs +136 -0
- package/scripts/smoke-test.ts +94 -0
- package/scripts/sync-mcp-plugin.js +143 -0
- package/scripts/test-no-plugin-alternates.mjs +113 -0
- package/scripts/validate-server.js +46 -0
- package/scripts/verify-automation-bridge.js +200 -0
- package/server.json +58 -21
- package/src/automation/bridge.ts +558 -0
- package/src/automation/connection-manager.ts +130 -0
- package/src/automation/handshake.ts +99 -0
- package/src/automation/index.ts +2 -0
- package/src/automation/message-handler.ts +167 -0
- package/src/automation/request-tracker.ts +123 -0
- package/src/automation/types.ts +107 -0
- package/src/cli.ts +33 -6
- package/src/config.ts +73 -0
- package/src/constants.ts +19 -0
- package/src/graphql/loaders.ts +244 -0
- package/src/graphql/resolvers.ts +1008 -0
- package/src/graphql/schema.ts +452 -0
- package/src/graphql/server.ts +156 -0
- package/src/graphql/types.ts +10 -0
- package/src/handlers/resource-handlers.ts +186 -0
- package/src/index.ts +166 -664
- package/src/resources/actors.ts +58 -76
- package/src/resources/assets.ts +148 -134
- package/src/resources/levels.ts +28 -33
- package/src/server/resource-registry.ts +47 -0
- package/src/server/tool-registry.ts +354 -0
- package/src/server-setup.ts +114 -0
- package/src/services/health-monitor.ts +132 -0
- package/src/services/metrics-server.ts +142 -0
- package/src/tools/actors.ts +426 -323
- package/src/tools/animation.ts +672 -461
- package/src/tools/assets.ts +364 -289
- package/src/tools/audio.ts +323 -766
- package/src/tools/base-tool.ts +52 -0
- package/src/tools/behavior-tree.ts +45 -0
- package/src/tools/blueprint.ts +792 -970
- package/src/tools/consolidated-tool-definitions.ts +993 -515
- package/src/tools/consolidated-tool-handlers.ts +258 -1146
- package/src/tools/debug.ts +292 -187
- package/src/tools/dynamic-handler-registry.ts +33 -0
- package/src/tools/editor.ts +329 -253
- package/src/tools/engine.ts +14 -3
- package/src/tools/environment.ts +281 -0
- package/src/tools/foliage.ts +330 -392
- package/src/tools/handlers/actor-handlers.ts +265 -0
- package/src/tools/handlers/animation-handlers.ts +237 -0
- package/src/tools/handlers/argument-helper.ts +142 -0
- package/src/tools/handlers/asset-handlers.ts +532 -0
- package/src/tools/handlers/audio-handlers.ts +194 -0
- package/src/tools/handlers/blueprint-handlers.ts +380 -0
- package/src/tools/handlers/common-handlers.ts +87 -0
- package/src/tools/handlers/editor-handlers.ts +123 -0
- package/src/tools/handlers/effect-handlers.ts +220 -0
- package/src/tools/handlers/environment-handlers.ts +183 -0
- package/src/tools/handlers/graph-handlers.ts +116 -0
- package/src/tools/handlers/input-handlers.ts +28 -0
- package/src/tools/handlers/inspect-handlers.ts +450 -0
- package/src/tools/handlers/level-handlers.ts +252 -0
- package/src/tools/handlers/lighting-handlers.ts +147 -0
- package/src/tools/handlers/performance-handlers.ts +132 -0
- package/src/tools/handlers/pipeline-handlers.ts +127 -0
- package/src/tools/handlers/sequence-handlers.ts +415 -0
- package/src/tools/handlers/system-handlers.ts +564 -0
- package/src/tools/input.ts +101 -0
- package/src/tools/introspection.ts +493 -584
- package/src/tools/landscape.ts +418 -507
- package/src/tools/level.ts +786 -708
- package/src/tools/lighting.ts +588 -984
- package/src/tools/logs.ts +9 -57
- package/src/tools/materials.ts +237 -121
- package/src/tools/niagara.ts +335 -168
- package/src/tools/performance.ts +320 -169
- package/src/tools/physics.ts +274 -613
- package/src/tools/property-dictionary.ts +98 -0
- package/src/tools/sequence.ts +276 -820
- package/src/tools/tool-definition-utils.ts +35 -0
- package/src/tools/ui.ts +205 -283
- package/src/types/automation-responses.ts +119 -0
- package/src/types/env.ts +0 -10
- package/src/types/responses.ts +355 -0
- package/src/types/tool-interfaces.ts +250 -0
- package/src/types/tool-types.ts +243 -21
- package/src/unreal-bridge.ts +460 -1550
- package/src/utils/command-validator.ts +76 -0
- package/src/utils/elicitation.ts +10 -7
- package/src/utils/error-handler.ts +14 -90
- package/src/utils/ini-reader.ts +86 -0
- package/src/utils/logger.ts +8 -3
- package/src/utils/normalize.test.ts +162 -0
- package/src/utils/normalize.ts +60 -0
- package/src/utils/path-security.ts +43 -0
- package/src/utils/response-factory.ts +44 -0
- package/src/utils/response-validator.ts +176 -56
- package/src/utils/result-helpers.ts +21 -19
- package/src/utils/safe-json.test.ts +90 -0
- package/src/utils/safe-json.ts +14 -11
- package/src/utils/unreal-command-queue.ts +152 -0
- package/src/utils/validation.test.ts +184 -0
- package/src/utils/validation.ts +4 -1
- package/src/wasm/index.ts +838 -0
- package/test-server.mjs +100 -0
- package/tests/run-unreal-tool-tests.mjs +242 -14
- package/tests/test-animation.mjs +369 -0
- package/tests/test-asset-advanced.mjs +82 -0
- package/tests/test-asset-errors.mjs +35 -0
- package/tests/test-asset-graph.mjs +311 -0
- package/tests/test-audio.mjs +417 -0
- package/tests/test-automation-timeouts.mjs +98 -0
- package/tests/test-behavior-tree.mjs +444 -0
- package/tests/test-blueprint-graph.mjs +410 -0
- package/tests/test-blueprint.mjs +577 -0
- package/tests/test-client-mode.mjs +86 -0
- package/tests/test-console-command.mjs +56 -0
- package/tests/test-control-actor.mjs +425 -0
- package/tests/test-control-editor.mjs +112 -0
- package/tests/test-graphql.mjs +372 -0
- package/tests/test-input.mjs +349 -0
- package/tests/test-inspect.mjs +302 -0
- package/tests/test-landscape.mjs +316 -0
- package/tests/test-lighting.mjs +428 -0
- package/tests/test-manage-asset.mjs +438 -0
- package/tests/test-manage-level.mjs +89 -0
- package/tests/test-materials.mjs +356 -0
- package/tests/test-niagara.mjs +185 -0
- package/tests/test-no-inline-python.mjs +122 -0
- package/tests/test-performance.mjs +539 -0
- package/tests/test-plugin-handshake.mjs +82 -0
- package/tests/test-runner.mjs +933 -0
- package/tests/test-sequence.mjs +104 -0
- package/tests/test-system.mjs +96 -0
- package/tests/test-wasm.mjs +283 -0
- package/tests/test-world-partition.mjs +215 -0
- package/tsconfig.json +3 -3
- package/vitest.config.ts +35 -0
- package/wasm/Cargo.lock +363 -0
- package/wasm/Cargo.toml +42 -0
- package/wasm/LICENSE +21 -0
- package/wasm/README.md +253 -0
- package/wasm/src/dependency_resolver.rs +377 -0
- package/wasm/src/lib.rs +153 -0
- package/wasm/src/property_parser.rs +271 -0
- package/wasm/src/transform_math.rs +396 -0
- package/wasm/tests/integration.rs +109 -0
- package/.github/workflows/smithery-build.yml +0 -29
- package/dist/prompts/index.d.ts +0 -21
- package/dist/prompts/index.js +0 -217
- package/dist/tools/build_environment_advanced.d.ts +0 -65
- package/dist/tools/build_environment_advanced.js +0 -633
- package/dist/tools/rc.d.ts +0 -110
- package/dist/tools/rc.js +0 -437
- package/dist/tools/visual.d.ts +0 -40
- package/dist/tools/visual.js +0 -282
- package/dist/utils/http.d.ts +0 -6
- package/dist/utils/http.js +0 -151
- package/dist/utils/python-output.d.ts +0 -18
- package/dist/utils/python-output.js +0 -290
- package/dist/utils/python.d.ts +0 -2
- package/dist/utils/python.js +0 -4
- package/dist/utils/stdio-redirect.d.ts +0 -2
- package/dist/utils/stdio-redirect.js +0 -20
- package/docs/unreal-tool-test-cases.md +0 -574
- package/smithery.yaml +0 -29
- package/src/prompts/index.ts +0 -249
- package/src/tools/build_environment_advanced.ts +0 -732
- package/src/tools/rc.ts +0 -515
- package/src/tools/visual.ts +0 -281
- package/src/utils/http.ts +0 -187
- package/src/utils/python-output.ts +0 -351
- package/src/utils/python.ts +0 -3
- package/src/utils/stdio-redirect.ts +0 -18
package/dist/tools/actors.js
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { ensureRotation, ensureVector3 } from '../utils/validation.js';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
export class ActorTools {
|
|
5
|
-
bridge;
|
|
2
|
+
import { BaseTool } from './base-tool.js';
|
|
3
|
+
import { wasmIntegration } from '../wasm/index.js';
|
|
4
|
+
export class ActorTools extends BaseTool {
|
|
6
5
|
constructor(bridge) {
|
|
7
|
-
|
|
6
|
+
super(bridge);
|
|
8
7
|
}
|
|
9
8
|
async spawn(params) {
|
|
10
9
|
if (!params.classPath || typeof params.classPath !== 'string' || params.classPath.trim().length === 0) {
|
|
@@ -28,305 +27,123 @@ export class ActorTools {
|
|
|
28
27
|
const mappedClassPath = shapeMapping[lowerName] ?? this.resolveActorClass(className);
|
|
29
28
|
const [locX, locY, locZ] = ensureVector3(params.location ?? { x: 0, y: 0, z: 100 }, 'actor location');
|
|
30
29
|
const [rotPitch, rotYaw, rotRoll] = ensureRotation(params.rotation ?? { pitch: 0, yaw: 0, roll: 0 }, 'actor rotation');
|
|
31
|
-
const escapedResolvedClassPath = escapePythonString(mappedClassPath);
|
|
32
|
-
const escapedRequestedPath = escapePythonString(className);
|
|
33
|
-
const escapedRequestedActorName = sanitizedActorName ? escapePythonString(sanitizedActorName) : '';
|
|
34
|
-
const pythonCmd = `
|
|
35
|
-
import unreal
|
|
36
|
-
import json
|
|
37
|
-
import time
|
|
38
|
-
|
|
39
|
-
result = {
|
|
40
|
-
"success": False,
|
|
41
|
-
"message": "",
|
|
42
|
-
"error": "",
|
|
43
|
-
"actorName": "",
|
|
44
|
-
"requestedClass": "${escapedRequestedPath}",
|
|
45
|
-
"resolvedClass": "${escapedResolvedClassPath}",
|
|
46
|
-
"location": [${locX}, ${locY}, ${locZ}],
|
|
47
|
-
"rotation": [${rotPitch}, ${rotYaw}, ${rotRoll}],
|
|
48
|
-
"requestedActorName": "${escapedRequestedActorName}",
|
|
49
|
-
"warnings": [],
|
|
50
|
-
"details": []
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
${this.getPythonSpawnHelper()}
|
|
54
|
-
|
|
55
|
-
abstract_classes = ['PlaneReflectionCapture', 'ReflectionCapture', 'Actor', 'Pawn', 'Character']
|
|
56
|
-
|
|
57
|
-
def finalize():
|
|
58
|
-
data = dict(result)
|
|
59
|
-
if data.get("success"):
|
|
60
|
-
if not data.get("message"):
|
|
61
|
-
data["message"] = "Actor spawned successfully"
|
|
62
|
-
data.pop("error", None)
|
|
63
|
-
else:
|
|
64
|
-
if not data.get("error"):
|
|
65
|
-
data["error"] = data.get("message") or "Failed to spawn actor"
|
|
66
|
-
if not data.get("message"):
|
|
67
|
-
data["message"] = data["error"]
|
|
68
|
-
if not data.get("warnings"):
|
|
69
|
-
data.pop("warnings", None)
|
|
70
|
-
if not data.get("details"):
|
|
71
|
-
data.pop("details", None)
|
|
72
|
-
return data
|
|
73
|
-
|
|
74
|
-
try:
|
|
75
|
-
les = unreal.get_editor_subsystem(unreal.LevelEditorSubsystem)
|
|
76
|
-
if les and les.is_in_play_in_editor():
|
|
77
|
-
result["message"] = "Cannot spawn actors while in Play In Editor mode. Please stop PIE first."
|
|
78
|
-
result["error"] = result["message"]
|
|
79
|
-
result["details"].append("Play In Editor mode detected")
|
|
80
|
-
print('RESULT:' + json.dumps(finalize()))
|
|
81
|
-
raise SystemExit(0)
|
|
82
|
-
except SystemExit:
|
|
83
|
-
raise
|
|
84
|
-
except Exception:
|
|
85
|
-
result["warnings"].append("Unable to determine Play In Editor state")
|
|
86
|
-
|
|
87
|
-
if result["requestedClass"] in abstract_classes:
|
|
88
|
-
result["message"] = f"Cannot spawn {result['requestedClass']}: class is abstract and cannot be instantiated"
|
|
89
|
-
result["error"] = result["message"]
|
|
90
|
-
else:
|
|
91
|
-
try:
|
|
92
|
-
class_path = result["resolvedClass"]
|
|
93
|
-
requested_path = result["requestedClass"]
|
|
94
|
-
location = unreal.Vector(${locX}, ${locY}, ${locZ})
|
|
95
|
-
rotation = unreal.Rotator(${rotPitch}, ${rotYaw}, ${rotRoll})
|
|
96
|
-
actor = None
|
|
97
|
-
|
|
98
|
-
simple_name = requested_path.split('/')[-1] if '/' in requested_path else requested_path
|
|
99
|
-
if '.' in simple_name:
|
|
100
|
-
simple_name = simple_name.split('.')[-1]
|
|
101
|
-
simple_name_lower = simple_name.lower()
|
|
102
|
-
class_lookup_name = class_path.split('.')[-1] if '.' in class_path else simple_name
|
|
103
|
-
|
|
104
|
-
result["details"].append(f"Attempting spawn using class path: {class_path}")
|
|
105
|
-
|
|
106
|
-
if class_path.startswith('/Game') or class_path.startswith('/Engine'):
|
|
107
|
-
try:
|
|
108
|
-
asset = unreal.EditorAssetLibrary.load_asset(class_path)
|
|
109
|
-
except Exception as asset_error:
|
|
110
|
-
asset = None
|
|
111
|
-
result["warnings"].append(f"Failed to load asset for {class_path}: {asset_error}")
|
|
112
|
-
if asset:
|
|
113
|
-
if isinstance(asset, unreal.Blueprint):
|
|
114
|
-
try:
|
|
115
|
-
actor_class = asset.generated_class()
|
|
116
|
-
except Exception as blueprint_error:
|
|
117
|
-
actor_class = None
|
|
118
|
-
result["warnings"].append(f"Failed to resolve blueprint class: {blueprint_error}")
|
|
119
|
-
if actor_class:
|
|
120
|
-
actor = spawn_actor_from_class(actor_class, location, rotation)
|
|
121
|
-
if actor:
|
|
122
|
-
result["details"].append("Spawned using Blueprint generated class")
|
|
123
|
-
elif isinstance(asset, unreal.StaticMesh):
|
|
124
|
-
actor = spawn_actor_from_class(unreal.StaticMeshActor, location, rotation)
|
|
125
|
-
if actor:
|
|
126
|
-
mesh_component = actor.get_component_by_class(unreal.StaticMeshComponent)
|
|
127
|
-
if mesh_component:
|
|
128
|
-
mesh_component.set_static_mesh(asset)
|
|
129
|
-
mesh_component.set_editor_property('mobility', unreal.ComponentMobility.MOVABLE)
|
|
130
|
-
result["details"].append("Applied static mesh to spawned StaticMeshActor")
|
|
131
|
-
|
|
132
|
-
if not actor:
|
|
133
|
-
shape_map = {
|
|
134
|
-
'cube': '/Engine/BasicShapes/Cube',
|
|
135
|
-
'sphere': '/Engine/BasicShapes/Sphere',
|
|
136
|
-
'cylinder': '/Engine/BasicShapes/Cylinder',
|
|
137
|
-
'cone': '/Engine/BasicShapes/Cone',
|
|
138
|
-
'plane': '/Engine/BasicShapes/Plane',
|
|
139
|
-
'torus': '/Engine/BasicShapes/Torus'
|
|
140
|
-
}
|
|
141
|
-
mesh_path = shape_map.get(simple_name_lower)
|
|
142
|
-
if not mesh_path and class_path.startswith('/Engine/BasicShapes'):
|
|
143
|
-
mesh_path = class_path
|
|
144
|
-
if mesh_path:
|
|
145
|
-
try:
|
|
146
|
-
shape_mesh = unreal.EditorAssetLibrary.load_asset(mesh_path)
|
|
147
|
-
except Exception as shape_error:
|
|
148
|
-
shape_mesh = None
|
|
149
|
-
result["warnings"].append(f"Failed to load shape mesh {mesh_path}: {shape_error}")
|
|
150
|
-
if shape_mesh:
|
|
151
|
-
actor = spawn_actor_from_class(unreal.StaticMeshActor, location, rotation)
|
|
152
|
-
if actor:
|
|
153
|
-
mesh_component = actor.get_component_by_class(unreal.StaticMeshComponent)
|
|
154
|
-
if mesh_component:
|
|
155
|
-
mesh_component.set_static_mesh(shape_mesh)
|
|
156
|
-
mesh_component.set_editor_property('mobility', unreal.ComponentMobility.MOVABLE)
|
|
157
|
-
result["details"].append(f"Spawned StaticMeshActor with mesh {mesh_path}")
|
|
158
|
-
|
|
159
|
-
if not actor:
|
|
160
|
-
if class_lookup_name == "StaticMeshActor":
|
|
161
|
-
actor = spawn_actor_from_class(unreal.StaticMeshActor, location, rotation)
|
|
162
|
-
if actor:
|
|
163
|
-
try:
|
|
164
|
-
cube_mesh = unreal.EditorAssetLibrary.load_asset('/Engine/BasicShapes/Cube')
|
|
165
|
-
except Exception as cube_error:
|
|
166
|
-
cube_mesh = None
|
|
167
|
-
result["warnings"].append(f"Failed to load default cube mesh: {cube_error}")
|
|
168
|
-
if cube_mesh:
|
|
169
|
-
mesh_component = actor.get_component_by_class(unreal.StaticMeshComponent)
|
|
170
|
-
if mesh_component:
|
|
171
|
-
mesh_component.set_static_mesh(cube_mesh)
|
|
172
|
-
mesh_component.set_editor_property('mobility', unreal.ComponentMobility.MOVABLE)
|
|
173
|
-
result["details"].append("Applied default cube mesh to StaticMeshActor")
|
|
174
|
-
elif class_lookup_name == "CameraActor":
|
|
175
|
-
actor = spawn_actor_from_class(unreal.CameraActor, location, rotation)
|
|
176
|
-
if actor:
|
|
177
|
-
result["details"].append("Spawned CameraActor via reflected class lookup")
|
|
178
|
-
else:
|
|
179
|
-
actor_class = getattr(unreal, class_lookup_name, None)
|
|
180
|
-
if actor_class:
|
|
181
|
-
actor = spawn_actor_from_class(actor_class, location, rotation)
|
|
182
|
-
if actor:
|
|
183
|
-
result["details"].append(f"Spawned {class_lookup_name} via reflected class lookup")
|
|
184
|
-
|
|
185
|
-
if actor:
|
|
186
|
-
desired_name = (result.get("requestedActorName") or "").strip()
|
|
187
|
-
actor_name = ""
|
|
188
|
-
if desired_name:
|
|
189
|
-
try:
|
|
190
|
-
try:
|
|
191
|
-
actor.set_actor_label(desired_name, True)
|
|
192
|
-
except TypeError:
|
|
193
|
-
actor.set_actor_label(desired_name)
|
|
194
|
-
actor_name = actor.get_actor_label() or desired_name
|
|
195
|
-
except Exception as label_error:
|
|
196
|
-
result["warnings"].append(f"Failed to honor requested actor name '{desired_name}': {label_error}")
|
|
197
|
-
if not actor_name:
|
|
198
|
-
timestamp = int(time.time() * 1000) % 10000
|
|
199
|
-
base_name = simple_name or class_lookup_name or class_path.split('/')[-1]
|
|
200
|
-
fallback_name = f"{base_name}_{timestamp}"
|
|
201
|
-
try:
|
|
202
|
-
actor.set_actor_label(fallback_name)
|
|
203
|
-
except Exception as label_error:
|
|
204
|
-
result["warnings"].append(f"Failed to set actor label: {label_error}")
|
|
205
|
-
actor_name = actor.get_actor_label() or fallback_name
|
|
206
|
-
result["success"] = True
|
|
207
|
-
result["actorName"] = actor_name
|
|
208
|
-
if not result["message"]:
|
|
209
|
-
result["message"] = f"Spawned {actor_name} at ({location.x}, {location.y}, {location.z})"
|
|
210
|
-
else:
|
|
211
|
-
result["message"] = f"Failed to spawn actor from: {class_path}. Try using /Engine/BasicShapes/Cube or StaticMeshActor"
|
|
212
|
-
result["error"] = result["message"]
|
|
213
|
-
except Exception as spawn_error:
|
|
214
|
-
result["error"] = f"Error spawning actor: {spawn_error}"
|
|
215
|
-
if not result["message"]:
|
|
216
|
-
result["message"] = result["error"]
|
|
217
|
-
|
|
218
|
-
print('RESULT:' + json.dumps(finalize()))
|
|
219
|
-
`.trim();
|
|
220
30
|
try {
|
|
221
|
-
const
|
|
222
|
-
const
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
31
|
+
const bridge = this.getAutomationBridge();
|
|
32
|
+
const timeoutMs = typeof params.timeoutMs === 'number' && params.timeoutMs > 0 ? params.timeoutMs : undefined;
|
|
33
|
+
const response = await bridge.sendAutomationRequest('control_actor', {
|
|
34
|
+
action: 'spawn',
|
|
35
|
+
classPath: mappedClassPath,
|
|
36
|
+
location: { x: locX, y: locY, z: locZ },
|
|
37
|
+
rotation: { pitch: rotPitch, yaw: rotYaw, roll: rotRoll },
|
|
38
|
+
actorName: sanitizedActorName,
|
|
39
|
+
meshPath: params.meshPath
|
|
40
|
+
}, timeoutMs ? { timeoutMs } : undefined);
|
|
41
|
+
if (!response || !response.success) {
|
|
42
|
+
const error = response?.error;
|
|
43
|
+
const errorMsg = typeof error === 'string' ? error : error?.message || response?.message || 'Failed to spawn actor';
|
|
44
|
+
throw new Error(errorMsg);
|
|
228
45
|
}
|
|
229
|
-
const
|
|
230
|
-
const resolvedClass = coerceString(interpreted.payload.resolvedClass) ?? mappedClassPath;
|
|
231
|
-
const requestedClass = coerceString(interpreted.payload.requestedClass) ?? className;
|
|
232
|
-
const locationVector = coerceVector3(interpreted.payload.location) ?? [locX, locY, locZ];
|
|
233
|
-
const rotationVector = coerceVector3(interpreted.payload.rotation) ?? [rotPitch, rotYaw, rotRoll];
|
|
46
|
+
const data = response.data || {};
|
|
234
47
|
const result = {
|
|
235
48
|
success: true,
|
|
236
|
-
message:
|
|
237
|
-
actorName:
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
49
|
+
message: response.message || `Spawned actor ${className}`,
|
|
50
|
+
actorName: data.name || response.actorName,
|
|
51
|
+
actorPath: data.objectPath || response.actorPath,
|
|
52
|
+
resolvedClass: mappedClassPath,
|
|
53
|
+
requestedClass: className,
|
|
54
|
+
location: { x: locX, y: locY, z: locZ },
|
|
55
|
+
rotation: { pitch: rotPitch, yaw: rotYaw, roll: rotRoll },
|
|
56
|
+
data: data,
|
|
57
|
+
actor: {
|
|
58
|
+
name: data.name || response.actorName,
|
|
59
|
+
path: data.objectPath || response.actorPath || mappedClassPath
|
|
60
|
+
}
|
|
242
61
|
};
|
|
243
|
-
if (
|
|
244
|
-
result.warnings =
|
|
62
|
+
if (response.warnings?.length) {
|
|
63
|
+
result.warnings = response.warnings;
|
|
245
64
|
}
|
|
246
|
-
if (
|
|
247
|
-
result.details =
|
|
65
|
+
if (response.details?.length) {
|
|
66
|
+
result.details = response.details;
|
|
67
|
+
}
|
|
68
|
+
if (response.componentPaths?.length) {
|
|
69
|
+
result.componentPaths = response.componentPaths;
|
|
248
70
|
}
|
|
249
71
|
return result;
|
|
250
72
|
}
|
|
251
73
|
catch (err) {
|
|
252
|
-
throw new Error(`Failed to spawn actor
|
|
74
|
+
throw new Error(`Failed to spawn actor: ${err}`);
|
|
253
75
|
}
|
|
254
76
|
}
|
|
255
|
-
async
|
|
256
|
-
|
|
257
|
-
const
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
const pieCheckResult = await this.bridge.executePython(pieCheckPython);
|
|
269
|
-
const outputStr = typeof pieCheckResult === 'string' ? pieCheckResult : JSON.stringify(pieCheckResult);
|
|
270
|
-
if (outputStr.includes('PIE_ACTIVE')) {
|
|
271
|
-
throw new Error('Cannot spawn actors while in Play In Editor mode. Please stop PIE first.');
|
|
272
|
-
}
|
|
77
|
+
async delete(params) {
|
|
78
|
+
if (params.actorNames && Array.isArray(params.actorNames)) {
|
|
79
|
+
const names = params.actorNames
|
|
80
|
+
.filter(name => typeof name === 'string')
|
|
81
|
+
.map(name => name.trim())
|
|
82
|
+
.filter(name => name.length > 0);
|
|
83
|
+
if (names.length === 0) {
|
|
84
|
+
return {
|
|
85
|
+
success: true,
|
|
86
|
+
message: 'No actors provided for deletion; no-op',
|
|
87
|
+
deleted: [],
|
|
88
|
+
noOp: true
|
|
89
|
+
};
|
|
273
90
|
}
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
91
|
+
const bridge = this.getAutomationBridge();
|
|
92
|
+
const response = await bridge.sendAutomationRequest('control_actor', {
|
|
93
|
+
action: 'delete',
|
|
94
|
+
actorNames: names
|
|
95
|
+
});
|
|
96
|
+
const result = (response?.data || response?.result || response) ?? {};
|
|
97
|
+
const deleted = result.deleted ?? names;
|
|
98
|
+
const missing = result.missing ?? [];
|
|
99
|
+
const errorObj = response?.error;
|
|
100
|
+
const errorCode = (typeof errorObj === 'object' ? errorObj.code : String(errorObj || result.error || '')).toUpperCase();
|
|
101
|
+
if (response && response.success === false && errorCode === 'DELETE_PARTIAL') {
|
|
102
|
+
return {
|
|
103
|
+
success: true,
|
|
104
|
+
message: errorObj?.message || response.message || 'Some actors could not be deleted',
|
|
105
|
+
deleted,
|
|
106
|
+
missing,
|
|
107
|
+
partial: true
|
|
108
|
+
};
|
|
280
109
|
}
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
// Check if this is an abstract class
|
|
284
|
-
if (abstractClasses.includes(params.classPath)) {
|
|
285
|
-
throw new Error(`Cannot spawn ${params.classPath}: class is abstract and cannot be instantiated`);
|
|
110
|
+
if (!response || response.success === false) {
|
|
111
|
+
throw new Error(errorObj?.message || response?.message || 'Failed to delete actors');
|
|
286
112
|
}
|
|
287
|
-
// Get the console-friendly class name
|
|
288
|
-
const spawnClass = this.getConsoleClassName(params.classPath);
|
|
289
|
-
// Use summon command with location if provided
|
|
290
|
-
const command = `summon ${spawnClass} ${locX} ${locY} ${locZ}`;
|
|
291
|
-
await this.bridge.httpCall('/remote/object/call', 'PUT', {
|
|
292
|
-
objectPath: '/Script/Engine.Default__KismetSystemLibrary',
|
|
293
|
-
functionName: 'ExecuteConsoleCommand',
|
|
294
|
-
parameters: {
|
|
295
|
-
WorldContextObject: null,
|
|
296
|
-
Command: command,
|
|
297
|
-
SpecificPlayer: null
|
|
298
|
-
},
|
|
299
|
-
generateTransaction: false
|
|
300
|
-
});
|
|
301
|
-
// Console commands don't reliably report success/failure
|
|
302
|
-
// We can't guarantee this actually worked, so indicate uncertainty
|
|
303
113
|
return {
|
|
304
114
|
success: true,
|
|
305
|
-
message:
|
|
306
|
-
|
|
115
|
+
message: response.message || 'Deleted actors',
|
|
116
|
+
deleted: result.deleted || deleted,
|
|
117
|
+
...result
|
|
307
118
|
};
|
|
308
119
|
}
|
|
309
|
-
|
|
310
|
-
throw new Error(
|
|
120
|
+
if (!params.actorName || typeof params.actorName !== 'string') {
|
|
121
|
+
throw new Error('Invalid actorName');
|
|
311
122
|
}
|
|
123
|
+
return this.sendRequest('delete', { actorName: params.actorName }, 'control_actor');
|
|
312
124
|
}
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
125
|
+
async applyForce(params) {
|
|
126
|
+
if (!params.actorName || typeof params.actorName !== 'string') {
|
|
127
|
+
throw new Error('Invalid actorName');
|
|
128
|
+
}
|
|
129
|
+
if (!params.force || typeof params.force !== 'object') {
|
|
130
|
+
throw new Error('Invalid force vector');
|
|
131
|
+
}
|
|
132
|
+
const [forceX, forceY, forceZ] = ensureVector3(params.force, 'force vector');
|
|
133
|
+
if (forceX === 0 && forceY === 0 && forceZ === 0) {
|
|
134
|
+
return {
|
|
135
|
+
success: true,
|
|
136
|
+
message: `Zero force provided for ${params.actorName}; no-op`,
|
|
137
|
+
physicsEnabled: false,
|
|
138
|
+
noOp: true
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
return this.sendRequest('apply_force', {
|
|
142
|
+
actorName: params.actorName,
|
|
143
|
+
force: { x: forceX, y: forceY, z: forceZ }
|
|
144
|
+
}, 'control_actor');
|
|
327
145
|
}
|
|
328
146
|
resolveActorClass(classPath) {
|
|
329
|
-
// Map common names to full Unreal class paths
|
|
330
147
|
const classMap = {
|
|
331
148
|
'PointLight': '/Script/Engine.PointLight',
|
|
332
149
|
'DirectionalLight': '/Script/Engine.DirectionalLight',
|
|
@@ -349,55 +166,283 @@ def spawn_actor_from_class(actor_class, location, rotation):
|
|
|
349
166
|
'AtmosphericFog': '/Script/Engine.AtmosphericFog',
|
|
350
167
|
'SphereReflectionCapture': '/Script/Engine.SphereReflectionCapture',
|
|
351
168
|
'BoxReflectionCapture': '/Script/Engine.BoxReflectionCapture',
|
|
352
|
-
// PlaneReflectionCapture is abstract and cannot be spawned
|
|
353
169
|
'DecalActor': '/Script/Engine.DecalActor'
|
|
354
170
|
};
|
|
355
|
-
// Check if it's a simple name that needs mapping
|
|
356
171
|
if (classMap[classPath]) {
|
|
357
172
|
return classMap[classPath];
|
|
358
173
|
}
|
|
359
|
-
// Check if it already looks like a full path
|
|
360
174
|
if (classPath.startsWith('/Script/') || classPath.startsWith('/Game/')) {
|
|
361
175
|
return classPath;
|
|
362
176
|
}
|
|
363
177
|
if (classPath.startsWith('/Engine/')) {
|
|
364
178
|
return classPath;
|
|
365
179
|
}
|
|
366
|
-
// Check for Blueprint paths
|
|
367
180
|
if (classPath.includes('Blueprint') || classPath.includes('BP_')) {
|
|
368
|
-
// Ensure it has the proper prefix
|
|
369
181
|
if (!classPath.startsWith('/Game/')) {
|
|
370
182
|
return '/Game/' + classPath;
|
|
371
183
|
}
|
|
372
184
|
return classPath;
|
|
373
185
|
}
|
|
374
|
-
// Default: assume it's an engine class
|
|
375
186
|
return '/Script/Engine.' + classPath;
|
|
376
187
|
}
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
|
|
188
|
+
async spawnBlueprint(params) {
|
|
189
|
+
const blueprintPath = typeof params.blueprintPath === 'string' ? params.blueprintPath.trim() : '';
|
|
190
|
+
if (!blueprintPath) {
|
|
191
|
+
throw new Error('Invalid blueprintPath');
|
|
192
|
+
}
|
|
193
|
+
const actorName = typeof params.actorName === 'string' && params.actorName.trim().length > 0 ? params.actorName.trim() : undefined;
|
|
194
|
+
const location = params.location ? ensureVector3(params.location, 'spawn_blueprint location') : undefined;
|
|
195
|
+
const rotation = params.rotation ? ensureRotation(params.rotation, 'spawn_blueprint rotation') : undefined;
|
|
196
|
+
const payload = { blueprintPath };
|
|
197
|
+
if (actorName)
|
|
198
|
+
payload.actorName = actorName;
|
|
199
|
+
if (location)
|
|
200
|
+
payload.location = { x: location[0], y: location[1], z: location[2] };
|
|
201
|
+
if (rotation)
|
|
202
|
+
payload.rotation = { pitch: rotation[0], yaw: rotation[1], roll: rotation[2] };
|
|
203
|
+
return this.sendRequest('spawn_blueprint', payload, 'control_actor');
|
|
204
|
+
}
|
|
205
|
+
async setTransform(params) {
|
|
206
|
+
const actorName = typeof params.actorName === 'string' ? params.actorName.trim() : '';
|
|
207
|
+
if (!actorName) {
|
|
208
|
+
throw new Error('Invalid actorName');
|
|
209
|
+
}
|
|
210
|
+
const payload = { actorName };
|
|
211
|
+
if (params.location) {
|
|
212
|
+
const loc = ensureVector3(params.location, 'set_transform location');
|
|
213
|
+
payload.location = { x: loc[0], y: loc[1], z: loc[2] };
|
|
214
|
+
}
|
|
215
|
+
if (params.rotation) {
|
|
216
|
+
const rot = ensureRotation(params.rotation, 'set_transform rotation');
|
|
217
|
+
payload.rotation = { pitch: rot[0], yaw: rot[1], roll: rot[2] };
|
|
218
|
+
}
|
|
219
|
+
if (params.scale) {
|
|
220
|
+
const scl = ensureVector3(params.scale, 'set_transform scale');
|
|
221
|
+
payload.scale = { x: scl[0], y: scl[1], z: scl[2] };
|
|
222
|
+
}
|
|
223
|
+
return this.sendRequest('set_transform', payload, 'control_actor');
|
|
224
|
+
}
|
|
225
|
+
async getTransform(actorName) {
|
|
226
|
+
if (typeof actorName !== 'string' || actorName.trim().length === 0) {
|
|
227
|
+
throw new Error('Invalid actorName');
|
|
228
|
+
}
|
|
229
|
+
return this.sendRequest('get_transform', { actorName }, 'control_actor')
|
|
230
|
+
.then(response => {
|
|
231
|
+
return response;
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
async setVisibility(params) {
|
|
235
|
+
const actorName = typeof params.actorName === 'string' ? params.actorName.trim() : '';
|
|
236
|
+
if (!actorName) {
|
|
237
|
+
throw new Error('Invalid actorName');
|
|
238
|
+
}
|
|
239
|
+
return this.sendRequest('set_visibility', { actorName, visible: Boolean(params.visible) }, 'control_actor');
|
|
240
|
+
}
|
|
241
|
+
async addComponent(params) {
|
|
242
|
+
const actorName = typeof params.actorName === 'string' ? params.actorName.trim() : '';
|
|
243
|
+
const componentType = typeof params.componentType === 'string' ? params.componentType.trim() : '';
|
|
244
|
+
if (!actorName)
|
|
245
|
+
throw new Error('Invalid actorName');
|
|
246
|
+
if (!componentType)
|
|
247
|
+
throw new Error('Invalid componentType');
|
|
248
|
+
return this.sendRequest('add_component', {
|
|
249
|
+
actorName,
|
|
250
|
+
componentType,
|
|
251
|
+
componentName: typeof params.componentName === 'string' ? params.componentName : undefined,
|
|
252
|
+
properties: params.properties
|
|
253
|
+
}, 'control_actor');
|
|
254
|
+
}
|
|
255
|
+
async setComponentProperties(params) {
|
|
256
|
+
const actorName = typeof params.actorName === 'string' ? params.actorName.trim() : '';
|
|
257
|
+
const componentName = typeof params.componentName === 'string' ? params.componentName.trim() : '';
|
|
258
|
+
if (!actorName)
|
|
259
|
+
throw new Error('Invalid actorName');
|
|
260
|
+
if (!componentName)
|
|
261
|
+
throw new Error('Invalid componentName');
|
|
262
|
+
return this.sendRequest('set_component_properties', {
|
|
263
|
+
actorName,
|
|
264
|
+
componentName,
|
|
265
|
+
properties: params.properties ?? {}
|
|
266
|
+
}, 'control_actor');
|
|
267
|
+
}
|
|
268
|
+
async getComponents(actorName) {
|
|
269
|
+
if (typeof actorName !== 'string' || actorName.trim().length === 0) {
|
|
270
|
+
throw new Error('Invalid actorName');
|
|
271
|
+
}
|
|
272
|
+
const response = await this.sendRequest('get_components', { actorName }, 'control_actor');
|
|
273
|
+
if (!response.success) {
|
|
274
|
+
return { success: false, error: response.error || `Failed to get components for actor ${actorName}` };
|
|
275
|
+
}
|
|
276
|
+
const data = response.data ?? response.result ?? response;
|
|
277
|
+
const components = Array.isArray(data)
|
|
278
|
+
? data
|
|
279
|
+
: (Array.isArray(data?.components) ? data.components : []);
|
|
280
|
+
const count = typeof data?.count === 'number' ? data.count : components.length;
|
|
281
|
+
return {
|
|
282
|
+
success: true,
|
|
283
|
+
message: 'Actor components retrieved',
|
|
284
|
+
components,
|
|
285
|
+
count
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
async duplicate(params) {
|
|
289
|
+
const actorName = typeof params.actorName === 'string' ? params.actorName.trim() : '';
|
|
290
|
+
if (!actorName)
|
|
291
|
+
throw new Error('Invalid actorName');
|
|
292
|
+
const payload = { actorName };
|
|
293
|
+
if (typeof params.newName === 'string' && params.newName.trim().length > 0) {
|
|
294
|
+
payload.newName = params.newName.trim();
|
|
295
|
+
}
|
|
296
|
+
if (params.offset) {
|
|
297
|
+
const offs = ensureVector3(params.offset, 'duplicate offset');
|
|
298
|
+
const origin = [0, 0, 0];
|
|
299
|
+
const calculatedOffset = wasmIntegration.vectorAdd(origin, offs);
|
|
300
|
+
console.error('[WASM] Using vectorAdd for duplicate offset calculation');
|
|
301
|
+
payload.offset = { x: calculatedOffset[0], y: calculatedOffset[1], z: calculatedOffset[2] };
|
|
302
|
+
}
|
|
303
|
+
return this.sendRequest('duplicate', payload, 'control_actor');
|
|
304
|
+
}
|
|
305
|
+
async addTag(params) {
|
|
306
|
+
const actorName = typeof params.actorName === 'string' ? params.actorName.trim() : '';
|
|
307
|
+
const tag = typeof params.tag === 'string' ? params.tag.trim() : '';
|
|
308
|
+
if (!actorName)
|
|
309
|
+
throw new Error('Invalid actorName');
|
|
310
|
+
if (!tag)
|
|
311
|
+
throw new Error('Invalid tag');
|
|
312
|
+
return this.sendRequest('add_tag', { actorName, tag }, 'control_actor');
|
|
313
|
+
}
|
|
314
|
+
async removeTag(params) {
|
|
315
|
+
const actorName = typeof params.actorName === 'string' ? params.actorName.trim() : '';
|
|
316
|
+
const tag = typeof params.tag === 'string' ? params.tag.trim() : '';
|
|
317
|
+
if (!actorName)
|
|
318
|
+
throw new Error('Invalid actorName');
|
|
319
|
+
if (!tag)
|
|
320
|
+
throw new Error('Invalid tag');
|
|
321
|
+
return this.sendRequest('remove_tag', { actorName, tag }, 'control_actor');
|
|
322
|
+
}
|
|
323
|
+
async findByTag(params) {
|
|
324
|
+
const tag = typeof params.tag === 'string' ? params.tag.trim() : '';
|
|
325
|
+
if (!tag) {
|
|
326
|
+
return {
|
|
327
|
+
success: true,
|
|
328
|
+
message: 'Empty tag query; no actors matched',
|
|
329
|
+
data: {
|
|
330
|
+
actors: [],
|
|
331
|
+
count: 0
|
|
332
|
+
}
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
return this.sendRequest('find_by_tag', {
|
|
336
|
+
tag,
|
|
337
|
+
matchType: typeof params.matchType === 'string' ? params.matchType : undefined
|
|
338
|
+
}, 'control_actor');
|
|
339
|
+
}
|
|
340
|
+
async findByName(name) {
|
|
341
|
+
if (typeof name !== 'string' || name.trim().length === 0) {
|
|
342
|
+
throw new Error('Invalid actor name query');
|
|
343
|
+
}
|
|
344
|
+
return this.sendRequest('find_by_name', { name: name.trim() }, 'control_actor');
|
|
345
|
+
}
|
|
346
|
+
async detach(actorName) {
|
|
347
|
+
if (typeof actorName !== 'string' || actorName.trim().length === 0) {
|
|
348
|
+
throw new Error('Invalid actorName');
|
|
349
|
+
}
|
|
350
|
+
return this.sendRequest('detach', { actorName }, 'control_actor');
|
|
351
|
+
}
|
|
352
|
+
async attach(params) {
|
|
353
|
+
const child = typeof params.childActor === 'string' ? params.childActor.trim() : '';
|
|
354
|
+
const parent = typeof params.parentActor === 'string' ? params.parentActor.trim() : '';
|
|
355
|
+
if (!child)
|
|
356
|
+
throw new Error('Invalid childActor');
|
|
357
|
+
if (!parent)
|
|
358
|
+
throw new Error('Invalid parentActor');
|
|
359
|
+
return this.sendRequest('attach', { childActor: child, parentActor: parent }, 'control_actor');
|
|
360
|
+
}
|
|
361
|
+
async deleteByTag(tag) {
|
|
362
|
+
if (typeof tag !== 'string' || tag.trim().length === 0) {
|
|
363
|
+
throw new Error('Invalid tag');
|
|
364
|
+
}
|
|
365
|
+
return this.sendRequest('delete_by_tag', { tag: tag.trim() }, 'control_actor');
|
|
366
|
+
}
|
|
367
|
+
async setBlueprintVariables(params) {
|
|
368
|
+
const actorName = typeof params.actorName === 'string' ? params.actorName.trim() : '';
|
|
369
|
+
if (!actorName)
|
|
370
|
+
throw new Error('Invalid actorName');
|
|
371
|
+
return this.sendRequest('set_blueprint_variables', { actorName, variables: params.variables ?? {} }, 'control_actor');
|
|
372
|
+
}
|
|
373
|
+
async createSnapshot(params) {
|
|
374
|
+
const actorName = typeof params.actorName === 'string' ? params.actorName.trim() : '';
|
|
375
|
+
const snapshotName = typeof params.snapshotName === 'string' ? params.snapshotName.trim() : '';
|
|
376
|
+
if (!actorName)
|
|
377
|
+
throw new Error('Invalid actorName');
|
|
378
|
+
if (!snapshotName)
|
|
379
|
+
throw new Error('Invalid snapshotName');
|
|
380
|
+
return this.sendRequest('create_snapshot', { actorName, snapshotName }, 'control_actor');
|
|
381
|
+
}
|
|
382
|
+
async restoreSnapshot(params) {
|
|
383
|
+
const actorName = typeof params.actorName === 'string' ? params.actorName.trim() : '';
|
|
384
|
+
const snapshotName = typeof params.snapshotName === 'string' ? params.snapshotName.trim() : '';
|
|
385
|
+
if (!actorName)
|
|
386
|
+
throw new Error('Invalid actorName');
|
|
387
|
+
if (!snapshotName)
|
|
388
|
+
throw new Error('Invalid snapshotName');
|
|
389
|
+
return this.sendRequest('restore_snapshot', { actorName, snapshotName }, 'control_actor');
|
|
390
|
+
}
|
|
391
|
+
async exportActor(params) {
|
|
392
|
+
const actorName = typeof params.actorName === 'string' ? params.actorName.trim() : '';
|
|
393
|
+
if (!actorName)
|
|
394
|
+
throw new Error('Invalid actorName');
|
|
395
|
+
return this.sendRequest('export', {
|
|
396
|
+
actorName,
|
|
397
|
+
destinationPath: params.destinationPath
|
|
398
|
+
}, 'control_actor');
|
|
399
|
+
}
|
|
400
|
+
async getBoundingBox(actorName) {
|
|
401
|
+
if (typeof actorName !== 'string' || actorName.trim().length === 0) {
|
|
402
|
+
throw new Error('Invalid actorName');
|
|
403
|
+
}
|
|
404
|
+
const response = await this.sendRequest('get_bounding_box', { actorName }, 'control_actor');
|
|
405
|
+
if (!response.success) {
|
|
406
|
+
return { success: false, error: response.error || `Failed to get bounding box for actor ${actorName}` };
|
|
407
|
+
}
|
|
408
|
+
return {
|
|
409
|
+
success: true,
|
|
410
|
+
message: 'Bounding box retrieved',
|
|
411
|
+
boundingBox: response.data || response.result || {}
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
async getMetadata(actorName) {
|
|
415
|
+
if (typeof actorName !== 'string' || actorName.trim().length === 0) {
|
|
416
|
+
throw new Error('Invalid actorName');
|
|
417
|
+
}
|
|
418
|
+
const response = await this.sendRequest('get_metadata', { actorName }, 'control_actor');
|
|
419
|
+
if (!response.success) {
|
|
420
|
+
return { success: false, error: response.error || `Failed to get metadata for actor ${actorName}` };
|
|
421
|
+
}
|
|
422
|
+
return {
|
|
423
|
+
success: true,
|
|
424
|
+
message: 'Actor metadata retrieved',
|
|
425
|
+
metadata: response.data || response.result || {}
|
|
426
|
+
};
|
|
427
|
+
}
|
|
428
|
+
async listActors(params) {
|
|
429
|
+
const payload = {};
|
|
430
|
+
if (params?.filter) {
|
|
431
|
+
payload.filter = params.filter;
|
|
432
|
+
}
|
|
433
|
+
const response = await this.sendRequest('list_actors', payload, 'control_actor');
|
|
434
|
+
if (!response.success) {
|
|
435
|
+
return { success: false, error: response.error || 'Failed to list actors' };
|
|
436
|
+
}
|
|
437
|
+
const dataObj = response.data || response.result || {};
|
|
438
|
+
const actorsRaw = response.actors || (dataObj && dataObj.actors) || (Array.isArray(dataObj) ? dataObj : []);
|
|
439
|
+
const actors = Array.isArray(actorsRaw) ? actorsRaw : [];
|
|
440
|
+
return {
|
|
441
|
+
success: true,
|
|
442
|
+
message: `Found ${actors.length} actors`,
|
|
443
|
+
actors,
|
|
444
|
+
count: actors.length
|
|
445
|
+
};
|
|
401
446
|
}
|
|
402
447
|
}
|
|
403
448
|
//# sourceMappingURL=actors.js.map
|