unreal-engine-mcp-server 0.4.7 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +26 -0
- package/.env.production +38 -7
- package/.eslintrc.json +0 -54
- package/.eslintrc.override.json +8 -0
- package/.github/ISSUE_TEMPLATE/bug_report.yml +94 -0
- package/.github/ISSUE_TEMPLATE/config.yml +8 -0
- package/.github/ISSUE_TEMPLATE/feature_request.yml +56 -0
- package/.github/copilot-instructions.md +478 -45
- package/.github/dependabot.yml +19 -0
- package/.github/labeler.yml +24 -0
- package/.github/labels.yml +70 -0
- package/.github/pull_request_template.md +42 -0
- package/.github/release-drafter-config.yml +51 -0
- package/.github/workflows/auto-merge.yml +38 -0
- package/.github/workflows/ci.yml +38 -0
- package/.github/workflows/dependency-review.yml +17 -0
- package/.github/workflows/gemini-issue-triage.yml +172 -0
- package/.github/workflows/greetings.yml +27 -0
- package/.github/workflows/labeler.yml +17 -0
- package/.github/workflows/links.yml +80 -0
- package/.github/workflows/pr-size-labeler.yml +137 -0
- package/.github/workflows/publish-mcp.yml +13 -7
- package/.github/workflows/release-drafter.yml +23 -0
- package/.github/workflows/release.yml +112 -0
- package/.github/workflows/semantic-pull-request.yml +35 -0
- package/.github/workflows/smoke-test.yml +36 -0
- package/.github/workflows/stale.yml +28 -0
- package/CHANGELOG.md +338 -31
- package/CONTRIBUTING.md +140 -0
- package/GEMINI.md +115 -0
- package/Public/Plugin_setup_guide.mp4 +0 -0
- package/README.md +189 -128
- package/claude_desktop_config_example.json +7 -6
- package/dist/automation/bridge.d.ts +50 -0
- package/dist/automation/bridge.js +452 -0
- package/dist/automation/connection-manager.d.ts +23 -0
- package/dist/automation/connection-manager.js +107 -0
- package/dist/automation/handshake.d.ts +11 -0
- package/dist/automation/handshake.js +89 -0
- package/dist/automation/index.d.ts +3 -0
- package/dist/automation/index.js +3 -0
- package/dist/automation/message-handler.d.ts +12 -0
- package/dist/automation/message-handler.js +149 -0
- package/dist/automation/request-tracker.d.ts +25 -0
- package/dist/automation/request-tracker.js +98 -0
- package/dist/automation/types.d.ts +130 -0
- package/dist/automation/types.js +2 -0
- package/dist/cli.js +32 -5
- package/dist/config.d.ts +26 -0
- package/dist/config.js +59 -0
- package/dist/constants.d.ts +16 -0
- package/dist/constants.js +16 -0
- package/dist/graphql/loaders.d.ts +64 -0
- package/dist/graphql/loaders.js +117 -0
- package/dist/graphql/resolvers.d.ts +268 -0
- package/dist/graphql/resolvers.js +746 -0
- package/dist/graphql/schema.d.ts +5 -0
- package/dist/graphql/schema.js +437 -0
- package/dist/graphql/server.d.ts +26 -0
- package/dist/graphql/server.js +117 -0
- package/dist/graphql/types.d.ts +9 -0
- package/dist/graphql/types.js +2 -0
- package/dist/handlers/resource-handlers.d.ts +20 -0
- package/dist/handlers/resource-handlers.js +180 -0
- package/dist/index.d.ts +33 -18
- package/dist/index.js +130 -619
- package/dist/resources/actors.d.ts +17 -12
- package/dist/resources/actors.js +56 -76
- package/dist/resources/assets.d.ts +6 -14
- package/dist/resources/assets.js +115 -147
- package/dist/resources/levels.d.ts +13 -13
- package/dist/resources/levels.js +25 -34
- package/dist/server/resource-registry.d.ts +20 -0
- package/dist/server/resource-registry.js +37 -0
- package/dist/server/tool-registry.d.ts +23 -0
- package/dist/server/tool-registry.js +322 -0
- package/dist/server-setup.d.ts +20 -0
- package/dist/server-setup.js +71 -0
- package/dist/services/health-monitor.d.ts +34 -0
- package/dist/services/health-monitor.js +105 -0
- package/dist/services/metrics-server.d.ts +11 -0
- package/dist/services/metrics-server.js +105 -0
- package/dist/tools/actors.d.ts +163 -9
- package/dist/tools/actors.js +356 -311
- package/dist/tools/animation.d.ts +135 -4
- package/dist/tools/animation.js +510 -411
- package/dist/tools/assets.d.ts +75 -29
- package/dist/tools/assets.js +265 -284
- package/dist/tools/audio.d.ts +102 -42
- package/dist/tools/audio.js +272 -685
- package/dist/tools/base-tool.d.ts +17 -0
- package/dist/tools/base-tool.js +46 -0
- package/dist/tools/behavior-tree.d.ts +94 -0
- package/dist/tools/behavior-tree.js +39 -0
- package/dist/tools/blueprint.d.ts +208 -126
- package/dist/tools/blueprint.js +685 -832
- package/dist/tools/consolidated-tool-definitions.d.ts +5462 -1781
- package/dist/tools/consolidated-tool-definitions.js +829 -496
- package/dist/tools/consolidated-tool-handlers.d.ts +2 -1
- package/dist/tools/consolidated-tool-handlers.js +198 -1027
- package/dist/tools/debug.d.ts +143 -85
- package/dist/tools/debug.js +234 -180
- package/dist/tools/dynamic-handler-registry.d.ts +13 -0
- package/dist/tools/dynamic-handler-registry.js +23 -0
- package/dist/tools/editor.d.ts +30 -83
- package/dist/tools/editor.js +247 -244
- package/dist/tools/engine.d.ts +10 -4
- package/dist/tools/engine.js +13 -5
- package/dist/tools/environment.d.ts +30 -0
- package/dist/tools/environment.js +267 -0
- package/dist/tools/foliage.d.ts +65 -99
- package/dist/tools/foliage.js +221 -331
- package/dist/tools/handlers/actor-handlers.d.ts +3 -0
- package/dist/tools/handlers/actor-handlers.js +227 -0
- package/dist/tools/handlers/animation-handlers.d.ts +3 -0
- package/dist/tools/handlers/animation-handlers.js +185 -0
- package/dist/tools/handlers/argument-helper.d.ts +16 -0
- package/dist/tools/handlers/argument-helper.js +80 -0
- package/dist/tools/handlers/asset-handlers.d.ts +3 -0
- package/dist/tools/handlers/asset-handlers.js +496 -0
- package/dist/tools/handlers/audio-handlers.d.ts +3 -0
- package/dist/tools/handlers/audio-handlers.js +166 -0
- package/dist/tools/handlers/blueprint-handlers.d.ts +4 -0
- package/dist/tools/handlers/blueprint-handlers.js +358 -0
- package/dist/tools/handlers/common-handlers.d.ts +14 -0
- package/dist/tools/handlers/common-handlers.js +56 -0
- package/dist/tools/handlers/editor-handlers.d.ts +3 -0
- package/dist/tools/handlers/editor-handlers.js +119 -0
- package/dist/tools/handlers/effect-handlers.d.ts +3 -0
- package/dist/tools/handlers/effect-handlers.js +171 -0
- package/dist/tools/handlers/environment-handlers.d.ts +3 -0
- package/dist/tools/handlers/environment-handlers.js +170 -0
- package/dist/tools/handlers/graph-handlers.d.ts +3 -0
- package/dist/tools/handlers/graph-handlers.js +90 -0
- package/dist/tools/handlers/input-handlers.d.ts +3 -0
- package/dist/tools/handlers/input-handlers.js +21 -0
- package/dist/tools/handlers/inspect-handlers.d.ts +3 -0
- package/dist/tools/handlers/inspect-handlers.js +383 -0
- package/dist/tools/handlers/level-handlers.d.ts +3 -0
- package/dist/tools/handlers/level-handlers.js +237 -0
- package/dist/tools/handlers/lighting-handlers.d.ts +3 -0
- package/dist/tools/handlers/lighting-handlers.js +144 -0
- package/dist/tools/handlers/performance-handlers.d.ts +3 -0
- package/dist/tools/handlers/performance-handlers.js +130 -0
- package/dist/tools/handlers/pipeline-handlers.d.ts +3 -0
- package/dist/tools/handlers/pipeline-handlers.js +110 -0
- package/dist/tools/handlers/sequence-handlers.d.ts +3 -0
- package/dist/tools/handlers/sequence-handlers.js +376 -0
- package/dist/tools/handlers/system-handlers.d.ts +4 -0
- package/dist/tools/handlers/system-handlers.js +506 -0
- package/dist/tools/input.d.ts +19 -0
- package/dist/tools/input.js +89 -0
- package/dist/tools/introspection.d.ts +103 -40
- package/dist/tools/introspection.js +425 -568
- package/dist/tools/landscape.d.ts +54 -93
- package/dist/tools/landscape.js +284 -409
- package/dist/tools/level.d.ts +66 -27
- package/dist/tools/level.js +647 -675
- package/dist/tools/lighting.d.ts +77 -38
- package/dist/tools/lighting.js +445 -943
- package/dist/tools/logs.d.ts +3 -3
- package/dist/tools/logs.js +5 -57
- package/dist/tools/materials.d.ts +91 -24
- package/dist/tools/materials.js +194 -118
- package/dist/tools/niagara.d.ts +149 -39
- package/dist/tools/niagara.js +267 -182
- package/dist/tools/performance.d.ts +27 -13
- package/dist/tools/performance.js +203 -122
- package/dist/tools/physics.d.ts +32 -77
- package/dist/tools/physics.js +175 -582
- package/dist/tools/property-dictionary.d.ts +13 -0
- package/dist/tools/property-dictionary.js +82 -0
- package/dist/tools/sequence.d.ts +85 -60
- package/dist/tools/sequence.js +208 -747
- package/dist/tools/tool-definition-utils.d.ts +59 -0
- package/dist/tools/tool-definition-utils.js +35 -0
- package/dist/tools/ui.d.ts +64 -34
- package/dist/tools/ui.js +134 -214
- package/dist/types/automation-responses.d.ts +115 -0
- package/dist/types/automation-responses.js +2 -0
- package/dist/types/env.d.ts +0 -3
- package/dist/types/env.js +0 -7
- package/dist/types/responses.d.ts +249 -0
- package/dist/types/responses.js +2 -0
- package/dist/types/tool-interfaces.d.ts +898 -0
- package/dist/types/tool-interfaces.js +2 -0
- package/dist/types/tool-types.d.ts +183 -19
- package/dist/types/tool-types.js +0 -4
- package/dist/unreal-bridge.d.ts +24 -131
- package/dist/unreal-bridge.js +364 -1506
- package/dist/utils/command-validator.d.ts +9 -0
- package/dist/utils/command-validator.js +68 -0
- package/dist/utils/elicitation.d.ts +1 -1
- package/dist/utils/elicitation.js +12 -15
- package/dist/utils/error-handler.d.ts +2 -51
- package/dist/utils/error-handler.js +11 -87
- package/dist/utils/ini-reader.d.ts +3 -0
- package/dist/utils/ini-reader.js +69 -0
- package/dist/utils/logger.js +9 -6
- package/dist/utils/normalize.d.ts +3 -0
- package/dist/utils/normalize.js +56 -0
- package/dist/utils/path-security.d.ts +2 -0
- package/dist/utils/path-security.js +24 -0
- package/dist/utils/response-factory.d.ts +7 -0
- package/dist/utils/response-factory.js +27 -0
- package/dist/utils/response-validator.d.ts +3 -24
- package/dist/utils/response-validator.js +130 -81
- package/dist/utils/result-helpers.d.ts +4 -5
- package/dist/utils/result-helpers.js +15 -16
- package/dist/utils/safe-json.js +5 -11
- package/dist/utils/unreal-command-queue.d.ts +24 -0
- package/dist/utils/unreal-command-queue.js +120 -0
- package/dist/utils/validation.d.ts +0 -40
- package/dist/utils/validation.js +1 -78
- package/dist/wasm/index.d.ts +70 -0
- package/dist/wasm/index.js +535 -0
- package/docs/GraphQL-API.md +888 -0
- package/docs/Migration-Guide-v0.5.0.md +684 -0
- package/docs/Roadmap.md +53 -0
- package/docs/WebAssembly-Integration.md +628 -0
- package/docs/editor-plugin-extension.md +370 -0
- package/docs/handler-mapping.md +242 -0
- package/docs/native-automation-progress.md +128 -0
- package/docs/testing-guide.md +423 -0
- package/mcp-config-example.json +6 -6
- package/package.json +67 -28
- package/plugins/McpAutomationBridge/Config/FilterPlugin.ini +8 -0
- package/plugins/McpAutomationBridge/McpAutomationBridge.uplugin +64 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/McpAutomationBridge.Build.cs +189 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridgeGlobals.cpp +22 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridgeGlobals.h +30 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridgeHelpers.h +1983 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridgeModule.cpp +72 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridgeSettings.cpp +46 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridgeSubsystem.cpp +581 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_AnimationHandlers.cpp +2394 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_AssetQueryHandlers.cpp +300 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_AssetWorkflowHandlers.cpp +2807 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_AudioHandlers.cpp +1087 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_BehaviorTreeHandlers.cpp +488 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_BlueprintCreationHandlers.cpp +643 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_BlueprintCreationHandlers.h +31 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_BlueprintGraphHandlers.cpp +1184 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_BlueprintHandlers.cpp +5652 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_BlueprintHandlers_List.cpp +152 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_ControlHandlers.cpp +2614 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_DebugHandlers.cpp +42 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_EditorFunctionHandlers.cpp +1237 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_EffectHandlers.cpp +1701 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_EnvironmentHandlers.cpp +2145 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_FoliageHandlers.cpp +954 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_InputHandlers.cpp +209 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_InsightsHandlers.cpp +41 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_LandscapeHandlers.cpp +1164 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_LevelHandlers.cpp +762 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_LightingHandlers.cpp +634 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_LogHandlers.cpp +136 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_MaterialGraphHandlers.cpp +494 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_NiagaraGraphHandlers.cpp +278 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_NiagaraHandlers.cpp +625 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_PerformanceHandlers.cpp +401 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_PipelineHandlers.cpp +67 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_ProcessRequest.cpp +735 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_PropertyHandlers.cpp +2634 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_RenderHandlers.cpp +189 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_SCSHandlers.cpp +917 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_SCSHandlers.h +39 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_SequenceHandlers.cpp +2670 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_SequencerHandlers.cpp +519 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_TestHandlers.cpp +38 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_UiHandlers.cpp +668 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_WorldPartitionHandlers.cpp +346 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpBridgeWebSocket.cpp +1330 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpBridgeWebSocket.h +149 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpConnectionManager.cpp +783 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Public/McpAutomationBridgeSettings.h +115 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Public/McpAutomationBridgeSubsystem.h +796 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Public/McpConnectionManager.h +117 -0
- package/scripts/check-unreal-connection.mjs +19 -0
- package/scripts/clean-tmp.js +23 -0
- package/scripts/patch-wasm.js +26 -0
- package/scripts/run-all-tests.mjs +136 -0
- package/scripts/smoke-test.ts +94 -0
- package/scripts/sync-mcp-plugin.js +143 -0
- package/scripts/test-no-plugin-alternates.mjs +113 -0
- package/scripts/validate-server.js +46 -0
- package/scripts/verify-automation-bridge.js +200 -0
- package/server.json +58 -21
- package/src/automation/bridge.ts +558 -0
- package/src/automation/connection-manager.ts +130 -0
- package/src/automation/handshake.ts +99 -0
- package/src/automation/index.ts +2 -0
- package/src/automation/message-handler.ts +167 -0
- package/src/automation/request-tracker.ts +123 -0
- package/src/automation/types.ts +107 -0
- package/src/cli.ts +33 -6
- package/src/config.ts +73 -0
- package/src/constants.ts +19 -0
- package/src/graphql/loaders.ts +244 -0
- package/src/graphql/resolvers.ts +1008 -0
- package/src/graphql/schema.ts +452 -0
- package/src/graphql/server.ts +156 -0
- package/src/graphql/types.ts +10 -0
- package/src/handlers/resource-handlers.ts +186 -0
- package/src/index.ts +166 -664
- package/src/resources/actors.ts +58 -76
- package/src/resources/assets.ts +148 -134
- package/src/resources/levels.ts +28 -33
- package/src/server/resource-registry.ts +47 -0
- package/src/server/tool-registry.ts +354 -0
- package/src/server-setup.ts +114 -0
- package/src/services/health-monitor.ts +132 -0
- package/src/services/metrics-server.ts +142 -0
- package/src/tools/actors.ts +426 -323
- package/src/tools/animation.ts +672 -461
- package/src/tools/assets.ts +364 -289
- package/src/tools/audio.ts +323 -766
- package/src/tools/base-tool.ts +52 -0
- package/src/tools/behavior-tree.ts +45 -0
- package/src/tools/blueprint.ts +792 -970
- package/src/tools/consolidated-tool-definitions.ts +993 -515
- package/src/tools/consolidated-tool-handlers.ts +258 -1146
- package/src/tools/debug.ts +292 -187
- package/src/tools/dynamic-handler-registry.ts +33 -0
- package/src/tools/editor.ts +329 -253
- package/src/tools/engine.ts +14 -3
- package/src/tools/environment.ts +281 -0
- package/src/tools/foliage.ts +330 -392
- package/src/tools/handlers/actor-handlers.ts +265 -0
- package/src/tools/handlers/animation-handlers.ts +237 -0
- package/src/tools/handlers/argument-helper.ts +142 -0
- package/src/tools/handlers/asset-handlers.ts +532 -0
- package/src/tools/handlers/audio-handlers.ts +194 -0
- package/src/tools/handlers/blueprint-handlers.ts +380 -0
- package/src/tools/handlers/common-handlers.ts +87 -0
- package/src/tools/handlers/editor-handlers.ts +123 -0
- package/src/tools/handlers/effect-handlers.ts +220 -0
- package/src/tools/handlers/environment-handlers.ts +183 -0
- package/src/tools/handlers/graph-handlers.ts +116 -0
- package/src/tools/handlers/input-handlers.ts +28 -0
- package/src/tools/handlers/inspect-handlers.ts +450 -0
- package/src/tools/handlers/level-handlers.ts +252 -0
- package/src/tools/handlers/lighting-handlers.ts +147 -0
- package/src/tools/handlers/performance-handlers.ts +132 -0
- package/src/tools/handlers/pipeline-handlers.ts +127 -0
- package/src/tools/handlers/sequence-handlers.ts +415 -0
- package/src/tools/handlers/system-handlers.ts +564 -0
- package/src/tools/input.ts +101 -0
- package/src/tools/introspection.ts +493 -584
- package/src/tools/landscape.ts +418 -507
- package/src/tools/level.ts +786 -708
- package/src/tools/lighting.ts +588 -984
- package/src/tools/logs.ts +9 -57
- package/src/tools/materials.ts +237 -121
- package/src/tools/niagara.ts +335 -168
- package/src/tools/performance.ts +320 -169
- package/src/tools/physics.ts +274 -613
- package/src/tools/property-dictionary.ts +98 -0
- package/src/tools/sequence.ts +276 -820
- package/src/tools/tool-definition-utils.ts +35 -0
- package/src/tools/ui.ts +205 -283
- package/src/types/automation-responses.ts +119 -0
- package/src/types/env.ts +0 -10
- package/src/types/responses.ts +355 -0
- package/src/types/tool-interfaces.ts +250 -0
- package/src/types/tool-types.ts +243 -21
- package/src/unreal-bridge.ts +460 -1550
- package/src/utils/command-validator.ts +76 -0
- package/src/utils/elicitation.ts +10 -7
- package/src/utils/error-handler.ts +14 -90
- package/src/utils/ini-reader.ts +86 -0
- package/src/utils/logger.ts +8 -3
- package/src/utils/normalize.test.ts +162 -0
- package/src/utils/normalize.ts +60 -0
- package/src/utils/path-security.ts +43 -0
- package/src/utils/response-factory.ts +44 -0
- package/src/utils/response-validator.ts +176 -56
- package/src/utils/result-helpers.ts +21 -19
- package/src/utils/safe-json.test.ts +90 -0
- package/src/utils/safe-json.ts +14 -11
- package/src/utils/unreal-command-queue.ts +152 -0
- package/src/utils/validation.test.ts +184 -0
- package/src/utils/validation.ts +4 -1
- package/src/wasm/index.ts +838 -0
- package/test-server.mjs +100 -0
- package/tests/run-unreal-tool-tests.mjs +242 -14
- package/tests/test-animation.mjs +369 -0
- package/tests/test-asset-advanced.mjs +82 -0
- package/tests/test-asset-errors.mjs +35 -0
- package/tests/test-asset-graph.mjs +311 -0
- package/tests/test-audio.mjs +417 -0
- package/tests/test-automation-timeouts.mjs +98 -0
- package/tests/test-behavior-tree.mjs +444 -0
- package/tests/test-blueprint-graph.mjs +410 -0
- package/tests/test-blueprint.mjs +577 -0
- package/tests/test-client-mode.mjs +86 -0
- package/tests/test-console-command.mjs +56 -0
- package/tests/test-control-actor.mjs +425 -0
- package/tests/test-control-editor.mjs +112 -0
- package/tests/test-graphql.mjs +372 -0
- package/tests/test-input.mjs +349 -0
- package/tests/test-inspect.mjs +302 -0
- package/tests/test-landscape.mjs +316 -0
- package/tests/test-lighting.mjs +428 -0
- package/tests/test-manage-asset.mjs +438 -0
- package/tests/test-manage-level.mjs +89 -0
- package/tests/test-materials.mjs +356 -0
- package/tests/test-niagara.mjs +185 -0
- package/tests/test-no-inline-python.mjs +122 -0
- package/tests/test-performance.mjs +539 -0
- package/tests/test-plugin-handshake.mjs +82 -0
- package/tests/test-runner.mjs +933 -0
- package/tests/test-sequence.mjs +104 -0
- package/tests/test-system.mjs +96 -0
- package/tests/test-wasm.mjs +283 -0
- package/tests/test-world-partition.mjs +215 -0
- package/tsconfig.json +3 -3
- package/vitest.config.ts +35 -0
- package/wasm/Cargo.lock +363 -0
- package/wasm/Cargo.toml +42 -0
- package/wasm/LICENSE +21 -0
- package/wasm/README.md +253 -0
- package/wasm/src/dependency_resolver.rs +377 -0
- package/wasm/src/lib.rs +153 -0
- package/wasm/src/property_parser.rs +271 -0
- package/wasm/src/transform_math.rs +396 -0
- package/wasm/tests/integration.rs +109 -0
- package/.github/workflows/smithery-build.yml +0 -29
- package/dist/prompts/index.d.ts +0 -21
- package/dist/prompts/index.js +0 -217
- package/dist/tools/build_environment_advanced.d.ts +0 -65
- package/dist/tools/build_environment_advanced.js +0 -633
- package/dist/tools/rc.d.ts +0 -110
- package/dist/tools/rc.js +0 -437
- package/dist/tools/visual.d.ts +0 -40
- package/dist/tools/visual.js +0 -282
- package/dist/utils/http.d.ts +0 -6
- package/dist/utils/http.js +0 -151
- package/dist/utils/python-output.d.ts +0 -18
- package/dist/utils/python-output.js +0 -290
- package/dist/utils/python.d.ts +0 -2
- package/dist/utils/python.js +0 -4
- package/dist/utils/stdio-redirect.d.ts +0 -2
- package/dist/utils/stdio-redirect.js +0 -20
- package/docs/unreal-tool-test-cases.md +0 -574
- package/smithery.yaml +0 -29
- package/src/prompts/index.ts +0 -249
- package/src/tools/build_environment_advanced.ts +0 -732
- package/src/tools/rc.ts +0 -515
- package/src/tools/visual.ts +0 -281
- package/src/utils/http.ts +0 -187
- package/src/utils/python-output.ts +0 -351
- package/src/utils/python.ts +0 -3
- package/src/utils/stdio-redirect.ts +0 -18
package/dist/tools/foliage.js
CHANGED
|
@@ -1,16 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { coerceBoolean, coerceNumber, coerceString } from '../utils/result-helpers.js';
|
|
2
2
|
export class FoliageTools {
|
|
3
3
|
bridge;
|
|
4
|
-
|
|
4
|
+
automationBridge;
|
|
5
|
+
constructor(bridge, automationBridge) {
|
|
5
6
|
this.bridge = bridge;
|
|
7
|
+
this.automationBridge = automationBridge;
|
|
6
8
|
}
|
|
7
|
-
|
|
8
|
-
// they have proven unreliable and generate engine warnings (failed FindConsoleObject).
|
|
9
|
-
// Instead, we validate inputs and return structured results. Actual foliage
|
|
10
|
-
// authoring should be implemented via Python APIs in future iterations.
|
|
11
|
-
// Add foliage type via Python (creates FoliageType asset properly)
|
|
9
|
+
setAutomationBridge(automationBridge) { this.automationBridge = automationBridge; }
|
|
12
10
|
async addFoliageType(params) {
|
|
13
|
-
// Basic validation to prevent bad inputs like 'undefined' and empty strings
|
|
14
11
|
const errors = [];
|
|
15
12
|
const name = String(params?.name ?? '').trim();
|
|
16
13
|
const meshPath = String(params?.meshPath ?? '').trim();
|
|
@@ -35,194 +32,58 @@ export class FoliageTools {
|
|
|
35
32
|
if (errors.length > 0) {
|
|
36
33
|
return { success: false, error: errors.join('; ') };
|
|
37
34
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
# Try to create factory and set mesh property
|
|
85
|
-
factory = None
|
|
86
|
-
try:
|
|
87
|
-
factory = unreal.FoliageType_InstancedStaticMeshFactory()
|
|
88
|
-
# Try different property names for different UE versions
|
|
89
|
-
try:
|
|
90
|
-
factory.set_editor_property('mesh', mesh)
|
|
91
|
-
except:
|
|
92
|
-
try:
|
|
93
|
-
factory.set_editor_property('static_mesh', mesh)
|
|
94
|
-
except:
|
|
95
|
-
try:
|
|
96
|
-
factory.set_editor_property('source_mesh', mesh)
|
|
97
|
-
except:
|
|
98
|
-
pass # Factory will use default or no mesh
|
|
99
|
-
except:
|
|
100
|
-
res['note'] += '; factory_creation_failed'
|
|
101
|
-
factory = None
|
|
102
|
-
|
|
103
|
-
# Create the asset with or without factory
|
|
104
|
-
if factory:
|
|
105
|
-
asset = asset_tools.create_asset(
|
|
106
|
-
asset_name=name,
|
|
107
|
-
package_path=package_path,
|
|
108
|
-
asset_class=unreal.FoliageType_InstancedStaticMesh,
|
|
109
|
-
factory=factory
|
|
110
|
-
)
|
|
111
|
-
else:
|
|
112
|
-
# Try without factory
|
|
113
|
-
asset = asset_tools.create_asset(
|
|
114
|
-
asset_name=name,
|
|
115
|
-
package_path=package_path,
|
|
116
|
-
asset_class=unreal.FoliageType_InstancedStaticMesh,
|
|
117
|
-
factory=None
|
|
118
|
-
)
|
|
119
|
-
|
|
120
|
-
if asset:
|
|
121
|
-
# Configure foliage properties
|
|
122
|
-
asset.set_editor_property('mesh', mesh)
|
|
123
|
-
if ${params.density !== undefined ? params.density : 1.0} >= 0:
|
|
124
|
-
asset.set_editor_property('density', ${params.density !== undefined ? params.density : 1.0})
|
|
125
|
-
if ${params.randomYaw === false ? 'False' : 'True'}:
|
|
126
|
-
asset.set_editor_property('random_yaw', True)
|
|
127
|
-
if ${params.alignToNormal === false ? 'False' : 'True'}:
|
|
128
|
-
asset.set_editor_property('align_to_normal', True)
|
|
129
|
-
|
|
130
|
-
# Set scale range
|
|
131
|
-
min_scale = ${params.minScale || 0.8}
|
|
132
|
-
max_scale = ${params.maxScale || 1.2}
|
|
133
|
-
asset.set_editor_property('scale_x', (min_scale, max_scale))
|
|
134
|
-
asset.set_editor_property('scale_y', (min_scale, max_scale))
|
|
135
|
-
asset.set_editor_property('scale_z', (min_scale, max_scale))
|
|
136
|
-
|
|
137
|
-
res['note'] += '; created_with_factory'
|
|
138
|
-
else:
|
|
139
|
-
res['note'] += '; factory_creation_failed'
|
|
140
|
-
except AttributeError:
|
|
141
|
-
# Fallback if factory doesn't exist - use base FoliageType
|
|
142
|
-
try:
|
|
143
|
-
asset = asset_tools.create_asset(
|
|
144
|
-
asset_name=name,
|
|
145
|
-
package_path=package_path,
|
|
146
|
-
asset_class=unreal.FoliageType,
|
|
147
|
-
factory=None
|
|
148
|
-
)
|
|
149
|
-
if asset:
|
|
150
|
-
res['note'] += '; created_base_foliage_type'
|
|
151
|
-
except Exception as e2:
|
|
152
|
-
res['note'] += f"; base_creation_failed: {e2}"
|
|
153
|
-
except Exception as e:
|
|
154
|
-
res['note'] += f"; factory_creation_failed: {e}"
|
|
155
|
-
asset = None
|
|
156
|
-
except Exception as e:
|
|
157
|
-
res['note'] += f"; create_asset failed: {e}"
|
|
158
|
-
asset = None
|
|
159
|
-
|
|
160
|
-
if asset and mesh:
|
|
161
|
-
try:
|
|
162
|
-
# Set the mesh property (different property names in different UE versions)
|
|
163
|
-
try:
|
|
164
|
-
asset.set_editor_property('mesh', mesh)
|
|
165
|
-
except:
|
|
166
|
-
try:
|
|
167
|
-
asset.set_editor_property('static_mesh', mesh)
|
|
168
|
-
except:
|
|
169
|
-
pass
|
|
170
|
-
|
|
171
|
-
# Save the asset
|
|
172
|
-
unreal.EditorAssetLibrary.save_asset(asset.get_path_name())
|
|
173
|
-
res['asset_path'] = str(asset.get_path_name())
|
|
174
|
-
res['created'] = True
|
|
175
|
-
res['method'] = 'FoliageType_InstancedStaticMesh'
|
|
176
|
-
except Exception as e:
|
|
177
|
-
res['note'] += f"; set/save asset failed: {e}"
|
|
178
|
-
elif not asset:
|
|
179
|
-
res['note'] += "; asset creation returned None"
|
|
180
|
-
elif not mesh:
|
|
181
|
-
res['note'] += "; mesh object is None, cannot assign to foliage type"
|
|
182
|
-
|
|
183
|
-
# Verify existence
|
|
184
|
-
res['exists_after'] = unreal.EditorAssetLibrary.does_asset_exist(res['asset_path']) if res['asset_path'] else False
|
|
185
|
-
res['success'] = res['exists_after'] or res['created']
|
|
186
|
-
|
|
187
|
-
except Exception as e:
|
|
188
|
-
res['success'] = False
|
|
189
|
-
res['note'] += f"; fatal: {e}"
|
|
190
|
-
|
|
191
|
-
print('RESULT:' + json.dumps(res))
|
|
192
|
-
`.trim();
|
|
193
|
-
const pyResp = await this.bridge.executePython(py);
|
|
194
|
-
const interpreted = interpretStandardResult(pyResp, {
|
|
195
|
-
successMessage: `Foliage type '${name}' processed`,
|
|
196
|
-
failureMessage: 'Add foliage type failed'
|
|
197
|
-
});
|
|
198
|
-
if (!interpreted.success) {
|
|
35
|
+
if (!this.automationBridge) {
|
|
36
|
+
throw new Error('Automation Bridge not available. Foliage operations require plugin support.');
|
|
37
|
+
}
|
|
38
|
+
try {
|
|
39
|
+
const base = meshPath.includes('.') ? meshPath : `${meshPath}.${meshPath.split('/').filter(Boolean).pop()}`;
|
|
40
|
+
const response = await this.automationBridge.sendAutomationRequest('add_foliage_type', {
|
|
41
|
+
name,
|
|
42
|
+
meshPath: base,
|
|
43
|
+
density: params.density ?? 100,
|
|
44
|
+
radius: params.radius ?? 0,
|
|
45
|
+
minScale: params.minScale ?? 1.0,
|
|
46
|
+
maxScale: params.maxScale ?? 1.0,
|
|
47
|
+
alignToNormal: params.alignToNormal ?? true,
|
|
48
|
+
randomYaw: params.randomYaw ?? true,
|
|
49
|
+
groundSlope: params.groundSlope ?? 45
|
|
50
|
+
}, {
|
|
51
|
+
timeoutMs: 60000
|
|
52
|
+
});
|
|
53
|
+
if (response.success === false) {
|
|
54
|
+
return {
|
|
55
|
+
success: false,
|
|
56
|
+
error: response.error || response.message || 'Add foliage type failed',
|
|
57
|
+
note: coerceString(response.result?.note)
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
const payload = response.result;
|
|
61
|
+
const created = coerceBoolean(payload.created, false) ?? false;
|
|
62
|
+
const exists = coerceBoolean(payload.exists_after, false) ?? created;
|
|
63
|
+
const method = coerceString(payload.method) ?? 'Unknown';
|
|
64
|
+
const assetPath = coerceString(payload.asset_path);
|
|
65
|
+
const usedMesh = coerceString(payload.used_mesh);
|
|
66
|
+
const note = coerceString(payload.note);
|
|
67
|
+
return {
|
|
68
|
+
success: true,
|
|
69
|
+
created,
|
|
70
|
+
exists,
|
|
71
|
+
method,
|
|
72
|
+
assetPath,
|
|
73
|
+
usedMesh,
|
|
74
|
+
note,
|
|
75
|
+
message: exists
|
|
76
|
+
? `Foliage type '${name}' ready (${method})`
|
|
77
|
+
: `Created foliage '${name}' but verification did not find it yet`
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
199
81
|
return {
|
|
200
82
|
success: false,
|
|
201
|
-
error:
|
|
202
|
-
note: coerceString(interpreted.payload.note) ?? bestEffortInterpretedText(interpreted)
|
|
83
|
+
error: `Failed to add foliage type: ${error instanceof Error ? error.message : String(error)}`
|
|
203
84
|
};
|
|
204
85
|
}
|
|
205
|
-
const payload = interpreted.payload;
|
|
206
|
-
const created = coerceBoolean(payload.created, false) ?? false;
|
|
207
|
-
const exists = coerceBoolean(payload.exists_after, false) ?? created;
|
|
208
|
-
const method = coerceString(payload.method) ?? 'Unknown';
|
|
209
|
-
const assetPath = coerceString(payload.asset_path);
|
|
210
|
-
const usedMesh = coerceString(payload.used_mesh);
|
|
211
|
-
const note = coerceString(payload.note);
|
|
212
|
-
return {
|
|
213
|
-
success: true,
|
|
214
|
-
created,
|
|
215
|
-
exists,
|
|
216
|
-
method,
|
|
217
|
-
assetPath,
|
|
218
|
-
usedMesh,
|
|
219
|
-
note,
|
|
220
|
-
message: exists
|
|
221
|
-
? `Foliage type '${name}' ready (${method})`
|
|
222
|
-
: `Created foliage '${name}' but verification did not find it yet`
|
|
223
|
-
};
|
|
224
86
|
}
|
|
225
|
-
// Paint foliage by placing HISM instances (editor-only)
|
|
226
87
|
async paintFoliage(params) {
|
|
227
88
|
const errors = [];
|
|
228
89
|
const foliageType = String(params?.foliageType ?? '').trim();
|
|
@@ -246,131 +107,92 @@ print('RESULT:' + json.dumps(res))
|
|
|
246
107
|
if (errors.length > 0) {
|
|
247
108
|
return { success: false, error: errors.join('; ') };
|
|
248
109
|
}
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
if not container:
|
|
282
|
-
raise RuntimeError('Failed to spawn foliage container actor via EditorActorSubsystem')
|
|
283
|
-
try:
|
|
284
|
-
container.set_actor_label(label)
|
|
285
|
-
except Exception:
|
|
286
|
-
pass
|
|
287
|
-
|
|
288
|
-
# Resolve mesh from FoliageType asset
|
|
289
|
-
mesh = None
|
|
290
|
-
fol_asset_path = f"/Game/Foliage/Types/{foliage_type_name}.{foliage_type_name}"
|
|
291
|
-
if unreal.EditorAssetLibrary.does_asset_exist(fol_asset_path):
|
|
292
|
-
try:
|
|
293
|
-
ft_asset = unreal.EditorAssetLibrary.load_asset(fol_asset_path)
|
|
294
|
-
mesh = ft_asset.get_editor_property('mesh')
|
|
295
|
-
except Exception:
|
|
296
|
-
mesh = None
|
|
297
|
-
|
|
298
|
-
if not mesh:
|
|
299
|
-
mesh = unreal.EditorAssetLibrary.load_asset('/Engine/EngineMeshes/Sphere')
|
|
300
|
-
res['note'] += '; used_fallback_mesh'
|
|
301
|
-
|
|
302
|
-
if mesh:
|
|
303
|
-
res['used_mesh'] = str(mesh.get_path_name())
|
|
304
|
-
|
|
305
|
-
# Since HISM components and add_component don't work in this version,
|
|
306
|
-
# spawn individual StaticMeshActors for each instance
|
|
307
|
-
target_count = max(5, int(radius / 20.0))
|
|
308
|
-
added = 0
|
|
309
|
-
for i in range(target_count):
|
|
310
|
-
ang = random.random() * math.tau
|
|
311
|
-
r = random.random() * radius
|
|
312
|
-
x, y, z = px + math.cos(ang) * r, py + math.sin(ang) * r, pz
|
|
313
|
-
try:
|
|
314
|
-
# Spawn static mesh actor at position using modern subsystem
|
|
315
|
-
inst_actor = actor_subsystem.spawn_actor_from_class(
|
|
316
|
-
unreal.StaticMeshActor,
|
|
317
|
-
unreal.Vector(x, y, z),
|
|
318
|
-
unreal.Rotator(0, random.random()*360.0, 0)
|
|
319
|
-
)
|
|
320
|
-
if inst_actor and mesh:
|
|
321
|
-
# Set mesh on the actor's component
|
|
322
|
-
try:
|
|
323
|
-
mesh_comp = inst_actor.static_mesh_component
|
|
324
|
-
if mesh_comp:
|
|
325
|
-
mesh_comp.set_static_mesh(mesh)
|
|
326
|
-
inst_actor.set_actor_label(f"{foliage_type_name}_instance_{i}")
|
|
327
|
-
# Group under the container for organization
|
|
328
|
-
inst_actor.attach_to_actor(container, "", unreal.AttachmentRule.KEEP_WORLD, unreal.AttachmentRule.KEEP_WORLD, unreal.AttachmentRule.KEEP_WORLD, False)
|
|
329
|
-
added += 1
|
|
330
|
-
except Exception as e:
|
|
331
|
-
res['note'] += f"; instance_{i} setup failed: {e}"
|
|
332
|
-
except Exception as e:
|
|
333
|
-
res['note'] += f"; spawn instance_{i} failed: {e}"
|
|
334
|
-
|
|
335
|
-
res['added'] = added
|
|
336
|
-
res['actor'] = container.get_actor_label()
|
|
337
|
-
res['component'] = 'StaticMeshActors' # Using actors instead of components
|
|
338
|
-
res['success'] = True
|
|
339
|
-
except Exception as e:
|
|
340
|
-
res['success'] = False
|
|
341
|
-
res['note'] += f"; fatal: {e}"
|
|
342
|
-
|
|
343
|
-
print('RESULT:' + json.dumps(res))
|
|
344
|
-
`.trim();
|
|
345
|
-
const pyResp = await this.bridge.executePython(py);
|
|
346
|
-
const interpreted = interpretStandardResult(pyResp, {
|
|
347
|
-
successMessage: `Painted foliage for '${foliageType}'`,
|
|
348
|
-
failureMessage: 'Paint foliage failed'
|
|
349
|
-
});
|
|
350
|
-
if (!interpreted.success) {
|
|
110
|
+
if (!this.automationBridge) {
|
|
111
|
+
throw new Error('Automation Bridge not available. Foliage operations require plugin support.');
|
|
112
|
+
}
|
|
113
|
+
try {
|
|
114
|
+
const typePath = foliageType.includes('/') ? foliageType : `/Game/Foliage/${foliageType}.${foliageType}`;
|
|
115
|
+
const response = await this.automationBridge.sendAutomationRequest('paint_foliage', {
|
|
116
|
+
foliageTypePath: typePath,
|
|
117
|
+
locations: [{ x: pos[0], y: pos[1], z: pos[2] }],
|
|
118
|
+
brushSize: Number.isFinite(params.brushSize) ? params.brushSize : 300,
|
|
119
|
+
paintDensity: params.paintDensity,
|
|
120
|
+
eraseMode: params.eraseMode
|
|
121
|
+
}, {
|
|
122
|
+
timeoutMs: 60000
|
|
123
|
+
});
|
|
124
|
+
if (response.success === false) {
|
|
125
|
+
return {
|
|
126
|
+
success: false,
|
|
127
|
+
error: response.error || response.message || 'Paint foliage failed',
|
|
128
|
+
note: coerceString(response.result?.note)
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
const payload = response.result;
|
|
132
|
+
const added = coerceNumber(payload.instancesPlaced) ?? coerceNumber(payload?.count) ?? 0;
|
|
133
|
+
const note = coerceString(payload.note);
|
|
134
|
+
return {
|
|
135
|
+
success: true,
|
|
136
|
+
added,
|
|
137
|
+
note,
|
|
138
|
+
message: `Painted ${added} instances for '${foliageType}' around (${pos[0]}, ${pos[1]}, ${pos[2]})`
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
catch (error) {
|
|
351
142
|
return {
|
|
352
143
|
success: false,
|
|
353
|
-
error:
|
|
354
|
-
note: coerceString(interpreted.payload.note) ?? bestEffortInterpretedText(interpreted)
|
|
144
|
+
error: `Failed to paint foliage: ${error instanceof Error ? error.message : String(error)}`
|
|
355
145
|
};
|
|
356
146
|
}
|
|
357
|
-
const payload = interpreted.payload;
|
|
358
|
-
const added = coerceNumber(payload.added) ?? 0;
|
|
359
|
-
const actor = coerceString(payload.actor);
|
|
360
|
-
const component = coerceString(payload.component);
|
|
361
|
-
const usedMesh = coerceString(payload.used_mesh);
|
|
362
|
-
const note = coerceString(payload.note);
|
|
363
|
-
return {
|
|
364
|
-
success: true,
|
|
365
|
-
added,
|
|
366
|
-
actor,
|
|
367
|
-
component,
|
|
368
|
-
usedMesh,
|
|
369
|
-
note,
|
|
370
|
-
message: `Painted ${added} instances for '${foliageType}' around (${pos[0]}, ${pos[1]}, ${pos[2]})`
|
|
371
|
-
};
|
|
372
147
|
}
|
|
373
|
-
|
|
148
|
+
async getFoliageInstances(params) {
|
|
149
|
+
if (!this.automationBridge) {
|
|
150
|
+
throw new Error('Automation Bridge not available. Foliage operations require plugin support.');
|
|
151
|
+
}
|
|
152
|
+
try {
|
|
153
|
+
const typePath = params.foliageType ? (params.foliageType.includes('/') ? params.foliageType : `/Game/Foliage/${params.foliageType}.${params.foliageType}`) : undefined;
|
|
154
|
+
const response = await this.automationBridge.sendAutomationRequest('get_foliage_instances', {
|
|
155
|
+
foliageTypePath: typePath
|
|
156
|
+
}, { timeoutMs: 60000 });
|
|
157
|
+
if (response.success === false) {
|
|
158
|
+
return { success: false, error: response.error || response.message || 'Get foliage instances failed' };
|
|
159
|
+
}
|
|
160
|
+
const payload = response.result;
|
|
161
|
+
return {
|
|
162
|
+
success: true,
|
|
163
|
+
count: coerceNumber(payload.count) ?? 0,
|
|
164
|
+
instances: payload.instances ?? [],
|
|
165
|
+
message: 'Foliage instances retrieved'
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
catch (error) {
|
|
169
|
+
return { success: false, error: `Failed to get foliage instances: ${error instanceof Error ? error.message : String(error)}` };
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
async removeFoliage(params) {
|
|
173
|
+
if (!this.automationBridge) {
|
|
174
|
+
throw new Error('Automation Bridge not available. Foliage operations require plugin support.');
|
|
175
|
+
}
|
|
176
|
+
try {
|
|
177
|
+
const typePath = params.foliageType ? (params.foliageType.includes('/') ? params.foliageType : `/Game/Foliage/${params.foliageType}.${params.foliageType}`) : undefined;
|
|
178
|
+
const response = await this.automationBridge.sendAutomationRequest('remove_foliage', {
|
|
179
|
+
foliageTypePath: typePath,
|
|
180
|
+
removeAll: !!params.removeAll
|
|
181
|
+
}, { timeoutMs: 60000 });
|
|
182
|
+
if (response.success === false) {
|
|
183
|
+
return { success: false, error: response.error || response.message || 'Remove foliage failed' };
|
|
184
|
+
}
|
|
185
|
+
const payload = response.result;
|
|
186
|
+
return {
|
|
187
|
+
success: true,
|
|
188
|
+
instancesRemoved: coerceNumber(payload.instancesRemoved) ?? 0,
|
|
189
|
+
message: 'Foliage removed'
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
catch (error) {
|
|
193
|
+
return { success: false, error: `Failed to remove foliage: ${error instanceof Error ? error.message : String(error)}` };
|
|
194
|
+
}
|
|
195
|
+
}
|
|
374
196
|
async createInstancedMesh(params) {
|
|
375
197
|
const commands = [];
|
|
376
198
|
commands.push(`CreateInstancedStaticMesh ${params.name} ${params.meshPath}`);
|
|
@@ -388,7 +210,6 @@ print('RESULT:' + json.dumps(res))
|
|
|
388
210
|
await this.bridge.executeConsoleCommands(commands);
|
|
389
211
|
return { success: true, message: `Instanced mesh ${params.name} created with ${params.instances.length} instances` };
|
|
390
212
|
}
|
|
391
|
-
// Set foliage LOD
|
|
392
213
|
async setFoliageLOD(params) {
|
|
393
214
|
const commands = [];
|
|
394
215
|
if (params.lodDistances) {
|
|
@@ -400,24 +221,99 @@ print('RESULT:' + json.dumps(res))
|
|
|
400
221
|
await this.bridge.executeConsoleCommands(commands);
|
|
401
222
|
return { success: true, message: 'Foliage LOD settings updated' };
|
|
402
223
|
}
|
|
403
|
-
|
|
224
|
+
async addFoliage(params) {
|
|
225
|
+
if (params.locations && params.locations.length > 0) {
|
|
226
|
+
if (!this.automationBridge) {
|
|
227
|
+
throw new Error('Automation Bridge not available.');
|
|
228
|
+
}
|
|
229
|
+
const response = await this.automationBridge.sendAutomationRequest('paint_foliage', {
|
|
230
|
+
foliageTypePath: params.foliageType.includes('/') ? params.foliageType : `/Game/Foliage/${params.foliageType}.${params.foliageType}`,
|
|
231
|
+
locations: params.locations,
|
|
232
|
+
brushSize: 0,
|
|
233
|
+
paintDensity: 1,
|
|
234
|
+
eraseMode: false
|
|
235
|
+
});
|
|
236
|
+
if (!response.success) {
|
|
237
|
+
return { success: false, error: response.error || 'Failed to add foliage instances' };
|
|
238
|
+
}
|
|
239
|
+
return { success: true, message: `Added ${params.locations.length} foliage instances` };
|
|
240
|
+
}
|
|
241
|
+
return { success: true, message: 'No locations provided for addFoliage' };
|
|
242
|
+
}
|
|
404
243
|
async createProceduralFoliage(params) {
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
244
|
+
if (!this.automationBridge) {
|
|
245
|
+
throw new Error('Automation Bridge not available.');
|
|
246
|
+
}
|
|
247
|
+
const volName = params.volumeName || params.name || 'ProceduralFoliageVolume';
|
|
248
|
+
const loc = params.bounds?.location ? [params.bounds.location.x, params.bounds.location.y, params.bounds.location.z] : (params.position || [0, 0, 0]);
|
|
249
|
+
const size = params.bounds?.size ? [params.bounds.size.x, params.bounds.size.y, params.bounds.size.z] : (params.size || [1000, 1000, 100]);
|
|
250
|
+
const foliageTypes = Array.isArray(params.foliageTypes)
|
|
251
|
+
? params.foliageTypes.map(t => {
|
|
252
|
+
if (typeof t === 'string')
|
|
253
|
+
return { meshPath: t, density: 0.5 };
|
|
254
|
+
return t;
|
|
255
|
+
})
|
|
256
|
+
: [];
|
|
257
|
+
const payload = {
|
|
258
|
+
name: volName,
|
|
259
|
+
bounds: {
|
|
260
|
+
location: { x: loc[0], y: loc[1], z: loc[2] },
|
|
261
|
+
size: { x: size[0], y: size[1], z: size[2] }
|
|
262
|
+
},
|
|
263
|
+
foliageTypes,
|
|
264
|
+
seed: params.seed ?? 42,
|
|
265
|
+
tileSize: params.tileSize ?? 1000
|
|
266
|
+
};
|
|
267
|
+
const response = await this.automationBridge.sendAutomationRequest('create_procedural_foliage', payload);
|
|
268
|
+
if (!response.success) {
|
|
269
|
+
return {
|
|
270
|
+
success: false,
|
|
271
|
+
error: response.error || 'Failed to create procedural foliage'
|
|
272
|
+
};
|
|
409
273
|
}
|
|
410
|
-
|
|
411
|
-
|
|
274
|
+
const result = response.result;
|
|
275
|
+
return {
|
|
276
|
+
success: true,
|
|
277
|
+
message: `Procedural foliage volume ${volName} created`,
|
|
278
|
+
details: response,
|
|
279
|
+
volumeActor: result?.volume_actor,
|
|
280
|
+
spawnerPath: result?.spawner_path,
|
|
281
|
+
foliageTypesCount: result?.foliage_types_count
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
async addFoliageInstances(params) {
|
|
285
|
+
if (!this.automationBridge) {
|
|
286
|
+
throw new Error('Automation Bridge not available. Foliage instance placement requires plugin support.');
|
|
287
|
+
}
|
|
288
|
+
try {
|
|
289
|
+
const typePath = params.foliageType.includes('/') ? params.foliageType : `/Game/Foliage/${params.foliageType}.${params.foliageType}`;
|
|
290
|
+
const response = await this.automationBridge.sendAutomationRequest('add_foliage_instances', {
|
|
291
|
+
foliageType: typePath,
|
|
292
|
+
transforms: params.transforms
|
|
293
|
+
}, {
|
|
294
|
+
timeoutMs: 120000
|
|
295
|
+
});
|
|
296
|
+
if (response.success === false) {
|
|
297
|
+
return {
|
|
298
|
+
success: false,
|
|
299
|
+
error: response.error || response.message || 'Failed to add foliage instances',
|
|
300
|
+
message: response.message || 'Failed to add foliage instances'
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
const result = response.result;
|
|
304
|
+
return {
|
|
305
|
+
success: true,
|
|
306
|
+
message: response.message || `Added ${result?.instances_count || params.transforms.length} foliage instances`,
|
|
307
|
+
instancesCount: result?.instances_count
|
|
308
|
+
};
|
|
412
309
|
}
|
|
413
|
-
|
|
414
|
-
|
|
310
|
+
catch (error) {
|
|
311
|
+
return {
|
|
312
|
+
success: false,
|
|
313
|
+
error: `Failed to add foliage instances: ${error instanceof Error ? error.message : String(error)}`
|
|
314
|
+
};
|
|
415
315
|
}
|
|
416
|
-
commands.push(`GenerateProceduralFoliage ${params.volumeName}`);
|
|
417
|
-
await this.bridge.executeConsoleCommands(commands);
|
|
418
|
-
return { success: true, message: `Procedural foliage volume ${params.volumeName} created` };
|
|
419
316
|
}
|
|
420
|
-
// Set foliage collision
|
|
421
317
|
async setFoliageCollision(params) {
|
|
422
318
|
const commands = [];
|
|
423
319
|
if (params.collisionEnabled !== undefined) {
|
|
@@ -432,7 +328,6 @@ print('RESULT:' + json.dumps(res))
|
|
|
432
328
|
await this.bridge.executeConsoleCommands(commands);
|
|
433
329
|
return { success: true, message: 'Foliage collision settings updated' };
|
|
434
330
|
}
|
|
435
|
-
// Create grass system
|
|
436
331
|
async createGrassSystem(params) {
|
|
437
332
|
const commands = [];
|
|
438
333
|
commands.push(`CreateGrassSystem ${params.name}`);
|
|
@@ -450,12 +345,10 @@ print('RESULT:' + json.dumps(res))
|
|
|
450
345
|
await this.bridge.executeConsoleCommands(commands);
|
|
451
346
|
return { success: true, message: `Grass system ${params.name} created` };
|
|
452
347
|
}
|
|
453
|
-
// Remove foliage instances
|
|
454
348
|
async removeFoliageInstances(params) {
|
|
455
349
|
const command = `RemoveFoliageInRadius ${params.foliageType} ${params.position.join(' ')} ${params.radius}`;
|
|
456
350
|
return this.bridge.executeConsoleCommand(command);
|
|
457
351
|
}
|
|
458
|
-
// Select foliage instances
|
|
459
352
|
async selectFoliageInstances(params) {
|
|
460
353
|
let command;
|
|
461
354
|
if (params.selectAll) {
|
|
@@ -469,7 +362,6 @@ print('RESULT:' + json.dumps(res))
|
|
|
469
362
|
}
|
|
470
363
|
return this.bridge.executeConsoleCommand(command);
|
|
471
364
|
}
|
|
472
|
-
// Update foliage instances
|
|
473
365
|
async updateFoliageInstances(params) {
|
|
474
366
|
const commands = [];
|
|
475
367
|
if (params.updateTransforms) {
|
|
@@ -482,7 +374,6 @@ print('RESULT:' + json.dumps(res))
|
|
|
482
374
|
await this.bridge.executeConsoleCommands(commands);
|
|
483
375
|
return { success: true, message: 'Foliage instances updated' };
|
|
484
376
|
}
|
|
485
|
-
// Create foliage spawner
|
|
486
377
|
async createFoliageSpawner(params) {
|
|
487
378
|
const commands = [];
|
|
488
379
|
commands.push(`CreateFoliageSpawner ${params.name} ${params.spawnArea}`);
|
|
@@ -494,7 +385,6 @@ print('RESULT:' + json.dumps(res))
|
|
|
494
385
|
await this.bridge.executeConsoleCommands(commands);
|
|
495
386
|
return { success: true, message: `Foliage spawner ${params.name} created` };
|
|
496
387
|
}
|
|
497
|
-
// Optimize foliage
|
|
498
388
|
async optimizeFoliage(params) {
|
|
499
389
|
const commands = [];
|
|
500
390
|
if (params.mergeInstances) {
|