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
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { cleanObject } from '../../utils/safe-json.js';
|
|
2
|
+
import { ITools } from '../../types/tool-interfaces.js';
|
|
3
|
+
import { executeAutomationRequest, requireNonEmptyString } from './common-handlers.js';
|
|
4
|
+
|
|
5
|
+
export async function handleEditorTools(action: string, args: any, tools: ITools) {
|
|
6
|
+
switch (action) {
|
|
7
|
+
case 'play': {
|
|
8
|
+
const res = await tools.editorTools.playInEditor(args.timeoutMs);
|
|
9
|
+
return cleanObject(res);
|
|
10
|
+
}
|
|
11
|
+
case 'stop':
|
|
12
|
+
case 'stop_pie': {
|
|
13
|
+
const res = await tools.editorTools.stopPlayInEditor();
|
|
14
|
+
return cleanObject(res);
|
|
15
|
+
}
|
|
16
|
+
case 'eject': {
|
|
17
|
+
const inPie = await tools.editorTools.isInPIE();
|
|
18
|
+
if (!inPie) {
|
|
19
|
+
return { success: false, error: 'NOT_IN_PIE', message: 'Cannot eject while not in PIE' };
|
|
20
|
+
}
|
|
21
|
+
return await executeAutomationRequest(tools, 'control_editor', { action: 'eject' });
|
|
22
|
+
}
|
|
23
|
+
case 'possess': {
|
|
24
|
+
const inPie = await tools.editorTools.isInPIE();
|
|
25
|
+
if (!inPie) {
|
|
26
|
+
return { success: false, error: 'NOT_IN_PIE', message: 'Cannot possess actor while not in PIE' };
|
|
27
|
+
}
|
|
28
|
+
return await executeAutomationRequest(tools, 'control_editor', args);
|
|
29
|
+
}
|
|
30
|
+
case 'pause': {
|
|
31
|
+
const res = await tools.editorTools.pausePlayInEditor();
|
|
32
|
+
return cleanObject(res);
|
|
33
|
+
}
|
|
34
|
+
case 'resume': {
|
|
35
|
+
const res = await tools.editorTools.resumePlayInEditor();
|
|
36
|
+
return cleanObject(res);
|
|
37
|
+
}
|
|
38
|
+
case 'screenshot': {
|
|
39
|
+
const res = await tools.editorTools.takeScreenshot(args.filename, args.resolution);
|
|
40
|
+
return cleanObject(res);
|
|
41
|
+
}
|
|
42
|
+
case 'console_command': {
|
|
43
|
+
const res = await tools.editorTools.executeConsoleCommand(args.command);
|
|
44
|
+
return cleanObject(res);
|
|
45
|
+
}
|
|
46
|
+
case 'set_camera': {
|
|
47
|
+
const res = await tools.editorTools.setViewportCamera(args.location, args.rotation);
|
|
48
|
+
return cleanObject(res);
|
|
49
|
+
}
|
|
50
|
+
case 'start_recording': {
|
|
51
|
+
// Use console command as fallback if bridge doesn't support it
|
|
52
|
+
const filename = args.filename || 'TestRecording';
|
|
53
|
+
await tools.editorTools.executeConsoleCommand(`DemoRec ${filename}`);
|
|
54
|
+
return { success: true, message: `Started recording to ${filename}`, action: 'start_recording' };
|
|
55
|
+
}
|
|
56
|
+
case 'stop_recording': {
|
|
57
|
+
await tools.editorTools.executeConsoleCommand('DemoStop');
|
|
58
|
+
return { success: true, message: 'Stopped recording', action: 'stop_recording' };
|
|
59
|
+
}
|
|
60
|
+
case 'step_frame': {
|
|
61
|
+
// Use console command for single frame advance
|
|
62
|
+
await tools.editorTools.executeConsoleCommand('r.SingleFrameAdvance 1');
|
|
63
|
+
return { success: true, message: 'Stepped frame', action: 'step_frame' };
|
|
64
|
+
}
|
|
65
|
+
case 'create_bookmark': {
|
|
66
|
+
const idx = parseInt(args.bookmarkName) || 0;
|
|
67
|
+
await tools.editorTools.executeConsoleCommand(`r.SetBookmark ${idx}`);
|
|
68
|
+
return { success: true, message: `Created bookmark ${idx}`, action: 'create_bookmark' };
|
|
69
|
+
}
|
|
70
|
+
case 'jump_to_bookmark': {
|
|
71
|
+
const idx = parseInt(args.bookmarkName) || 0;
|
|
72
|
+
await tools.editorTools.executeConsoleCommand(`r.JumpToBookmark ${idx}`);
|
|
73
|
+
return { success: true, message: `Jumped to bookmark ${idx}`, action: 'jump_to_bookmark' };
|
|
74
|
+
}
|
|
75
|
+
case 'set_preferences': {
|
|
76
|
+
const res = await tools.editorTools.setEditorPreferences(args.category, args.preferences);
|
|
77
|
+
return cleanObject(res);
|
|
78
|
+
}
|
|
79
|
+
case 'open_asset': {
|
|
80
|
+
const assetPath = requireNonEmptyString(args.assetPath || args.path, 'assetPath');
|
|
81
|
+
const res = await executeAutomationRequest(tools, 'control_editor', { action: 'open_asset', assetPath });
|
|
82
|
+
return cleanObject(res);
|
|
83
|
+
}
|
|
84
|
+
case 'execute_command': {
|
|
85
|
+
const command = requireNonEmptyString(args.command, 'command');
|
|
86
|
+
const res = await tools.editorTools.executeConsoleCommand(command);
|
|
87
|
+
return { ...cleanObject(res), action: 'execute_command' };
|
|
88
|
+
}
|
|
89
|
+
case 'set_camera_fov': {
|
|
90
|
+
await tools.editorTools.executeConsoleCommand(`fov ${args.fov}`);
|
|
91
|
+
return { success: true, message: `Set FOV to ${args.fov}`, action: 'set_camera_fov' };
|
|
92
|
+
}
|
|
93
|
+
case 'set_game_speed': {
|
|
94
|
+
await tools.editorTools.executeConsoleCommand(`slomo ${args.speed}`);
|
|
95
|
+
return { success: true, message: `Set game speed to ${args.speed}`, action: 'set_game_speed' };
|
|
96
|
+
}
|
|
97
|
+
case 'set_view_mode': {
|
|
98
|
+
const viewMode = requireNonEmptyString(args.viewMode, 'viewMode');
|
|
99
|
+
const validModes = [
|
|
100
|
+
'Lit', 'Unlit', 'Wireframe', 'DetailLighting', 'LightingOnly', 'Reflections',
|
|
101
|
+
'OptimizationViewmodes', 'ShaderComplexity', 'LightmapDensity', 'StationaryLightOverlap', 'LightComplexity',
|
|
102
|
+
'PathTracing', 'Visualizer', 'LODColoration', 'CollisionPawn', 'CollisionVisibility'
|
|
103
|
+
];
|
|
104
|
+
if (!validModes.includes(viewMode)) {
|
|
105
|
+
throw new Error(`unknown_viewmode: ${viewMode}. Must be one of: ${validModes.join(', ')}`);
|
|
106
|
+
}
|
|
107
|
+
await tools.editorTools.executeConsoleCommand(`viewmode ${viewMode}`);
|
|
108
|
+
return { success: true, message: `Set view mode to ${viewMode}`, action: 'set_view_mode' };
|
|
109
|
+
}
|
|
110
|
+
case 'set_viewport_resolution': {
|
|
111
|
+
await tools.editorTools.executeConsoleCommand(`r.SetRes ${args.width}x${args.height}`);
|
|
112
|
+
return { success: true, message: `Set viewport resolution to ${args.width}x${args.height}`, action: 'set_viewport_resolution' };
|
|
113
|
+
}
|
|
114
|
+
case 'set_viewport_realtime': {
|
|
115
|
+
const enabled = args.enabled !== undefined ? args.enabled : (args.realtime !== false);
|
|
116
|
+
// Use console command since interface doesn't have setViewportRealtime
|
|
117
|
+
await tools.editorTools.executeConsoleCommand(`r.ViewportRealtime ${enabled ? 1 : 0}`);
|
|
118
|
+
return { success: true, message: `Set viewport realtime to ${enabled}`, action: 'set_viewport_realtime' };
|
|
119
|
+
}
|
|
120
|
+
default:
|
|
121
|
+
return await executeAutomationRequest(tools, 'control_editor', args);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import { cleanObject } from '../../utils/safe-json.js';
|
|
2
|
+
import { ITools } from '../../types/tool-interfaces.js';
|
|
3
|
+
import { executeAutomationRequest, requireNonEmptyString } from './common-handlers.js';
|
|
4
|
+
|
|
5
|
+
function ensureActionAndSubAction(action: string, args: any) {
|
|
6
|
+
if (!args || typeof args !== 'object') return;
|
|
7
|
+
// Many callers pass the tool action as the action name (e.g. "niagara") and
|
|
8
|
+
// omit args.action; the native handler requires subAction.
|
|
9
|
+
if (!args.action) {
|
|
10
|
+
args.action = action;
|
|
11
|
+
}
|
|
12
|
+
if (!args.subAction) {
|
|
13
|
+
args.subAction = args.action;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function isNonEmptyString(val: unknown): val is string {
|
|
18
|
+
return typeof val === 'string' && val.trim().length > 0;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export async function handleEffectTools(action: string, args: any, tools: ITools) {
|
|
22
|
+
if (!args || typeof args !== 'object') {
|
|
23
|
+
args = {};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Always ensure action/subAction are present before any routing.
|
|
27
|
+
ensureActionAndSubAction(action, args);
|
|
28
|
+
|
|
29
|
+
// Handle creation actions explicitly to use NiagaraTools helper
|
|
30
|
+
if (action === 'create_niagara_system') {
|
|
31
|
+
const res = await tools.niagaraTools.createSystem({
|
|
32
|
+
name: args.name,
|
|
33
|
+
savePath: args.savePath,
|
|
34
|
+
template: args.template
|
|
35
|
+
});
|
|
36
|
+
return cleanObject(res);
|
|
37
|
+
}
|
|
38
|
+
if (action === 'create_niagara_emitter') {
|
|
39
|
+
const res = await tools.niagaraTools.createEmitter({
|
|
40
|
+
name: args.name,
|
|
41
|
+
savePath: args.savePath,
|
|
42
|
+
systemPath: args.systemPath,
|
|
43
|
+
template: args.template
|
|
44
|
+
});
|
|
45
|
+
return cleanObject(res);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Pre-process arguments for particle presets
|
|
49
|
+
if (args.action === 'particle') {
|
|
50
|
+
const presets: Record<string, string> = {
|
|
51
|
+
'Default': '/StarterContent/Particles/P_Steam_Lit.P_Steam_Lit',
|
|
52
|
+
'Smoke': '/StarterContent/Particles/P_Smoke.P_Smoke',
|
|
53
|
+
'Fire': '/StarterContent/Particles/P_Fire.P_Fire',
|
|
54
|
+
'Explosion': '/StarterContent/Particles/P_Explosion.P_Explosion',
|
|
55
|
+
};
|
|
56
|
+
// Check both preset and effectType fields
|
|
57
|
+
const key = args.preset || args.effectType;
|
|
58
|
+
if (key && presets[key]) {
|
|
59
|
+
args.preset = presets[key];
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Handle debug shapes (must happen before any automation request)
|
|
64
|
+
if (action === 'debug_shape' || args.action === 'debug_shape') {
|
|
65
|
+
// Map 'shape' to 'shapeType' if provided (schema uses 'shape', C++ uses 'shapeType')
|
|
66
|
+
if (args.shape && !args.shapeType) {
|
|
67
|
+
args.shapeType = args.shape;
|
|
68
|
+
}
|
|
69
|
+
requireNonEmptyString(args.shapeType, 'shapeType', 'Missing required parameter: shapeType');
|
|
70
|
+
args.action = 'debug_shape';
|
|
71
|
+
args.subAction = 'debug_shape';
|
|
72
|
+
return cleanObject(await executeAutomationRequest(tools, 'create_effect', args));
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Validate Niagara-related required parameters (keep errors explicit and early)
|
|
76
|
+
const subAction = String(args.subAction || '').trim();
|
|
77
|
+
if (subAction === 'niagara' || subAction === 'spawn_niagara') {
|
|
78
|
+
requireNonEmptyString(args.systemPath, 'systemPath', 'Missing required parameter: systemPath');
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (subAction === 'activate_niagara' || subAction === 'deactivate_niagara' || subAction === 'advance_simulation') {
|
|
82
|
+
const systemName = args.systemName ?? args.actorName;
|
|
83
|
+
requireNonEmptyString(systemName, 'systemName', 'Missing required parameter: systemName (or actorName)');
|
|
84
|
+
args.systemName = systemName;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (subAction === 'set_niagara_parameter') {
|
|
88
|
+
const systemName = args.systemName ?? args.actorName;
|
|
89
|
+
requireNonEmptyString(systemName, 'systemName', 'Missing required parameter: systemName (or actorName)');
|
|
90
|
+
requireNonEmptyString(args.parameterName, 'parameterName', 'Missing required parameter: parameterName');
|
|
91
|
+
// parameterType is required for unambiguous native conversion; accept common aliases.
|
|
92
|
+
if (!isNonEmptyString(args.parameterType) && isNonEmptyString(args.type)) {
|
|
93
|
+
args.parameterType = args.type.charAt(0).toUpperCase() + args.type.slice(1);
|
|
94
|
+
}
|
|
95
|
+
requireNonEmptyString(args.parameterType, 'parameterType', 'Missing required parameter: parameterType');
|
|
96
|
+
args.systemName = systemName;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Handle debug cleanup actions
|
|
100
|
+
if (action === 'clear_debug_shapes') {
|
|
101
|
+
return executeAutomationRequest(tools, action, args);
|
|
102
|
+
}
|
|
103
|
+
if (action === 'cleanup') {
|
|
104
|
+
args.action = 'cleanup';
|
|
105
|
+
args.subAction = 'cleanup';
|
|
106
|
+
return executeAutomationRequest(tools, 'create_effect', args);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Map high-level actions to create_effect with subAction
|
|
110
|
+
const createActions = [
|
|
111
|
+
'create_volumetric_fog',
|
|
112
|
+
'create_particle_trail',
|
|
113
|
+
'create_environment_effect',
|
|
114
|
+
'create_impact_effect',
|
|
115
|
+
'create_niagara_ribbon'
|
|
116
|
+
];
|
|
117
|
+
if (createActions.includes(action)) {
|
|
118
|
+
args.action = action;
|
|
119
|
+
return executeAutomationRequest(tools, 'create_effect', args);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Map simulation control actions
|
|
123
|
+
if (action === 'activate' || action === 'activate_effect') {
|
|
124
|
+
args.action = 'activate_niagara';
|
|
125
|
+
args.systemName = args.actorName || args.systemName;
|
|
126
|
+
requireNonEmptyString(args.systemName, 'systemName', 'Missing required parameter: systemName (or actorName)');
|
|
127
|
+
args.reset = true;
|
|
128
|
+
return executeAutomationRequest(tools, 'create_effect', args);
|
|
129
|
+
}
|
|
130
|
+
if (action === 'deactivate') {
|
|
131
|
+
args.action = 'deactivate_niagara';
|
|
132
|
+
args.systemName = args.actorName || args.systemName;
|
|
133
|
+
requireNonEmptyString(args.systemName, 'systemName', 'Missing required parameter: systemName (or actorName)');
|
|
134
|
+
return executeAutomationRequest(tools, 'create_effect', args);
|
|
135
|
+
}
|
|
136
|
+
if (action === 'reset') {
|
|
137
|
+
args.action = 'activate_niagara';
|
|
138
|
+
args.systemName = args.actorName || args.systemName;
|
|
139
|
+
requireNonEmptyString(args.systemName, 'systemName', 'Missing required parameter: systemName (or actorName)');
|
|
140
|
+
args.reset = true;
|
|
141
|
+
return executeAutomationRequest(tools, 'create_effect', args);
|
|
142
|
+
}
|
|
143
|
+
if (action === 'advance_simulation') {
|
|
144
|
+
args.action = 'advance_simulation';
|
|
145
|
+
args.systemName = args.actorName || args.systemName;
|
|
146
|
+
requireNonEmptyString(args.systemName, 'systemName', 'Missing required parameter: systemName (or actorName)');
|
|
147
|
+
return executeAutomationRequest(tools, 'create_effect', args);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Map parameter setting
|
|
151
|
+
if (action === 'set_niagara_parameter') {
|
|
152
|
+
args.action = 'set_niagara_parameter';
|
|
153
|
+
// If actorName is provided, use it as systemName (which C++ expects for actor label)
|
|
154
|
+
if (args.actorName && !args.systemName) {
|
|
155
|
+
args.systemName = args.actorName;
|
|
156
|
+
}
|
|
157
|
+
// Map 'type' to 'parameterType' if provided and parameterType is missing
|
|
158
|
+
if (args.type && !args.parameterType) {
|
|
159
|
+
args.parameterType = args.type.charAt(0).toUpperCase() + args.type.slice(1);
|
|
160
|
+
}
|
|
161
|
+
requireNonEmptyString(args.systemName, 'systemName', 'Missing required parameter: systemName (or actorName)');
|
|
162
|
+
requireNonEmptyString(args.parameterName, 'parameterName', 'Missing required parameter: parameterName');
|
|
163
|
+
requireNonEmptyString(args.parameterType, 'parameterType', 'Missing required parameter: parameterType');
|
|
164
|
+
return executeAutomationRequest(tools, 'create_effect', args);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const res: any = await executeAutomationRequest(
|
|
168
|
+
tools,
|
|
169
|
+
'create_effect',
|
|
170
|
+
args,
|
|
171
|
+
'Automation bridge not available for effect creation operations'
|
|
172
|
+
);
|
|
173
|
+
|
|
174
|
+
const result = res?.result ?? res ?? {};
|
|
175
|
+
const topError = typeof res?.error === 'string' ? res.error : '';
|
|
176
|
+
const nestedError = typeof result.error === 'string' ? result.error : '';
|
|
177
|
+
const errorCode = (topError || nestedError).toUpperCase();
|
|
178
|
+
|
|
179
|
+
const topMessage = typeof res?.message === 'string' ? res.message : '';
|
|
180
|
+
const nestedMessage = typeof result.message === 'string' ? result.message : '';
|
|
181
|
+
const message = topMessage || nestedMessage || '';
|
|
182
|
+
|
|
183
|
+
const combined = `${topError} ${nestedError} ${message}`.toLowerCase();
|
|
184
|
+
|
|
185
|
+
if (
|
|
186
|
+
action === 'niagara' &&
|
|
187
|
+
(
|
|
188
|
+
errorCode === 'SYSTEM_NOT_FOUND' ||
|
|
189
|
+
combined.includes('niagara system not found') ||
|
|
190
|
+
combined.includes('system asset not found')
|
|
191
|
+
)
|
|
192
|
+
) {
|
|
193
|
+
return cleanObject({
|
|
194
|
+
success: false,
|
|
195
|
+
error: 'SYSTEM_NOT_FOUND',
|
|
196
|
+
message: message || 'Niagara system not found',
|
|
197
|
+
systemPath: args.systemPath,
|
|
198
|
+
handled: true
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// If we got here and it was a spawn_niagara failure, maybe try to be helpful about paths
|
|
203
|
+
if (action === 'spawn_niagara' && errorCode === 'SYSTEM_NOT_FOUND' && args.systemPath) {
|
|
204
|
+
// Check if path ends in .Name
|
|
205
|
+
const path = args.systemPath;
|
|
206
|
+
const name = path.split('/').pop();
|
|
207
|
+
if (name && !path.endsWith(`.${name}`)) {
|
|
208
|
+
// Retry with corrected path?
|
|
209
|
+
// We can't easily retry here without recursion, but we can hint in the message.
|
|
210
|
+
return cleanObject({
|
|
211
|
+
success: false,
|
|
212
|
+
error: 'SYSTEM_NOT_FOUND',
|
|
213
|
+
message: `Niagara System not found at ${path}. Did you mean ${path}.${name}?`,
|
|
214
|
+
systemPath: path
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
return cleanObject(res);
|
|
220
|
+
}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import { cleanObject } from '../../utils/safe-json.js';
|
|
2
|
+
import { ITools } from '../../types/tool-interfaces.js';
|
|
3
|
+
import { executeAutomationRequest } from './common-handlers.js';
|
|
4
|
+
|
|
5
|
+
export async function handleEnvironmentTools(action: string, args: any, tools: ITools) {
|
|
6
|
+
const envAction = String(action || '').toLowerCase();
|
|
7
|
+
switch (envAction) {
|
|
8
|
+
case 'create_landscape':
|
|
9
|
+
return cleanObject(await tools.landscapeTools.createLandscape({
|
|
10
|
+
name: args.name,
|
|
11
|
+
location: args.location,
|
|
12
|
+
sizeX: args.sizeX,
|
|
13
|
+
sizeY: args.sizeY,
|
|
14
|
+
quadsPerSection: args.quadsPerSection,
|
|
15
|
+
sectionsPerComponent: args.sectionsPerComponent,
|
|
16
|
+
componentCount: args.componentCount,
|
|
17
|
+
materialPath: args.materialPath,
|
|
18
|
+
enableWorldPartition: args.enableWorldPartition,
|
|
19
|
+
runtimeGrid: args.runtimeGrid,
|
|
20
|
+
isSpatiallyLoaded: args.isSpatiallyLoaded,
|
|
21
|
+
dataLayers: args.dataLayers
|
|
22
|
+
}));
|
|
23
|
+
case 'modify_heightmap':
|
|
24
|
+
return cleanObject(await tools.landscapeTools.modifyHeightmap({
|
|
25
|
+
landscapeName: args.landscapeName || args.name,
|
|
26
|
+
heightData: args.heightData,
|
|
27
|
+
minX: args.minX,
|
|
28
|
+
minY: args.minY,
|
|
29
|
+
maxX: args.maxX,
|
|
30
|
+
maxY: args.maxY,
|
|
31
|
+
updateNormals: args.updateNormals
|
|
32
|
+
}));
|
|
33
|
+
case 'sculpt':
|
|
34
|
+
case 'sculpt_landscape': {
|
|
35
|
+
// Default to 'Raise' tool if not specified
|
|
36
|
+
const tool = args.tool || 'Raise';
|
|
37
|
+
return cleanObject(await tools.landscapeTools.sculptLandscape({
|
|
38
|
+
landscapeName: args.landscapeName || args.name,
|
|
39
|
+
tool,
|
|
40
|
+
location: args.location,
|
|
41
|
+
radius: args.radius || 500,
|
|
42
|
+
strength: args.strength || 0.5
|
|
43
|
+
}));
|
|
44
|
+
}
|
|
45
|
+
case 'add_foliage': {
|
|
46
|
+
// Check if this is adding a foliage TYPE (has meshPath) or INSTANCES (has locations/position)
|
|
47
|
+
if (args.meshPath) {
|
|
48
|
+
// Derive a better default name from mesh path if not provided
|
|
49
|
+
const defaultName = args.meshPath.split('/').pop()?.split('.')[0] + '_Foliage_Type';
|
|
50
|
+
return cleanObject(await tools.foliageTools.addFoliageType({
|
|
51
|
+
name: args.foliageType || args.name || defaultName,
|
|
52
|
+
meshPath: args.meshPath,
|
|
53
|
+
density: args.density
|
|
54
|
+
}));
|
|
55
|
+
} else {
|
|
56
|
+
// Validate foliageType is provided
|
|
57
|
+
const foliageType = args.foliageType || args.foliageTypePath;
|
|
58
|
+
if (!foliageType) {
|
|
59
|
+
return cleanObject({
|
|
60
|
+
success: false,
|
|
61
|
+
error: 'INVALID_ARGUMENT',
|
|
62
|
+
message: 'add_foliage requires either: (1) meshPath to create a new foliage type, or (2) foliageType/foliageTypePath to place instances of an existing type. Example foliage assets: /Game/StarterContent/Props/SM_Bush, /Engine/BasicShapes/Sphere'
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Support location+radius to generate locations if explicit array not provided
|
|
67
|
+
let locations = args.locations;
|
|
68
|
+
if (!locations && args.location && args.radius) {
|
|
69
|
+
// Generate locations around the center point within radius
|
|
70
|
+
const center = args.location;
|
|
71
|
+
const radius = args.radius || 500;
|
|
72
|
+
const count = args.density || args.count || 10;
|
|
73
|
+
locations = [];
|
|
74
|
+
for (let i = 0; i < count; i++) {
|
|
75
|
+
const angle = Math.random() * Math.PI * 2;
|
|
76
|
+
const dist = Math.random() * radius;
|
|
77
|
+
locations.push({
|
|
78
|
+
x: (center.x || 0) + Math.cos(angle) * dist,
|
|
79
|
+
y: (center.y || 0) + Math.sin(angle) * dist,
|
|
80
|
+
z: center.z || 0
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
} else if (!locations && args.position) {
|
|
84
|
+
locations = [args.position];
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Validate we have locations to place
|
|
88
|
+
if (!locations || locations.length === 0) {
|
|
89
|
+
return cleanObject({
|
|
90
|
+
success: false,
|
|
91
|
+
error: 'INVALID_ARGUMENT',
|
|
92
|
+
message: 'add_foliage requires locations to place foliage instances. Provide: locations array, or location+radius, or position'
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return cleanObject(await tools.foliageTools.addFoliage({
|
|
97
|
+
foliageType,
|
|
98
|
+
locations
|
|
99
|
+
}));
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
case 'add_foliage_instances':
|
|
104
|
+
return cleanObject(await tools.foliageTools.addFoliageInstances({
|
|
105
|
+
foliageType: args.foliageType || args.foliageTypePath || args.meshPath,
|
|
106
|
+
transforms: args.transforms || (args.locations ? args.locations.map((l: any) => ({ location: [l.x, l.y, l.z] })) : [])
|
|
107
|
+
}));
|
|
108
|
+
case 'paint_foliage':
|
|
109
|
+
return cleanObject(await tools.foliageTools.paintFoliage({
|
|
110
|
+
foliageType: args.foliageType || args.foliageTypePath,
|
|
111
|
+
position: args.position || args.location, // Handle both
|
|
112
|
+
brushSize: args.brushSize || args.radius,
|
|
113
|
+
paintDensity: args.density || args.strength, // Map strength/density
|
|
114
|
+
eraseMode: args.eraseMode
|
|
115
|
+
}));
|
|
116
|
+
case 'create_procedural_terrain':
|
|
117
|
+
return cleanObject(await tools.landscapeTools.createProceduralTerrain({
|
|
118
|
+
name: args.name,
|
|
119
|
+
location: args.location,
|
|
120
|
+
subdivisions: args.subdivisions,
|
|
121
|
+
settings: args.settings
|
|
122
|
+
}));
|
|
123
|
+
case 'create_procedural_foliage':
|
|
124
|
+
return cleanObject(await tools.foliageTools.createProceduralFoliage({
|
|
125
|
+
name: args.name,
|
|
126
|
+
foliageTypes: args.foliageTypes,
|
|
127
|
+
volumeName: args.volumeName,
|
|
128
|
+
bounds: args.bounds,
|
|
129
|
+
seed: args.seed,
|
|
130
|
+
tileSize: args.tileSize
|
|
131
|
+
}));
|
|
132
|
+
|
|
133
|
+
case 'bake_lightmap':
|
|
134
|
+
return cleanObject(await tools.lightingTools.buildLighting({
|
|
135
|
+
quality: (args.quality as any) || 'Preview',
|
|
136
|
+
buildOnlySelected: false,
|
|
137
|
+
buildReflectionCaptures: false
|
|
138
|
+
}));
|
|
139
|
+
case 'create_landscape_grass_type':
|
|
140
|
+
return cleanObject(await tools.landscapeTools.createLandscapeGrassType({
|
|
141
|
+
name: args.name,
|
|
142
|
+
// Prefer explicit meshPath used by tests, fall back to path/staticMesh for
|
|
143
|
+
// compatibility with older callers.
|
|
144
|
+
meshPath: args.meshPath || args.path || args.staticMesh,
|
|
145
|
+
path: args.path,
|
|
146
|
+
staticMesh: args.staticMesh
|
|
147
|
+
}));
|
|
148
|
+
case 'export_snapshot':
|
|
149
|
+
return cleanObject(await tools.environmentTools.exportSnapshot({
|
|
150
|
+
path: args.path,
|
|
151
|
+
filename: args.filename
|
|
152
|
+
}));
|
|
153
|
+
case 'import_snapshot':
|
|
154
|
+
return cleanObject(await tools.environmentTools.importSnapshot({
|
|
155
|
+
path: args.path,
|
|
156
|
+
filename: args.filename
|
|
157
|
+
}));
|
|
158
|
+
case 'set_landscape_material':
|
|
159
|
+
return cleanObject(await tools.landscapeTools.setLandscapeMaterial({
|
|
160
|
+
landscapeName: args.landscapeName || args.name,
|
|
161
|
+
materialPath: args.materialPath
|
|
162
|
+
}));
|
|
163
|
+
case 'generate_lods':
|
|
164
|
+
return cleanObject(await executeAutomationRequest(tools, 'build_environment', {
|
|
165
|
+
action: 'generate_lods',
|
|
166
|
+
assetPaths: args.assetPaths || args.assets || (args.path ? [args.path] : []),
|
|
167
|
+
numLODs: args.numLODs
|
|
168
|
+
}, 'Bridge unavailable'));
|
|
169
|
+
case 'delete': {
|
|
170
|
+
const names = Array.isArray(args.names)
|
|
171
|
+
? args.names
|
|
172
|
+
: (Array.isArray(args.actors) ? args.actors : []);
|
|
173
|
+
if (args.name) {
|
|
174
|
+
names.push(args.name);
|
|
175
|
+
}
|
|
176
|
+
const res = await tools.environmentTools.cleanup({ names });
|
|
177
|
+
return cleanObject(res);
|
|
178
|
+
}
|
|
179
|
+
default:
|
|
180
|
+
const res = await executeAutomationRequest(tools, 'build_environment', args, 'Automation bridge not available for environment building operations');
|
|
181
|
+
return cleanObject(res);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { cleanObject } from '../../utils/safe-json.js';
|
|
2
|
+
import { ITools } from '../../types/tool-interfaces.js';
|
|
3
|
+
import { executeAutomationRequest } from './common-handlers.js';
|
|
4
|
+
|
|
5
|
+
export async function handleGraphTools(toolName: string, action: string, args: any, tools: ITools) {
|
|
6
|
+
// Common validation
|
|
7
|
+
if (!args.assetPath && !args.blueprintPath && !args.systemPath) {
|
|
8
|
+
// Some actions might not need a path if they operate on "currently open" asset,
|
|
9
|
+
// but generally we want an asset path.
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// Dispatch based on tool name
|
|
13
|
+
switch (toolName) {
|
|
14
|
+
case 'manage_blueprint_graph':
|
|
15
|
+
return handleBlueprintGraph(action, args, tools);
|
|
16
|
+
case 'manage_niagara_graph':
|
|
17
|
+
return handleNiagaraGraph(action, args, tools);
|
|
18
|
+
case 'manage_material_graph':
|
|
19
|
+
return handleMaterialGraph(action, args, tools);
|
|
20
|
+
case 'manage_behavior_tree':
|
|
21
|
+
return handleBehaviorTree(action, args, tools);
|
|
22
|
+
default:
|
|
23
|
+
return { success: false, error: 'UNKNOWN_TOOL', message: `Unknown graph tool: ${toolName}` };
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async function handleBlueprintGraph(action: string, args: any, tools: ITools) {
|
|
28
|
+
const processedArgs = { ...args, subAction: action };
|
|
29
|
+
|
|
30
|
+
// Default graphName
|
|
31
|
+
if (!processedArgs.graphName) {
|
|
32
|
+
processedArgs.graphName = 'EventGraph';
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Fix Issue 1: Map FunctionCall to CallFunction
|
|
36
|
+
if (processedArgs.nodeType === 'FunctionCall') {
|
|
37
|
+
processedArgs.nodeType = 'CallFunction';
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Fix Issue 2 & 3: Map memberName to specific names based on nodeType
|
|
41
|
+
if (processedArgs.memberName) {
|
|
42
|
+
if (processedArgs.nodeType === 'VariableGet' || processedArgs.nodeType === 'VariableSet') {
|
|
43
|
+
if (!processedArgs.variableName) processedArgs.variableName = processedArgs.memberName;
|
|
44
|
+
} else if (processedArgs.nodeType === 'Event' || processedArgs.nodeType === 'CustomEvent' || (processedArgs.nodeType && processedArgs.nodeType.startsWith('K2Node_Event'))) {
|
|
45
|
+
if (!processedArgs.eventName) processedArgs.eventName = processedArgs.memberName;
|
|
46
|
+
// CustomEvent uses eventName (mapped to CustomFunctionName) or customEventName in some contexts,
|
|
47
|
+
// but C++ CustomEvent handler uses 'eventName' payload field.
|
|
48
|
+
} else if (processedArgs.nodeType === 'CallFunction' || processedArgs.nodeType === 'K2Node_CallFunction') {
|
|
49
|
+
// C++ uses 'memberName' for CallFunction, so this is fine.
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Fix Issue 5: Map memberClass/componentClass to targetClass for Cast nodes
|
|
54
|
+
if ((processedArgs.memberClass || processedArgs.componentClass) &&
|
|
55
|
+
(processedArgs.nodeType === 'Cast' || (processedArgs.nodeType && processedArgs.nodeType.startsWith('CastTo')))) {
|
|
56
|
+
if (!processedArgs.targetClass) processedArgs.targetClass = processedArgs.memberClass || processedArgs.componentClass;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Fix Issue 6: Support connect_pins parameter mapping
|
|
60
|
+
// Input: nodeId, pinName, linkedTo (TargetNode.Pin)
|
|
61
|
+
if (action === 'connect_pins') {
|
|
62
|
+
// Map source
|
|
63
|
+
if (!processedArgs.fromNodeId && processedArgs.nodeId) {
|
|
64
|
+
processedArgs.fromNodeId = processedArgs.nodeId;
|
|
65
|
+
}
|
|
66
|
+
if (!processedArgs.fromPinName && processedArgs.pinName) {
|
|
67
|
+
processedArgs.fromPinName = processedArgs.pinName;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Map target from linkedTo
|
|
71
|
+
if (!processedArgs.toNodeId && processedArgs.linkedTo) {
|
|
72
|
+
if (processedArgs.linkedTo.includes('.')) {
|
|
73
|
+
const parts = processedArgs.linkedTo.split('.');
|
|
74
|
+
processedArgs.toNodeId = parts[0];
|
|
75
|
+
processedArgs.toPinName = parts.slice(1).join('.');
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Support Node.Pin format for connect_pins (existing logic preserved/enhanced)
|
|
81
|
+
if (action === 'connect_pins') {
|
|
82
|
+
if (processedArgs.fromNodeId && processedArgs.fromNodeId.includes('.') && !processedArgs.fromPinName) {
|
|
83
|
+
const parts = processedArgs.fromNodeId.split('.');
|
|
84
|
+
processedArgs.fromNodeId = parts[0];
|
|
85
|
+
processedArgs.fromPinName = parts.slice(1).join('.');
|
|
86
|
+
}
|
|
87
|
+
if (processedArgs.toNodeId && processedArgs.toNodeId.includes('.') && !processedArgs.toPinName) {
|
|
88
|
+
const parts = processedArgs.toNodeId.split('.');
|
|
89
|
+
processedArgs.toNodeId = parts[0];
|
|
90
|
+
processedArgs.toPinName = parts.slice(1).join('.');
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const res: any = await executeAutomationRequest(tools, 'manage_blueprint_graph', processedArgs, 'Automation bridge not available');
|
|
95
|
+
return cleanObject({ ...res, ...(res.result || {}) });
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
async function handleNiagaraGraph(action: string, args: any, tools: ITools) {
|
|
99
|
+
const payload = { ...args, subAction: action };
|
|
100
|
+
// Map systemPath to assetPath if missing
|
|
101
|
+
if (payload.systemPath && !payload.assetPath) {
|
|
102
|
+
payload.assetPath = payload.systemPath;
|
|
103
|
+
}
|
|
104
|
+
const res: any = await executeAutomationRequest(tools, 'manage_niagara_graph', payload, 'Automation bridge not available');
|
|
105
|
+
return cleanObject({ ...res, ...(res.result || {}) });
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
async function handleMaterialGraph(action: string, args: any, tools: ITools) {
|
|
109
|
+
const res: any = await executeAutomationRequest(tools, 'manage_material_graph', { ...args, subAction: action }, 'Automation bridge not available');
|
|
110
|
+
return cleanObject({ ...res, ...(res.result || {}) });
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
async function handleBehaviorTree(action: string, args: any, tools: ITools) {
|
|
114
|
+
const res: any = await executeAutomationRequest(tools, 'manage_behavior_tree', { ...args, subAction: action }, 'Automation bridge not available');
|
|
115
|
+
return cleanObject({ ...res, ...(res.result || {}) });
|
|
116
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { ITools } from '../../types/tool-interfaces.js';
|
|
2
|
+
import { cleanObject } from '../../utils/safe-json.js';
|
|
3
|
+
import { ResponseFactory } from '../../utils/response-factory.js';
|
|
4
|
+
import { InputTools } from '../input.js';
|
|
5
|
+
|
|
6
|
+
export async function handleInputTools(
|
|
7
|
+
action: string,
|
|
8
|
+
args: any,
|
|
9
|
+
tools: ITools
|
|
10
|
+
) {
|
|
11
|
+
const inputTools = tools.inputTools as InputTools;
|
|
12
|
+
if (!inputTools) {
|
|
13
|
+
return ResponseFactory.error('Input tools not available');
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
switch (action) {
|
|
17
|
+
case 'create_input_action':
|
|
18
|
+
return cleanObject(await inputTools.createInputAction(args.name, args.path));
|
|
19
|
+
case 'create_input_mapping_context':
|
|
20
|
+
return cleanObject(await inputTools.createInputMappingContext(args.name, args.path));
|
|
21
|
+
case 'add_mapping':
|
|
22
|
+
return cleanObject(await inputTools.addMapping(args.contextPath, args.actionPath, args.key));
|
|
23
|
+
case 'remove_mapping':
|
|
24
|
+
return cleanObject(await inputTools.removeMapping(args.contextPath, args.actionPath));
|
|
25
|
+
default:
|
|
26
|
+
return ResponseFactory.error(`Unknown input action: ${action}`);
|
|
27
|
+
}
|
|
28
|
+
}
|