unreal-engine-mcp-server 0.4.6 → 0.5.0
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.yml +148 -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 +23 -0
- package/.github/workflows/labeler.yml +16 -0
- package/.github/workflows/links.yml +80 -0
- package/.github/workflows/pr-size-labeler.yml +137 -0
- package/.github/workflows/publish-mcp.yml +12 -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 +269 -22
- package/CONTRIBUTING.md +140 -0
- package/README.md +166 -72
- 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 +27 -0
- package/dist/config.js +60 -0
- package/dist/constants.d.ts +12 -0
- package/dist/constants.js +12 -0
- package/dist/graphql/resolvers.d.ts +268 -0
- package/dist/graphql/resolvers.js +743 -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 +115 -0
- package/dist/graphql/types.d.ts +7 -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 +31 -18
- package/dist/index.js +119 -604
- package/dist/prompts/index.js +4 -4
- 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 +21 -0
- package/dist/server-setup.js +111 -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 +147 -9
- package/dist/tools/actors.js +350 -311
- package/dist/tools/animation.d.ts +135 -4
- package/dist/tools/animation.js +510 -411
- package/dist/tools/assets.d.ts +117 -19
- package/dist/tools/assets.js +259 -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/helpers.d.ts +29 -0
- package/dist/tools/blueprint/helpers.js +182 -0
- package/dist/tools/blueprint.d.ts +228 -118
- package/dist/tools/blueprint.js +685 -832
- package/dist/tools/consolidated-tool-definitions.d.ts +5475 -1627
- package/dist/tools/consolidated-tool-definitions.js +829 -482
- package/dist/tools/consolidated-tool-handlers.d.ts +2 -1
- package/dist/tools/consolidated-tool-handlers.js +211 -1009
- package/dist/tools/debug.d.ts +143 -85
- package/dist/tools/debug.js +234 -180
- package/dist/tools/dynamic-handler-registry.d.ts +11 -0
- package/dist/tools/dynamic-handler-registry.js +101 -0
- package/dist/tools/editor.d.ts +139 -18
- package/dist/tools/editor.js +239 -244
- package/dist/tools/engine.d.ts +10 -4
- package/dist/tools/engine.js +13 -5
- package/dist/tools/environment.d.ts +36 -0
- package/dist/tools/environment.js +267 -0
- package/dist/tools/foliage.d.ts +105 -14
- package/dist/tools/foliage.js +219 -331
- package/dist/tools/handlers/actor-handlers.d.ts +3 -0
- package/dist/tools/handlers/actor-handlers.js +232 -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 +97 -36
- package/dist/tools/landscape.js +280 -409
- package/dist/tools/level.d.ts +130 -10
- package/dist/tools/level.js +639 -675
- package/dist/tools/lighting.d.ts +77 -38
- package/dist/tools/lighting.js +441 -943
- package/dist/tools/logs.d.ts +45 -0
- package/dist/tools/logs.js +210 -0
- package/dist/tools/materials.d.ts +91 -24
- package/dist/tools/materials.js +190 -118
- package/dist/tools/niagara.d.ts +149 -39
- package/dist/tools/niagara.js +232 -182
- package/dist/tools/performance.d.ts +27 -12
- package/dist/tools/performance.js +204 -122
- package/dist/tools/physics.d.ts +32 -77
- package/dist/tools/physics.js +171 -582
- package/dist/tools/property-dictionary.d.ts +13 -0
- package/dist/tools/property-dictionary.js +82 -0
- package/dist/tools/sequence.d.ts +73 -48
- package/dist/tools/sequence.js +196 -748
- 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 +66 -34
- package/dist/tools/ui.js +134 -214
- package/dist/types/env.d.ts +0 -3
- package/dist/types/env.js +0 -7
- package/dist/types/tool-interfaces.d.ts +898 -0
- package/dist/types/tool-interfaces.js +2 -0
- package/dist/types/tool-types.d.ts +195 -11
- 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 +67 -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/response-factory.d.ts +7 -0
- package/dist/utils/response-factory.js +33 -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 +692 -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 +60 -27
- 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 +131 -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 +57 -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 +12 -0
- package/src/graphql/resolvers.ts +1010 -0
- package/src/graphql/schema.ts +452 -0
- package/src/graphql/server.ts +154 -0
- package/src/graphql/types.ts +7 -0
- package/src/handlers/resource-handlers.ts +186 -0
- package/src/index.ts +152 -649
- package/src/prompts/index.ts +4 -4
- package/src/resources/actors.ts +58 -76
- package/src/resources/assets.ts +147 -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 +148 -0
- package/src/services/health-monitor.ts +132 -0
- package/src/services/metrics-server.ts +142 -0
- package/src/tools/actors.ts +417 -322
- package/src/tools/animation.ts +671 -461
- package/src/tools/assets.ts +353 -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/helpers.ts +189 -0
- package/src/tools/blueprint.ts +787 -965
- package/src/tools/consolidated-tool-definitions.ts +993 -500
- package/src/tools/consolidated-tool-handlers.ts +272 -1122
- package/src/tools/debug.ts +292 -187
- package/src/tools/dynamic-handler-registry.ts +151 -0
- package/src/tools/editor.ts +309 -246
- package/src/tools/engine.ts +14 -3
- package/src/tools/environment.ts +287 -0
- package/src/tools/foliage.ts +314 -379
- package/src/tools/handlers/actor-handlers.ts +271 -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 +394 -489
- package/src/tools/level.ts +752 -694
- package/src/tools/lighting.ts +583 -984
- package/src/tools/logs.ts +219 -0
- package/src/tools/materials.ts +231 -121
- package/src/tools/niagara.ts +293 -168
- package/src/tools/performance.ts +320 -168
- package/src/tools/physics.ts +268 -613
- package/src/tools/property-dictionary.ts +98 -0
- package/src/tools/sequence.ts +255 -815
- package/src/tools/tool-definition-utils.ts +35 -0
- package/src/tools/ui.ts +207 -283
- package/src/types/env.ts +0 -10
- package/src/types/tool-interfaces.ts +250 -0
- package/src/types/tool-types.ts +250 -13
- package/src/unreal-bridge.ts +460 -1550
- package/src/utils/command-validator.ts +75 -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.ts +60 -0
- package/src/utils/response-factory.ts +39 -0
- package/src/utils/response-validator.ts +176 -56
- package/src/utils/result-helpers.ts +21 -19
- package/src/utils/safe-json.ts +14 -11
- package/src/utils/unreal-command-queue.ts +152 -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 +44 -0
- package/tests/test-asset-advanced.mjs +82 -0
- package/tests/test-asset-errors.mjs +35 -0
- package/tests/test-audio.mjs +219 -0
- package/tests/test-automation-timeouts.mjs +98 -0
- package/tests/test-behavior-tree.mjs +261 -0
- package/tests/test-blueprint-events.mjs +35 -0
- package/tests/test-blueprint-graph.mjs +79 -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 +80 -0
- package/tests/test-extra-tools.mjs +38 -0
- package/tests/test-graphql.mjs +322 -0
- package/tests/test-inspect.mjs +72 -0
- package/tests/test-landscape.mjs +60 -0
- package/tests/test-manage-asset.mjs +438 -0
- package/tests/test-manage-level.mjs +70 -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-plugin-handshake.mjs +82 -0
- package/tests/test-render.mjs +33 -0
- package/tests/test-runner.mjs +933 -0
- package/tests/test-search-assets.mjs +66 -0
- package/tests/test-sequence.mjs +68 -0
- package/tests/test-system.mjs +57 -0
- package/tests/test-wasm.mjs +193 -0
- package/tests/test-world-partition.mjs +215 -0
- package/tsconfig.json +3 -3
- 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/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 -572
- package/smithery.yaml +0 -29
- 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,8 @@
|
|
|
1
1
|
import { ensureRotation, ensureVector3 } from '../utils/validation.js';
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
export class ActorTools {
|
|
5
|
-
bridge;
|
|
2
|
+
import { BaseTool } from './base-tool.js';
|
|
3
|
+
export class ActorTools extends BaseTool {
|
|
6
4
|
constructor(bridge) {
|
|
7
|
-
|
|
5
|
+
super(bridge);
|
|
8
6
|
}
|
|
9
7
|
async spawn(params) {
|
|
10
8
|
if (!params.classPath || typeof params.classPath !== 'string' || params.classPath.trim().length === 0) {
|
|
@@ -28,305 +26,121 @@ export class ActorTools {
|
|
|
28
26
|
const mappedClassPath = shapeMapping[lowerName] ?? this.resolveActorClass(className);
|
|
29
27
|
const [locX, locY, locZ] = ensureVector3(params.location ?? { x: 0, y: 0, z: 100 }, 'actor location');
|
|
30
28
|
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
29
|
try {
|
|
221
|
-
const
|
|
222
|
-
const
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
30
|
+
const bridge = this.getAutomationBridge();
|
|
31
|
+
const timeoutMs = typeof params.timeoutMs === 'number' && params.timeoutMs > 0 ? params.timeoutMs : undefined;
|
|
32
|
+
const response = await bridge.sendAutomationRequest('control_actor', {
|
|
33
|
+
action: 'spawn',
|
|
34
|
+
classPath: mappedClassPath,
|
|
35
|
+
location: { x: locX, y: locY, z: locZ },
|
|
36
|
+
rotation: { pitch: rotPitch, yaw: rotYaw, roll: rotRoll },
|
|
37
|
+
actorName: sanitizedActorName,
|
|
38
|
+
meshPath: params.meshPath
|
|
39
|
+
}, timeoutMs ? { timeoutMs } : undefined);
|
|
40
|
+
if (!response || !response.success) {
|
|
41
|
+
throw new Error(response?.error || response?.message || 'Failed to spawn actor');
|
|
228
42
|
}
|
|
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];
|
|
43
|
+
const data = response.data || {};
|
|
234
44
|
const result = {
|
|
235
45
|
success: true,
|
|
236
|
-
message:
|
|
237
|
-
actorName:
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
46
|
+
message: response.message || `Spawned actor ${className}`,
|
|
47
|
+
actorName: data.name || response.actorName,
|
|
48
|
+
actorPath: data.objectPath || response.actorPath,
|
|
49
|
+
resolvedClass: mappedClassPath,
|
|
50
|
+
requestedClass: className,
|
|
51
|
+
location: { x: locX, y: locY, z: locZ },
|
|
52
|
+
rotation: { pitch: rotPitch, yaw: rotYaw, roll: rotRoll },
|
|
53
|
+
data: data,
|
|
54
|
+
actor: {
|
|
55
|
+
name: data.name || response.actorName,
|
|
56
|
+
path: data.objectPath || response.actorPath || mappedClassPath
|
|
57
|
+
}
|
|
242
58
|
};
|
|
243
|
-
if (
|
|
244
|
-
result.warnings =
|
|
59
|
+
if (response.warnings?.length) {
|
|
60
|
+
result.warnings = response.warnings;
|
|
245
61
|
}
|
|
246
|
-
if (
|
|
247
|
-
result.details =
|
|
62
|
+
if (response.details?.length) {
|
|
63
|
+
result.details = response.details;
|
|
64
|
+
}
|
|
65
|
+
if (response.componentPaths?.length) {
|
|
66
|
+
result.componentPaths = response.componentPaths;
|
|
248
67
|
}
|
|
249
68
|
return result;
|
|
250
69
|
}
|
|
251
70
|
catch (err) {
|
|
252
|
-
throw new Error(`Failed to spawn actor
|
|
71
|
+
throw new Error(`Failed to spawn actor: ${err}`);
|
|
253
72
|
}
|
|
254
73
|
}
|
|
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
|
-
}
|
|
74
|
+
async delete(params) {
|
|
75
|
+
if (params.actorNames && Array.isArray(params.actorNames)) {
|
|
76
|
+
const names = params.actorNames
|
|
77
|
+
.filter(name => typeof name === 'string')
|
|
78
|
+
.map(name => name.trim())
|
|
79
|
+
.filter(name => name.length > 0);
|
|
80
|
+
if (names.length === 0) {
|
|
81
|
+
return {
|
|
82
|
+
success: true,
|
|
83
|
+
message: 'No actors provided for deletion; no-op',
|
|
84
|
+
deleted: [],
|
|
85
|
+
noOp: true
|
|
86
|
+
};
|
|
273
87
|
}
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
88
|
+
const bridge = this.getAutomationBridge();
|
|
89
|
+
const response = await bridge.sendAutomationRequest('control_actor', {
|
|
90
|
+
action: 'delete',
|
|
91
|
+
actorNames: names
|
|
92
|
+
});
|
|
93
|
+
const result = (response?.data || response?.result || response) ?? {};
|
|
94
|
+
const deleted = result.deleted ?? names;
|
|
95
|
+
const missing = result.missing ?? [];
|
|
96
|
+
const errorObj = response?.error;
|
|
97
|
+
const errorCode = (typeof errorObj === 'object' ? errorObj.code : String(errorObj || result.error || '')).toUpperCase();
|
|
98
|
+
if (response && response.success === false && errorCode === 'DELETE_PARTIAL') {
|
|
99
|
+
return {
|
|
100
|
+
success: true,
|
|
101
|
+
message: errorObj?.message || response.message || 'Some actors could not be deleted',
|
|
102
|
+
deleted,
|
|
103
|
+
missing,
|
|
104
|
+
partial: true
|
|
105
|
+
};
|
|
280
106
|
}
|
|
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`);
|
|
107
|
+
if (!response || response.success === false) {
|
|
108
|
+
throw new Error(errorObj?.message || response?.message || 'Failed to delete actors');
|
|
286
109
|
}
|
|
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
110
|
return {
|
|
304
111
|
success: true,
|
|
305
|
-
message:
|
|
306
|
-
|
|
112
|
+
message: response.message || 'Deleted actors',
|
|
113
|
+
deleted: result.deleted || deleted,
|
|
114
|
+
...result
|
|
307
115
|
};
|
|
308
116
|
}
|
|
309
|
-
|
|
310
|
-
throw new Error(
|
|
117
|
+
if (!params.actorName || typeof params.actorName !== 'string') {
|
|
118
|
+
throw new Error('Invalid actorName');
|
|
311
119
|
}
|
|
120
|
+
return this.sendRequest('delete', { actorName: params.actorName }, 'control_actor');
|
|
312
121
|
}
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
122
|
+
async applyForce(params) {
|
|
123
|
+
if (!params.actorName || typeof params.actorName !== 'string') {
|
|
124
|
+
throw new Error('Invalid actorName');
|
|
125
|
+
}
|
|
126
|
+
if (!params.force || typeof params.force !== 'object') {
|
|
127
|
+
throw new Error('Invalid force vector');
|
|
128
|
+
}
|
|
129
|
+
const [forceX, forceY, forceZ] = ensureVector3(params.force, 'force vector');
|
|
130
|
+
if (forceX === 0 && forceY === 0 && forceZ === 0) {
|
|
131
|
+
return {
|
|
132
|
+
success: true,
|
|
133
|
+
message: `Zero force provided for ${params.actorName}; no-op`,
|
|
134
|
+
physicsEnabled: false,
|
|
135
|
+
noOp: true
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
return this.sendRequest('apply_force', {
|
|
139
|
+
actorName: params.actorName,
|
|
140
|
+
force: { x: forceX, y: forceY, z: forceZ }
|
|
141
|
+
}, 'control_actor');
|
|
327
142
|
}
|
|
328
143
|
resolveActorClass(classPath) {
|
|
329
|
-
// Map common names to full Unreal class paths
|
|
330
144
|
const classMap = {
|
|
331
145
|
'PointLight': '/Script/Engine.PointLight',
|
|
332
146
|
'DirectionalLight': '/Script/Engine.DirectionalLight',
|
|
@@ -349,55 +163,280 @@ def spawn_actor_from_class(actor_class, location, rotation):
|
|
|
349
163
|
'AtmosphericFog': '/Script/Engine.AtmosphericFog',
|
|
350
164
|
'SphereReflectionCapture': '/Script/Engine.SphereReflectionCapture',
|
|
351
165
|
'BoxReflectionCapture': '/Script/Engine.BoxReflectionCapture',
|
|
352
|
-
// PlaneReflectionCapture is abstract and cannot be spawned
|
|
353
166
|
'DecalActor': '/Script/Engine.DecalActor'
|
|
354
167
|
};
|
|
355
|
-
// Check if it's a simple name that needs mapping
|
|
356
168
|
if (classMap[classPath]) {
|
|
357
169
|
return classMap[classPath];
|
|
358
170
|
}
|
|
359
|
-
// Check if it already looks like a full path
|
|
360
171
|
if (classPath.startsWith('/Script/') || classPath.startsWith('/Game/')) {
|
|
361
172
|
return classPath;
|
|
362
173
|
}
|
|
363
174
|
if (classPath.startsWith('/Engine/')) {
|
|
364
175
|
return classPath;
|
|
365
176
|
}
|
|
366
|
-
// Check for Blueprint paths
|
|
367
177
|
if (classPath.includes('Blueprint') || classPath.includes('BP_')) {
|
|
368
|
-
// Ensure it has the proper prefix
|
|
369
178
|
if (!classPath.startsWith('/Game/')) {
|
|
370
179
|
return '/Game/' + classPath;
|
|
371
180
|
}
|
|
372
181
|
return classPath;
|
|
373
182
|
}
|
|
374
|
-
// Default: assume it's an engine class
|
|
375
183
|
return '/Script/Engine.' + classPath;
|
|
376
184
|
}
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
|
|
185
|
+
async spawnBlueprint(params) {
|
|
186
|
+
const blueprintPath = typeof params.blueprintPath === 'string' ? params.blueprintPath.trim() : '';
|
|
187
|
+
if (!blueprintPath) {
|
|
188
|
+
throw new Error('Invalid blueprintPath');
|
|
189
|
+
}
|
|
190
|
+
const actorName = typeof params.actorName === 'string' && params.actorName.trim().length > 0 ? params.actorName.trim() : undefined;
|
|
191
|
+
const location = params.location ? ensureVector3(params.location, 'spawn_blueprint location') : undefined;
|
|
192
|
+
const rotation = params.rotation ? ensureRotation(params.rotation, 'spawn_blueprint rotation') : undefined;
|
|
193
|
+
const payload = { blueprintPath };
|
|
194
|
+
if (actorName)
|
|
195
|
+
payload.actorName = actorName;
|
|
196
|
+
if (location)
|
|
197
|
+
payload.location = { x: location[0], y: location[1], z: location[2] };
|
|
198
|
+
if (rotation)
|
|
199
|
+
payload.rotation = { pitch: rotation[0], yaw: rotation[1], roll: rotation[2] };
|
|
200
|
+
return this.sendRequest('spawn_blueprint', payload, 'control_actor');
|
|
201
|
+
}
|
|
202
|
+
async setTransform(params) {
|
|
203
|
+
const actorName = typeof params.actorName === 'string' ? params.actorName.trim() : '';
|
|
204
|
+
if (!actorName) {
|
|
205
|
+
throw new Error('Invalid actorName');
|
|
206
|
+
}
|
|
207
|
+
const payload = { actorName };
|
|
208
|
+
if (params.location) {
|
|
209
|
+
const loc = ensureVector3(params.location, 'set_transform location');
|
|
210
|
+
payload.location = { x: loc[0], y: loc[1], z: loc[2] };
|
|
211
|
+
}
|
|
212
|
+
if (params.rotation) {
|
|
213
|
+
const rot = ensureRotation(params.rotation, 'set_transform rotation');
|
|
214
|
+
payload.rotation = { pitch: rot[0], yaw: rot[1], roll: rot[2] };
|
|
215
|
+
}
|
|
216
|
+
if (params.scale) {
|
|
217
|
+
const scl = ensureVector3(params.scale, 'set_transform scale');
|
|
218
|
+
payload.scale = { x: scl[0], y: scl[1], z: scl[2] };
|
|
219
|
+
}
|
|
220
|
+
return this.sendRequest('set_transform', payload, 'control_actor');
|
|
221
|
+
}
|
|
222
|
+
async getTransform(actorName) {
|
|
223
|
+
if (typeof actorName !== 'string' || actorName.trim().length === 0) {
|
|
224
|
+
throw new Error('Invalid actorName');
|
|
225
|
+
}
|
|
226
|
+
return this.sendRequest('get_transform', { actorName }, 'control_actor')
|
|
227
|
+
.then(response => {
|
|
228
|
+
return response;
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
async setVisibility(params) {
|
|
232
|
+
const actorName = typeof params.actorName === 'string' ? params.actorName.trim() : '';
|
|
233
|
+
if (!actorName) {
|
|
234
|
+
throw new Error('Invalid actorName');
|
|
235
|
+
}
|
|
236
|
+
return this.sendRequest('set_visibility', { actorName, visible: Boolean(params.visible) }, 'control_actor');
|
|
237
|
+
}
|
|
238
|
+
async addComponent(params) {
|
|
239
|
+
const actorName = typeof params.actorName === 'string' ? params.actorName.trim() : '';
|
|
240
|
+
const componentType = typeof params.componentType === 'string' ? params.componentType.trim() : '';
|
|
241
|
+
if (!actorName)
|
|
242
|
+
throw new Error('Invalid actorName');
|
|
243
|
+
if (!componentType)
|
|
244
|
+
throw new Error('Invalid componentType');
|
|
245
|
+
return this.sendRequest('add_component', {
|
|
246
|
+
actorName,
|
|
247
|
+
componentType,
|
|
248
|
+
componentName: typeof params.componentName === 'string' ? params.componentName : undefined,
|
|
249
|
+
properties: params.properties
|
|
250
|
+
}, 'control_actor');
|
|
251
|
+
}
|
|
252
|
+
async setComponentProperties(params) {
|
|
253
|
+
const actorName = typeof params.actorName === 'string' ? params.actorName.trim() : '';
|
|
254
|
+
const componentName = typeof params.componentName === 'string' ? params.componentName.trim() : '';
|
|
255
|
+
if (!actorName)
|
|
256
|
+
throw new Error('Invalid actorName');
|
|
257
|
+
if (!componentName)
|
|
258
|
+
throw new Error('Invalid componentName');
|
|
259
|
+
return this.sendRequest('set_component_properties', {
|
|
260
|
+
actorName,
|
|
261
|
+
componentName,
|
|
262
|
+
properties: params.properties ?? {}
|
|
263
|
+
}, 'control_actor');
|
|
264
|
+
}
|
|
265
|
+
async getComponents(actorName) {
|
|
266
|
+
if (typeof actorName !== 'string' || actorName.trim().length === 0) {
|
|
267
|
+
throw new Error('Invalid actorName');
|
|
268
|
+
}
|
|
269
|
+
const response = await this.sendRequest('get_components', { actorName }, 'control_actor');
|
|
270
|
+
if (!response.success) {
|
|
271
|
+
return { success: false, error: response.error || `Failed to get components for actor ${actorName}` };
|
|
272
|
+
}
|
|
273
|
+
const data = response.data ?? response.result ?? response;
|
|
274
|
+
const components = Array.isArray(data)
|
|
275
|
+
? data
|
|
276
|
+
: (Array.isArray(data?.components) ? data.components : []);
|
|
277
|
+
const count = typeof data?.count === 'number' ? data.count : components.length;
|
|
278
|
+
return {
|
|
279
|
+
success: true,
|
|
280
|
+
message: 'Actor components retrieved',
|
|
281
|
+
components,
|
|
282
|
+
count
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
async duplicate(params) {
|
|
286
|
+
const actorName = typeof params.actorName === 'string' ? params.actorName.trim() : '';
|
|
287
|
+
if (!actorName)
|
|
288
|
+
throw new Error('Invalid actorName');
|
|
289
|
+
const payload = { actorName };
|
|
290
|
+
if (typeof params.newName === 'string' && params.newName.trim().length > 0) {
|
|
291
|
+
payload.newName = params.newName.trim();
|
|
292
|
+
}
|
|
293
|
+
if (params.offset) {
|
|
294
|
+
const offs = ensureVector3(params.offset, 'duplicate offset');
|
|
295
|
+
payload.offset = { x: offs[0], y: offs[1], z: offs[2] };
|
|
296
|
+
}
|
|
297
|
+
return this.sendRequest('duplicate', payload, 'control_actor');
|
|
298
|
+
}
|
|
299
|
+
async addTag(params) {
|
|
300
|
+
const actorName = typeof params.actorName === 'string' ? params.actorName.trim() : '';
|
|
301
|
+
const tag = typeof params.tag === 'string' ? params.tag.trim() : '';
|
|
302
|
+
if (!actorName)
|
|
303
|
+
throw new Error('Invalid actorName');
|
|
304
|
+
if (!tag)
|
|
305
|
+
throw new Error('Invalid tag');
|
|
306
|
+
return this.sendRequest('add_tag', { actorName, tag }, 'control_actor');
|
|
307
|
+
}
|
|
308
|
+
async removeTag(params) {
|
|
309
|
+
const actorName = typeof params.actorName === 'string' ? params.actorName.trim() : '';
|
|
310
|
+
const tag = typeof params.tag === 'string' ? params.tag.trim() : '';
|
|
311
|
+
if (!actorName)
|
|
312
|
+
throw new Error('Invalid actorName');
|
|
313
|
+
if (!tag)
|
|
314
|
+
throw new Error('Invalid tag');
|
|
315
|
+
return this.sendRequest('remove_tag', { actorName, tag }, 'control_actor');
|
|
316
|
+
}
|
|
317
|
+
async findByTag(params) {
|
|
318
|
+
const tag = typeof params.tag === 'string' ? params.tag.trim() : '';
|
|
319
|
+
if (!tag) {
|
|
320
|
+
return {
|
|
321
|
+
success: true,
|
|
322
|
+
message: 'Empty tag query; no actors matched',
|
|
323
|
+
data: {
|
|
324
|
+
actors: [],
|
|
325
|
+
count: 0
|
|
326
|
+
}
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
return this.sendRequest('find_by_tag', {
|
|
330
|
+
tag,
|
|
331
|
+
matchType: typeof params.matchType === 'string' ? params.matchType : undefined
|
|
332
|
+
}, 'control_actor');
|
|
333
|
+
}
|
|
334
|
+
async findByName(name) {
|
|
335
|
+
if (typeof name !== 'string' || name.trim().length === 0) {
|
|
336
|
+
throw new Error('Invalid actor name query');
|
|
337
|
+
}
|
|
338
|
+
return this.sendRequest('find_by_name', { name: name.trim() }, 'control_actor');
|
|
339
|
+
}
|
|
340
|
+
async detach(actorName) {
|
|
341
|
+
if (typeof actorName !== 'string' || actorName.trim().length === 0) {
|
|
342
|
+
throw new Error('Invalid actorName');
|
|
343
|
+
}
|
|
344
|
+
return this.sendRequest('detach', { actorName }, 'control_actor');
|
|
345
|
+
}
|
|
346
|
+
async attach(params) {
|
|
347
|
+
const child = typeof params.childActor === 'string' ? params.childActor.trim() : '';
|
|
348
|
+
const parent = typeof params.parentActor === 'string' ? params.parentActor.trim() : '';
|
|
349
|
+
if (!child)
|
|
350
|
+
throw new Error('Invalid childActor');
|
|
351
|
+
if (!parent)
|
|
352
|
+
throw new Error('Invalid parentActor');
|
|
353
|
+
return this.sendRequest('attach', { childActor: child, parentActor: parent }, 'control_actor');
|
|
354
|
+
}
|
|
355
|
+
async deleteByTag(tag) {
|
|
356
|
+
if (typeof tag !== 'string' || tag.trim().length === 0) {
|
|
357
|
+
throw new Error('Invalid tag');
|
|
358
|
+
}
|
|
359
|
+
return this.sendRequest('delete_by_tag', { tag: tag.trim() }, 'control_actor');
|
|
360
|
+
}
|
|
361
|
+
async setBlueprintVariables(params) {
|
|
362
|
+
const actorName = typeof params.actorName === 'string' ? params.actorName.trim() : '';
|
|
363
|
+
if (!actorName)
|
|
364
|
+
throw new Error('Invalid actorName');
|
|
365
|
+
return this.sendRequest('set_blueprint_variables', { actorName, variables: params.variables ?? {} }, 'control_actor');
|
|
366
|
+
}
|
|
367
|
+
async createSnapshot(params) {
|
|
368
|
+
const actorName = typeof params.actorName === 'string' ? params.actorName.trim() : '';
|
|
369
|
+
const snapshotName = typeof params.snapshotName === 'string' ? params.snapshotName.trim() : '';
|
|
370
|
+
if (!actorName)
|
|
371
|
+
throw new Error('Invalid actorName');
|
|
372
|
+
if (!snapshotName)
|
|
373
|
+
throw new Error('Invalid snapshotName');
|
|
374
|
+
return this.sendRequest('create_snapshot', { actorName, snapshotName }, 'control_actor');
|
|
375
|
+
}
|
|
376
|
+
async restoreSnapshot(params) {
|
|
377
|
+
const actorName = typeof params.actorName === 'string' ? params.actorName.trim() : '';
|
|
378
|
+
const snapshotName = typeof params.snapshotName === 'string' ? params.snapshotName.trim() : '';
|
|
379
|
+
if (!actorName)
|
|
380
|
+
throw new Error('Invalid actorName');
|
|
381
|
+
if (!snapshotName)
|
|
382
|
+
throw new Error('Invalid snapshotName');
|
|
383
|
+
return this.sendRequest('restore_snapshot', { actorName, snapshotName }, 'control_actor');
|
|
384
|
+
}
|
|
385
|
+
async exportActor(params) {
|
|
386
|
+
const actorName = typeof params.actorName === 'string' ? params.actorName.trim() : '';
|
|
387
|
+
if (!actorName)
|
|
388
|
+
throw new Error('Invalid actorName');
|
|
389
|
+
return this.sendRequest('export', {
|
|
390
|
+
actorName,
|
|
391
|
+
destinationPath: params.destinationPath
|
|
392
|
+
}, 'control_actor');
|
|
393
|
+
}
|
|
394
|
+
async getBoundingBox(actorName) {
|
|
395
|
+
if (typeof actorName !== 'string' || actorName.trim().length === 0) {
|
|
396
|
+
throw new Error('Invalid actorName');
|
|
397
|
+
}
|
|
398
|
+
const response = await this.sendRequest('get_bounding_box', { actorName }, 'control_actor');
|
|
399
|
+
if (!response.success) {
|
|
400
|
+
return { success: false, error: response.error || `Failed to get bounding box for actor ${actorName}` };
|
|
401
|
+
}
|
|
402
|
+
return {
|
|
403
|
+
success: true,
|
|
404
|
+
message: 'Bounding box retrieved',
|
|
405
|
+
boundingBox: response.data || response.result || {}
|
|
406
|
+
};
|
|
407
|
+
}
|
|
408
|
+
async getMetadata(actorName) {
|
|
409
|
+
if (typeof actorName !== 'string' || actorName.trim().length === 0) {
|
|
410
|
+
throw new Error('Invalid actorName');
|
|
411
|
+
}
|
|
412
|
+
const response = await this.sendRequest('get_metadata', { actorName }, 'control_actor');
|
|
413
|
+
if (!response.success) {
|
|
414
|
+
return { success: false, error: response.error || `Failed to get metadata for actor ${actorName}` };
|
|
415
|
+
}
|
|
416
|
+
return {
|
|
417
|
+
success: true,
|
|
418
|
+
message: 'Actor metadata retrieved',
|
|
419
|
+
metadata: response.data || response.result || {}
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
async listActors(params) {
|
|
423
|
+
const payload = {};
|
|
424
|
+
if (params?.filter) {
|
|
425
|
+
payload.filter = params.filter;
|
|
426
|
+
}
|
|
427
|
+
const response = await this.sendRequest('list_actors', payload, 'control_actor');
|
|
428
|
+
if (!response.success) {
|
|
429
|
+
return { success: false, error: response.error || 'Failed to list actors' };
|
|
430
|
+
}
|
|
431
|
+
const dataObj = response.data || response.result || {};
|
|
432
|
+
const actorsRaw = response.actors || (dataObj && dataObj.actors) || (Array.isArray(dataObj) ? dataObj : []);
|
|
433
|
+
const actors = Array.isArray(actorsRaw) ? actorsRaw : [];
|
|
434
|
+
return {
|
|
435
|
+
success: true,
|
|
436
|
+
message: `Found ${actors.length} actors`,
|
|
437
|
+
actors,
|
|
438
|
+
count: actors.length
|
|
439
|
+
};
|
|
401
440
|
}
|
|
402
441
|
}
|
|
403
442
|
//# sourceMappingURL=actors.js.map
|