unreal-engine-mcp-server 0.4.7 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +26 -0
- package/.env.production +38 -7
- package/.eslintrc.json +0 -54
- package/.eslintrc.override.json +8 -0
- package/.github/ISSUE_TEMPLATE/bug_report.yml +94 -0
- package/.github/ISSUE_TEMPLATE/config.yml +8 -0
- package/.github/ISSUE_TEMPLATE/feature_request.yml +56 -0
- package/.github/copilot-instructions.md +478 -45
- package/.github/dependabot.yml +19 -0
- package/.github/labeler.yml +24 -0
- package/.github/labels.yml +70 -0
- package/.github/pull_request_template.md +42 -0
- package/.github/release-drafter.yml +148 -0
- package/.github/workflows/auto-merge.yml +38 -0
- package/.github/workflows/ci.yml +38 -0
- package/.github/workflows/dependency-review.yml +17 -0
- package/.github/workflows/gemini-issue-triage.yml +172 -0
- package/.github/workflows/greetings.yml +23 -0
- package/.github/workflows/labeler.yml +16 -0
- package/.github/workflows/links.yml +80 -0
- package/.github/workflows/pr-size-labeler.yml +137 -0
- package/.github/workflows/publish-mcp.yml +12 -7
- package/.github/workflows/release-drafter.yml +23 -0
- package/.github/workflows/release.yml +112 -0
- package/.github/workflows/semantic-pull-request.yml +35 -0
- package/.github/workflows/smoke-test.yml +36 -0
- package/.github/workflows/stale.yml +28 -0
- package/CHANGELOG.md +267 -31
- package/CONTRIBUTING.md +140 -0
- package/README.md +166 -71
- package/claude_desktop_config_example.json +7 -6
- package/dist/automation/bridge.d.ts +50 -0
- package/dist/automation/bridge.js +452 -0
- package/dist/automation/connection-manager.d.ts +23 -0
- package/dist/automation/connection-manager.js +107 -0
- package/dist/automation/handshake.d.ts +11 -0
- package/dist/automation/handshake.js +89 -0
- package/dist/automation/index.d.ts +3 -0
- package/dist/automation/index.js +3 -0
- package/dist/automation/message-handler.d.ts +12 -0
- package/dist/automation/message-handler.js +149 -0
- package/dist/automation/request-tracker.d.ts +25 -0
- package/dist/automation/request-tracker.js +98 -0
- package/dist/automation/types.d.ts +130 -0
- package/dist/automation/types.js +2 -0
- package/dist/cli.js +32 -5
- package/dist/config.d.ts +27 -0
- package/dist/config.js +60 -0
- package/dist/constants.d.ts +12 -0
- package/dist/constants.js +12 -0
- package/dist/graphql/resolvers.d.ts +268 -0
- package/dist/graphql/resolvers.js +743 -0
- package/dist/graphql/schema.d.ts +5 -0
- package/dist/graphql/schema.js +437 -0
- package/dist/graphql/server.d.ts +26 -0
- package/dist/graphql/server.js +115 -0
- package/dist/graphql/types.d.ts +7 -0
- package/dist/graphql/types.js +2 -0
- package/dist/handlers/resource-handlers.d.ts +20 -0
- package/dist/handlers/resource-handlers.js +180 -0
- package/dist/index.d.ts +31 -18
- package/dist/index.js +119 -619
- package/dist/prompts/index.js +4 -4
- package/dist/resources/actors.d.ts +17 -12
- package/dist/resources/actors.js +56 -76
- package/dist/resources/assets.d.ts +6 -14
- package/dist/resources/assets.js +115 -147
- package/dist/resources/levels.d.ts +13 -13
- package/dist/resources/levels.js +25 -34
- package/dist/server/resource-registry.d.ts +20 -0
- package/dist/server/resource-registry.js +37 -0
- package/dist/server/tool-registry.d.ts +23 -0
- package/dist/server/tool-registry.js +322 -0
- package/dist/server-setup.d.ts +21 -0
- package/dist/server-setup.js +111 -0
- package/dist/services/health-monitor.d.ts +34 -0
- package/dist/services/health-monitor.js +105 -0
- package/dist/services/metrics-server.d.ts +11 -0
- package/dist/services/metrics-server.js +105 -0
- package/dist/tools/actors.d.ts +147 -9
- package/dist/tools/actors.js +350 -311
- package/dist/tools/animation.d.ts +135 -4
- package/dist/tools/animation.js +510 -411
- package/dist/tools/assets.d.ts +117 -19
- package/dist/tools/assets.js +259 -284
- package/dist/tools/audio.d.ts +102 -42
- package/dist/tools/audio.js +272 -685
- package/dist/tools/base-tool.d.ts +17 -0
- package/dist/tools/base-tool.js +46 -0
- package/dist/tools/behavior-tree.d.ts +94 -0
- package/dist/tools/behavior-tree.js +39 -0
- package/dist/tools/blueprint/helpers.d.ts +29 -0
- package/dist/tools/blueprint/helpers.js +182 -0
- package/dist/tools/blueprint.d.ts +228 -118
- package/dist/tools/blueprint.js +685 -832
- package/dist/tools/consolidated-tool-definitions.d.ts +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 +211 -1026
- package/dist/tools/debug.d.ts +143 -85
- package/dist/tools/debug.js +234 -180
- package/dist/tools/dynamic-handler-registry.d.ts +11 -0
- package/dist/tools/dynamic-handler-registry.js +101 -0
- package/dist/tools/editor.d.ts +139 -18
- package/dist/tools/editor.js +239 -244
- package/dist/tools/engine.d.ts +10 -4
- package/dist/tools/engine.js +13 -5
- package/dist/tools/environment.d.ts +36 -0
- package/dist/tools/environment.js +267 -0
- package/dist/tools/foliage.d.ts +105 -14
- package/dist/tools/foliage.js +219 -331
- package/dist/tools/handlers/actor-handlers.d.ts +3 -0
- package/dist/tools/handlers/actor-handlers.js +232 -0
- package/dist/tools/handlers/animation-handlers.d.ts +3 -0
- package/dist/tools/handlers/animation-handlers.js +185 -0
- package/dist/tools/handlers/argument-helper.d.ts +16 -0
- package/dist/tools/handlers/argument-helper.js +80 -0
- package/dist/tools/handlers/asset-handlers.d.ts +3 -0
- package/dist/tools/handlers/asset-handlers.js +496 -0
- package/dist/tools/handlers/audio-handlers.d.ts +3 -0
- package/dist/tools/handlers/audio-handlers.js +166 -0
- package/dist/tools/handlers/blueprint-handlers.d.ts +4 -0
- package/dist/tools/handlers/blueprint-handlers.js +358 -0
- package/dist/tools/handlers/common-handlers.d.ts +14 -0
- package/dist/tools/handlers/common-handlers.js +56 -0
- package/dist/tools/handlers/editor-handlers.d.ts +3 -0
- package/dist/tools/handlers/editor-handlers.js +119 -0
- package/dist/tools/handlers/effect-handlers.d.ts +3 -0
- package/dist/tools/handlers/effect-handlers.js +171 -0
- package/dist/tools/handlers/environment-handlers.d.ts +3 -0
- package/dist/tools/handlers/environment-handlers.js +170 -0
- package/dist/tools/handlers/graph-handlers.d.ts +3 -0
- package/dist/tools/handlers/graph-handlers.js +90 -0
- package/dist/tools/handlers/input-handlers.d.ts +3 -0
- package/dist/tools/handlers/input-handlers.js +21 -0
- package/dist/tools/handlers/inspect-handlers.d.ts +3 -0
- package/dist/tools/handlers/inspect-handlers.js +383 -0
- package/dist/tools/handlers/level-handlers.d.ts +3 -0
- package/dist/tools/handlers/level-handlers.js +237 -0
- package/dist/tools/handlers/lighting-handlers.d.ts +3 -0
- package/dist/tools/handlers/lighting-handlers.js +144 -0
- package/dist/tools/handlers/performance-handlers.d.ts +3 -0
- package/dist/tools/handlers/performance-handlers.js +130 -0
- package/dist/tools/handlers/pipeline-handlers.d.ts +3 -0
- package/dist/tools/handlers/pipeline-handlers.js +110 -0
- package/dist/tools/handlers/sequence-handlers.d.ts +3 -0
- package/dist/tools/handlers/sequence-handlers.js +376 -0
- package/dist/tools/handlers/system-handlers.d.ts +4 -0
- package/dist/tools/handlers/system-handlers.js +506 -0
- package/dist/tools/input.d.ts +19 -0
- package/dist/tools/input.js +89 -0
- package/dist/tools/introspection.d.ts +103 -40
- package/dist/tools/introspection.js +425 -568
- package/dist/tools/landscape.d.ts +97 -36
- package/dist/tools/landscape.js +280 -409
- package/dist/tools/level.d.ts +130 -10
- package/dist/tools/level.js +639 -675
- package/dist/tools/lighting.d.ts +77 -38
- package/dist/tools/lighting.js +441 -943
- package/dist/tools/logs.d.ts +3 -3
- package/dist/tools/logs.js +5 -57
- package/dist/tools/materials.d.ts +91 -24
- package/dist/tools/materials.js +190 -118
- package/dist/tools/niagara.d.ts +149 -39
- package/dist/tools/niagara.js +232 -182
- package/dist/tools/performance.d.ts +27 -12
- package/dist/tools/performance.js +204 -122
- package/dist/tools/physics.d.ts +32 -77
- package/dist/tools/physics.js +171 -582
- package/dist/tools/property-dictionary.d.ts +13 -0
- package/dist/tools/property-dictionary.js +82 -0
- package/dist/tools/sequence.d.ts +73 -48
- package/dist/tools/sequence.js +196 -748
- package/dist/tools/tool-definition-utils.d.ts +59 -0
- package/dist/tools/tool-definition-utils.js +35 -0
- package/dist/tools/ui.d.ts +66 -34
- package/dist/tools/ui.js +134 -214
- package/dist/types/env.d.ts +0 -3
- package/dist/types/env.js +0 -7
- package/dist/types/tool-interfaces.d.ts +898 -0
- package/dist/types/tool-interfaces.js +2 -0
- package/dist/types/tool-types.d.ts +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 +67 -0
- package/dist/utils/elicitation.d.ts +1 -1
- package/dist/utils/elicitation.js +12 -15
- package/dist/utils/error-handler.d.ts +2 -51
- package/dist/utils/error-handler.js +11 -87
- package/dist/utils/ini-reader.d.ts +3 -0
- package/dist/utils/ini-reader.js +69 -0
- package/dist/utils/logger.js +9 -6
- package/dist/utils/normalize.d.ts +3 -0
- package/dist/utils/normalize.js +56 -0
- package/dist/utils/response-factory.d.ts +7 -0
- package/dist/utils/response-factory.js +33 -0
- package/dist/utils/response-validator.d.ts +3 -24
- package/dist/utils/response-validator.js +130 -81
- package/dist/utils/result-helpers.d.ts +4 -5
- package/dist/utils/result-helpers.js +15 -16
- package/dist/utils/safe-json.js +5 -11
- package/dist/utils/unreal-command-queue.d.ts +24 -0
- package/dist/utils/unreal-command-queue.js +120 -0
- package/dist/utils/validation.d.ts +0 -40
- package/dist/utils/validation.js +1 -78
- package/dist/wasm/index.d.ts +70 -0
- package/dist/wasm/index.js +535 -0
- package/docs/GraphQL-API.md +888 -0
- package/docs/Migration-Guide-v0.5.0.md +692 -0
- package/docs/Roadmap.md +53 -0
- package/docs/WebAssembly-Integration.md +628 -0
- package/docs/editor-plugin-extension.md +370 -0
- package/docs/handler-mapping.md +242 -0
- package/docs/native-automation-progress.md +128 -0
- package/docs/testing-guide.md +423 -0
- package/mcp-config-example.json +6 -6
- package/package.json +60 -27
- package/plugins/McpAutomationBridge/Config/FilterPlugin.ini +8 -0
- package/plugins/McpAutomationBridge/McpAutomationBridge.uplugin +64 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/McpAutomationBridge.Build.cs +189 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridgeGlobals.cpp +22 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridgeGlobals.h +30 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridgeHelpers.h +1983 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridgeModule.cpp +72 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridgeSettings.cpp +46 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridgeSubsystem.cpp +581 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_AnimationHandlers.cpp +2394 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_AssetQueryHandlers.cpp +300 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_AssetWorkflowHandlers.cpp +2807 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_AudioHandlers.cpp +1087 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_BehaviorTreeHandlers.cpp +488 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_BlueprintCreationHandlers.cpp +643 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_BlueprintCreationHandlers.h +31 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_BlueprintGraphHandlers.cpp +1184 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_BlueprintHandlers.cpp +5652 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_BlueprintHandlers_List.cpp +152 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_ControlHandlers.cpp +2614 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_DebugHandlers.cpp +42 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_EditorFunctionHandlers.cpp +1237 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_EffectHandlers.cpp +1701 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_EnvironmentHandlers.cpp +2145 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_FoliageHandlers.cpp +954 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_InputHandlers.cpp +209 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_InsightsHandlers.cpp +41 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_LandscapeHandlers.cpp +1164 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_LevelHandlers.cpp +762 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_LightingHandlers.cpp +634 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_LogHandlers.cpp +136 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_MaterialGraphHandlers.cpp +494 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_NiagaraGraphHandlers.cpp +278 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_NiagaraHandlers.cpp +625 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_PerformanceHandlers.cpp +401 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_PipelineHandlers.cpp +67 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_ProcessRequest.cpp +735 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_PropertyHandlers.cpp +2634 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_RenderHandlers.cpp +189 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_SCSHandlers.cpp +917 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_SCSHandlers.h +39 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_SequenceHandlers.cpp +2670 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_SequencerHandlers.cpp +519 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_TestHandlers.cpp +38 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_UiHandlers.cpp +668 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_WorldPartitionHandlers.cpp +346 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpBridgeWebSocket.cpp +1330 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpBridgeWebSocket.h +149 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpConnectionManager.cpp +783 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Public/McpAutomationBridgeSettings.h +115 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Public/McpAutomationBridgeSubsystem.h +796 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Public/McpConnectionManager.h +117 -0
- package/scripts/check-unreal-connection.mjs +19 -0
- package/scripts/clean-tmp.js +23 -0
- package/scripts/patch-wasm.js +26 -0
- package/scripts/run-all-tests.mjs +131 -0
- package/scripts/smoke-test.ts +94 -0
- package/scripts/sync-mcp-plugin.js +143 -0
- package/scripts/test-no-plugin-alternates.mjs +113 -0
- package/scripts/validate-server.js +46 -0
- package/scripts/verify-automation-bridge.js +200 -0
- package/server.json +57 -21
- package/src/automation/bridge.ts +558 -0
- package/src/automation/connection-manager.ts +130 -0
- package/src/automation/handshake.ts +99 -0
- package/src/automation/index.ts +2 -0
- package/src/automation/message-handler.ts +167 -0
- package/src/automation/request-tracker.ts +123 -0
- package/src/automation/types.ts +107 -0
- package/src/cli.ts +33 -6
- package/src/config.ts +73 -0
- package/src/constants.ts +12 -0
- package/src/graphql/resolvers.ts +1010 -0
- package/src/graphql/schema.ts +452 -0
- package/src/graphql/server.ts +154 -0
- package/src/graphql/types.ts +7 -0
- package/src/handlers/resource-handlers.ts +186 -0
- package/src/index.ts +152 -663
- package/src/prompts/index.ts +4 -4
- package/src/resources/actors.ts +58 -76
- package/src/resources/assets.ts +147 -134
- package/src/resources/levels.ts +28 -33
- package/src/server/resource-registry.ts +47 -0
- package/src/server/tool-registry.ts +354 -0
- package/src/server-setup.ts +148 -0
- package/src/services/health-monitor.ts +132 -0
- package/src/services/metrics-server.ts +142 -0
- package/src/tools/actors.ts +417 -322
- package/src/tools/animation.ts +671 -461
- package/src/tools/assets.ts +353 -289
- package/src/tools/audio.ts +323 -766
- package/src/tools/base-tool.ts +52 -0
- package/src/tools/behavior-tree.ts +45 -0
- package/src/tools/blueprint/helpers.ts +189 -0
- package/src/tools/blueprint.ts +787 -965
- package/src/tools/consolidated-tool-definitions.ts +993 -515
- package/src/tools/consolidated-tool-handlers.ts +272 -1139
- package/src/tools/debug.ts +292 -187
- package/src/tools/dynamic-handler-registry.ts +151 -0
- package/src/tools/editor.ts +309 -246
- package/src/tools/engine.ts +14 -3
- package/src/tools/environment.ts +287 -0
- package/src/tools/foliage.ts +314 -379
- package/src/tools/handlers/actor-handlers.ts +271 -0
- package/src/tools/handlers/animation-handlers.ts +237 -0
- package/src/tools/handlers/argument-helper.ts +142 -0
- package/src/tools/handlers/asset-handlers.ts +532 -0
- package/src/tools/handlers/audio-handlers.ts +194 -0
- package/src/tools/handlers/blueprint-handlers.ts +380 -0
- package/src/tools/handlers/common-handlers.ts +87 -0
- package/src/tools/handlers/editor-handlers.ts +123 -0
- package/src/tools/handlers/effect-handlers.ts +220 -0
- package/src/tools/handlers/environment-handlers.ts +183 -0
- package/src/tools/handlers/graph-handlers.ts +116 -0
- package/src/tools/handlers/input-handlers.ts +28 -0
- package/src/tools/handlers/inspect-handlers.ts +450 -0
- package/src/tools/handlers/level-handlers.ts +252 -0
- package/src/tools/handlers/lighting-handlers.ts +147 -0
- package/src/tools/handlers/performance-handlers.ts +132 -0
- package/src/tools/handlers/pipeline-handlers.ts +127 -0
- package/src/tools/handlers/sequence-handlers.ts +415 -0
- package/src/tools/handlers/system-handlers.ts +564 -0
- package/src/tools/input.ts +101 -0
- package/src/tools/introspection.ts +493 -584
- package/src/tools/landscape.ts +394 -489
- package/src/tools/level.ts +752 -694
- package/src/tools/lighting.ts +583 -984
- package/src/tools/logs.ts +9 -57
- package/src/tools/materials.ts +231 -121
- package/src/tools/niagara.ts +293 -168
- package/src/tools/performance.ts +320 -168
- package/src/tools/physics.ts +268 -613
- package/src/tools/property-dictionary.ts +98 -0
- package/src/tools/sequence.ts +255 -815
- package/src/tools/tool-definition-utils.ts +35 -0
- package/src/tools/ui.ts +207 -283
- package/src/types/env.ts +0 -10
- package/src/types/tool-interfaces.ts +250 -0
- package/src/types/tool-types.ts +243 -21
- package/src/unreal-bridge.ts +460 -1550
- package/src/utils/command-validator.ts +75 -0
- package/src/utils/elicitation.ts +10 -7
- package/src/utils/error-handler.ts +14 -90
- package/src/utils/ini-reader.ts +86 -0
- package/src/utils/logger.ts +8 -3
- package/src/utils/normalize.ts +60 -0
- package/src/utils/response-factory.ts +39 -0
- package/src/utils/response-validator.ts +176 -56
- package/src/utils/result-helpers.ts +21 -19
- package/src/utils/safe-json.ts +14 -11
- package/src/utils/unreal-command-queue.ts +152 -0
- package/src/utils/validation.ts +4 -1
- package/src/wasm/index.ts +838 -0
- package/test-server.mjs +100 -0
- package/tests/run-unreal-tool-tests.mjs +242 -14
- package/tests/test-animation.mjs +44 -0
- package/tests/test-asset-advanced.mjs +82 -0
- package/tests/test-asset-errors.mjs +35 -0
- package/tests/test-audio.mjs +219 -0
- package/tests/test-automation-timeouts.mjs +98 -0
- package/tests/test-behavior-tree.mjs +261 -0
- package/tests/test-blueprint-events.mjs +35 -0
- package/tests/test-blueprint-graph.mjs +79 -0
- package/tests/test-blueprint.mjs +577 -0
- package/tests/test-client-mode.mjs +86 -0
- package/tests/test-console-command.mjs +56 -0
- package/tests/test-control-actor.mjs +425 -0
- package/tests/test-control-editor.mjs +80 -0
- package/tests/test-extra-tools.mjs +38 -0
- package/tests/test-graphql.mjs +322 -0
- package/tests/test-inspect.mjs +72 -0
- package/tests/test-landscape.mjs +60 -0
- package/tests/test-manage-asset.mjs +438 -0
- package/tests/test-manage-level.mjs +70 -0
- package/tests/test-materials.mjs +356 -0
- package/tests/test-niagara.mjs +185 -0
- package/tests/test-no-inline-python.mjs +122 -0
- package/tests/test-plugin-handshake.mjs +82 -0
- package/tests/test-render.mjs +33 -0
- package/tests/test-runner.mjs +933 -0
- package/tests/test-search-assets.mjs +66 -0
- package/tests/test-sequence.mjs +68 -0
- package/tests/test-system.mjs +57 -0
- package/tests/test-wasm.mjs +193 -0
- package/tests/test-world-partition.mjs +215 -0
- package/tsconfig.json +3 -3
- package/wasm/Cargo.lock +363 -0
- package/wasm/Cargo.toml +42 -0
- package/wasm/LICENSE +21 -0
- package/wasm/README.md +253 -0
- package/wasm/src/dependency_resolver.rs +377 -0
- package/wasm/src/lib.rs +153 -0
- package/wasm/src/property_parser.rs +271 -0
- package/wasm/src/transform_math.rs +396 -0
- package/wasm/tests/integration.rs +109 -0
- package/.github/workflows/smithery-build.yml +0 -29
- package/dist/tools/build_environment_advanced.d.ts +0 -65
- package/dist/tools/build_environment_advanced.js +0 -633
- package/dist/tools/rc.d.ts +0 -110
- package/dist/tools/rc.js +0 -437
- package/dist/tools/visual.d.ts +0 -40
- package/dist/tools/visual.js +0 -282
- package/dist/utils/http.d.ts +0 -6
- package/dist/utils/http.js +0 -151
- package/dist/utils/python-output.d.ts +0 -18
- package/dist/utils/python-output.js +0 -290
- package/dist/utils/python.d.ts +0 -2
- package/dist/utils/python.js +0 -4
- package/dist/utils/stdio-redirect.d.ts +0 -2
- package/dist/utils/stdio-redirect.js +0 -20
- package/docs/unreal-tool-test-cases.md +0 -574
- package/smithery.yaml +0 -29
- package/src/tools/build_environment_advanced.ts +0 -732
- package/src/tools/rc.ts +0 -515
- package/src/tools/visual.ts +0 -281
- package/src/utils/http.ts +0 -187
- package/src/utils/python-output.ts +0 -351
- package/src/utils/python.ts +0 -3
- package/src/utils/stdio-redirect.ts +0 -18
|
@@ -0,0 +1,643 @@
|
|
|
1
|
+
#include "McpAutomationBridge_BlueprintCreationHandlers.h"
|
|
2
|
+
#include "HAL/PlatformTime.h"
|
|
3
|
+
#include "McpAutomationBridgeGlobals.h"
|
|
4
|
+
#include "McpAutomationBridgeHelpers.h"
|
|
5
|
+
#include "McpAutomationBridgeSubsystem.h"
|
|
6
|
+
#include "Misc/ScopeExit.h"
|
|
7
|
+
#include "Misc/ScopeLock.h"
|
|
8
|
+
|
|
9
|
+
#if WITH_EDITOR
|
|
10
|
+
#include "AssetRegistry/AssetRegistryModule.h"
|
|
11
|
+
#include "AssetToolsModule.h"
|
|
12
|
+
#include "Components/ActorComponent.h"
|
|
13
|
+
#include "Components/StaticMeshComponent.h"
|
|
14
|
+
#include "EditorAssetLibrary.h"
|
|
15
|
+
#include "Engine/SCS_Node.h"
|
|
16
|
+
#include "Engine/SimpleConstructionScript.h"
|
|
17
|
+
#include "Factories/BlueprintFactory.h"
|
|
18
|
+
#include "GameFramework/Actor.h"
|
|
19
|
+
#include "GameFramework/Character.h"
|
|
20
|
+
#include "GameFramework/Pawn.h"
|
|
21
|
+
#include "Kismet2/BlueprintEditorUtils.h"
|
|
22
|
+
#include "Kismet2/KismetEditorUtilities.h"
|
|
23
|
+
#include "UObject/UObjectIterator.h"
|
|
24
|
+
#include "UObject/UnrealType.h"
|
|
25
|
+
|
|
26
|
+
// Respect build-rule's PublicDefinitions: if the build rule set
|
|
27
|
+
// MCP_HAS_SUBOBJECT_DATA_SUBSYSTEM=1 then include the subsystem headers.
|
|
28
|
+
#if defined(MCP_HAS_SUBOBJECT_DATA_SUBSYSTEM) && \
|
|
29
|
+
(MCP_HAS_SUBOBJECT_DATA_SUBSYSTEM == 1)
|
|
30
|
+
#if defined(__has_include)
|
|
31
|
+
#if __has_include("Subsystems/SubobjectDataSubsystem.h")
|
|
32
|
+
#include "Subsystems/SubobjectDataSubsystem.h"
|
|
33
|
+
#elif __has_include("SubobjectDataSubsystem.h")
|
|
34
|
+
#include "SubobjectDataSubsystem.h"
|
|
35
|
+
#elif __has_include("SubobjectData/SubobjectDataSubsystem.h")
|
|
36
|
+
#include "SubobjectData/SubobjectDataSubsystem.h"
|
|
37
|
+
#endif
|
|
38
|
+
#else
|
|
39
|
+
#include "SubobjectDataSubsystem.h"
|
|
40
|
+
#endif
|
|
41
|
+
#elif !defined(MCP_HAS_SUBOBJECT_DATA_SUBSYSTEM)
|
|
42
|
+
// If the build-rule did not define the macro, perform header probing here
|
|
43
|
+
// to discover whether the engine exposes SubobjectData headers.
|
|
44
|
+
#if defined(__has_include)
|
|
45
|
+
#if __has_include("Subsystems/SubobjectDataSubsystem.h")
|
|
46
|
+
#include "Subsystems/SubobjectDataSubsystem.h"
|
|
47
|
+
#define MCP_HAS_SUBOBJECT_DATA_SUBSYSTEM 1
|
|
48
|
+
#elif __has_include("SubobjectDataSubsystem.h")
|
|
49
|
+
#include "SubobjectDataSubsystem.h"
|
|
50
|
+
#define MCP_HAS_SUBOBJECT_DATA_SUBSYSTEM 1
|
|
51
|
+
#elif __has_include("SubobjectData/SubobjectDataSubsystem.h")
|
|
52
|
+
#include "SubobjectData/SubobjectDataSubsystem.h"
|
|
53
|
+
#define MCP_HAS_SUBOBJECT_DATA_SUBSYSTEM 1
|
|
54
|
+
#else
|
|
55
|
+
#define MCP_HAS_SUBOBJECT_DATA_SUBSYSTEM 0
|
|
56
|
+
#endif
|
|
57
|
+
#else
|
|
58
|
+
#define MCP_HAS_SUBOBJECT_DATA_SUBSYSTEM 0
|
|
59
|
+
#endif
|
|
60
|
+
#else
|
|
61
|
+
#define MCP_HAS_SUBOBJECT_DATA_SUBSYSTEM 0
|
|
62
|
+
#endif
|
|
63
|
+
|
|
64
|
+
#endif // WITH_EDITOR
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* @brief Probes subobject handles for a temporary blueprint and returns gathered handles to the requester.
|
|
68
|
+
*
|
|
69
|
+
* Creates a temporary probe Blueprint, attempts to gather subobject handles via the SubobjectDataSubsystem when available, and falls back to enumerating SimpleConstructionScript nodes when the subsystem is not available. In non-editor builds, sends a NOT_IMPLEMENTED response.
|
|
70
|
+
*
|
|
71
|
+
* @param Self Pointer to the MCP Automation Bridge subsystem handling the request.
|
|
72
|
+
* @param RequestId Identifier for the incoming request; used when sending the response.
|
|
73
|
+
* @param LocalPayload JSON payload for the probe request (may include "componentClass").
|
|
74
|
+
* @param RequestingSocket WebSocket of the requesting client; may be null for non-socket invocations.
|
|
75
|
+
* @return true if the request was handled (a response was sent).
|
|
76
|
+
*/
|
|
77
|
+
bool FBlueprintCreationHandlers::HandleBlueprintProbeSubobjectHandle(
|
|
78
|
+
UMcpAutomationBridgeSubsystem *Self, const FString &RequestId,
|
|
79
|
+
const TSharedPtr<FJsonObject> &LocalPayload,
|
|
80
|
+
TSharedPtr<FMcpBridgeWebSocket> RequestingSocket) {
|
|
81
|
+
check(Self);
|
|
82
|
+
// Local extraction
|
|
83
|
+
FString ComponentClass;
|
|
84
|
+
LocalPayload->TryGetStringField(TEXT("componentClass"), ComponentClass);
|
|
85
|
+
if (ComponentClass.IsEmpty())
|
|
86
|
+
ComponentClass = TEXT("StaticMeshComponent");
|
|
87
|
+
|
|
88
|
+
#if WITH_EDITOR
|
|
89
|
+
UE_LOG(LogMcpAutomationBridgeSubsystem, Log,
|
|
90
|
+
TEXT("HandleBlueprintAction: blueprint_probe_subobject_handle start "
|
|
91
|
+
"RequestId=%s componentClass=%s"),
|
|
92
|
+
*RequestId, *ComponentClass);
|
|
93
|
+
|
|
94
|
+
auto CleanupProbeAsset = [](UBlueprint *ProbeBP) {
|
|
95
|
+
#if WITH_EDITOR
|
|
96
|
+
if (ProbeBP) {
|
|
97
|
+
const FString AssetPath = ProbeBP->GetPathName();
|
|
98
|
+
if (!UEditorAssetLibrary::DeleteLoadedAsset(ProbeBP)) {
|
|
99
|
+
UE_LOG(LogMcpAutomationBridgeSubsystem, Warning,
|
|
100
|
+
TEXT("Failed to delete loaded probe asset: %s"), *AssetPath);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (!AssetPath.IsEmpty() &&
|
|
104
|
+
UEditorAssetLibrary::DoesAssetExist(AssetPath)) {
|
|
105
|
+
if (!UEditorAssetLibrary::DeleteAsset(AssetPath)) {
|
|
106
|
+
UE_LOG(LogMcpAutomationBridgeSubsystem, Error,
|
|
107
|
+
TEXT("Failed to delete probe asset file: %s"), *AssetPath);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
#endif
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
const FString ProbeFolder = TEXT("/Game/Temp/MCPProbe");
|
|
115
|
+
const FString ProbeName = FString::Printf(
|
|
116
|
+
TEXT("MCP_Probe_%s"), *FGuid::NewGuid().ToString(EGuidFormats::Digits));
|
|
117
|
+
UBlueprint *CreatedBP = nullptr;
|
|
118
|
+
{
|
|
119
|
+
UBlueprintFactory *Factory = NewObject<UBlueprintFactory>();
|
|
120
|
+
FAssetToolsModule &AssetToolsModule =
|
|
121
|
+
FModuleManager::LoadModuleChecked<FAssetToolsModule>(
|
|
122
|
+
TEXT("AssetTools"));
|
|
123
|
+
UObject *NewObj = AssetToolsModule.Get().CreateAsset(
|
|
124
|
+
ProbeName, ProbeFolder, UBlueprint::StaticClass(), Factory);
|
|
125
|
+
if (!NewObj) {
|
|
126
|
+
TSharedPtr<FJsonObject> Err = MakeShared<FJsonObject>();
|
|
127
|
+
Err->SetStringField(TEXT("componentClass"), ComponentClass);
|
|
128
|
+
Err->SetStringField(TEXT("error"),
|
|
129
|
+
TEXT("Failed to create probe blueprint asset"));
|
|
130
|
+
UE_LOG(LogMcpAutomationBridgeSubsystem, Warning,
|
|
131
|
+
TEXT("blueprint_probe_subobject_handle: asset creation failed"));
|
|
132
|
+
Self->SendAutomationResponse(RequestingSocket, RequestId, false,
|
|
133
|
+
TEXT("Failed to create probe blueprint"),
|
|
134
|
+
Err, TEXT("PROBE_CREATE_FAILED"));
|
|
135
|
+
return true;
|
|
136
|
+
}
|
|
137
|
+
CreatedBP = Cast<UBlueprint>(NewObj);
|
|
138
|
+
if (!CreatedBP) {
|
|
139
|
+
TSharedPtr<FJsonObject> Err = MakeShared<FJsonObject>();
|
|
140
|
+
Err->SetStringField(TEXT("componentClass"), ComponentClass);
|
|
141
|
+
Err->SetStringField(TEXT("error"),
|
|
142
|
+
TEXT("Probe asset was not a Blueprint"));
|
|
143
|
+
UE_LOG(
|
|
144
|
+
LogMcpAutomationBridgeSubsystem, Warning,
|
|
145
|
+
TEXT(
|
|
146
|
+
"blueprint_probe_subobject_handle: created asset not blueprint"));
|
|
147
|
+
Self->SendAutomationResponse(
|
|
148
|
+
RequestingSocket, RequestId, false,
|
|
149
|
+
TEXT("Probe asset created was not a Blueprint"), Err,
|
|
150
|
+
TEXT("PROBE_CREATE_FAILED"));
|
|
151
|
+
CleanupProbeAsset(CreatedBP);
|
|
152
|
+
return true;
|
|
153
|
+
}
|
|
154
|
+
FAssetRegistryModule &Arm =
|
|
155
|
+
FModuleManager::LoadModuleChecked<FAssetRegistryModule>(
|
|
156
|
+
TEXT("AssetRegistry"));
|
|
157
|
+
Arm.Get().AssetCreated(CreatedBP);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
TSharedPtr<FJsonObject> ResultObj = MakeShared<FJsonObject>();
|
|
161
|
+
ResultObj->SetStringField(TEXT("componentClass"), ComponentClass);
|
|
162
|
+
ResultObj->SetBoolField(TEXT("success"), false);
|
|
163
|
+
ResultObj->SetBoolField(TEXT("subsystemAvailable"), false);
|
|
164
|
+
|
|
165
|
+
#if MCP_HAS_SUBOBJECT_DATA_SUBSYSTEM
|
|
166
|
+
if (USubobjectDataSubsystem *Subsystem =
|
|
167
|
+
(GEngine ? GEngine->GetEngineSubsystem<USubobjectDataSubsystem>()
|
|
168
|
+
: nullptr)) {
|
|
169
|
+
ResultObj->SetBoolField(TEXT("subsystemAvailable"), true);
|
|
170
|
+
|
|
171
|
+
TArray<FSubobjectDataHandle> GatheredHandles;
|
|
172
|
+
Subsystem->K2_GatherSubobjectDataForBlueprint(CreatedBP, GatheredHandles);
|
|
173
|
+
|
|
174
|
+
TArray<TSharedPtr<FJsonValue>> HandleJsonArr;
|
|
175
|
+
const UScriptStruct *HandleStruct = FSubobjectDataHandle::StaticStruct();
|
|
176
|
+
for (int32 Index = 0; Index < GatheredHandles.Num(); ++Index) {
|
|
177
|
+
const FSubobjectDataHandle &Handle = GatheredHandles[Index];
|
|
178
|
+
FString Repr;
|
|
179
|
+
if (HandleStruct) {
|
|
180
|
+
Repr = FString::Printf(TEXT("%s@%p"), *HandleStruct->GetName(),
|
|
181
|
+
(void *)&Handle);
|
|
182
|
+
} else {
|
|
183
|
+
Repr = FString::Printf(TEXT("<subobject_handle_%d>"), Index);
|
|
184
|
+
}
|
|
185
|
+
HandleJsonArr.Add(MakeShared<FJsonValueString>(Repr));
|
|
186
|
+
}
|
|
187
|
+
ResultObj->SetArrayField(TEXT("gatheredHandles"), HandleJsonArr);
|
|
188
|
+
ResultObj->SetBoolField(TEXT("success"), true);
|
|
189
|
+
|
|
190
|
+
CleanupProbeAsset(CreatedBP);
|
|
191
|
+
Self->SendAutomationResponse(RequestingSocket, RequestId, true,
|
|
192
|
+
TEXT("Native probe completed"), ResultObj,
|
|
193
|
+
FString());
|
|
194
|
+
return true;
|
|
195
|
+
}
|
|
196
|
+
#endif
|
|
197
|
+
|
|
198
|
+
// Subsystem unavailable – fallback to simple SCS enumeration
|
|
199
|
+
ResultObj->SetBoolField(TEXT("subsystemAvailable"), false);
|
|
200
|
+
TArray<TSharedPtr<FJsonValue>> HandleJsonArr;
|
|
201
|
+
if (CreatedBP && CreatedBP->SimpleConstructionScript) {
|
|
202
|
+
const TArray<USCS_Node *> &Nodes =
|
|
203
|
+
CreatedBP->SimpleConstructionScript->GetAllNodes();
|
|
204
|
+
for (USCS_Node *Node : Nodes) {
|
|
205
|
+
if (!Node || !Node->GetVariableName().IsValid())
|
|
206
|
+
continue;
|
|
207
|
+
HandleJsonArr.Add(MakeShared<FJsonValueString>(FString::Printf(
|
|
208
|
+
TEXT("scs://%s"), *Node->GetVariableName().ToString())));
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
if (HandleJsonArr.Num() == 0) {
|
|
212
|
+
HandleJsonArr.Add(
|
|
213
|
+
MakeShared<FJsonValueString>(TEXT("<probe_handle_stub>")));
|
|
214
|
+
}
|
|
215
|
+
ResultObj->SetArrayField(TEXT("gatheredHandles"), HandleJsonArr);
|
|
216
|
+
ResultObj->SetBoolField(TEXT("success"), true);
|
|
217
|
+
|
|
218
|
+
CleanupProbeAsset(CreatedBP);
|
|
219
|
+
Self->SendAutomationResponse(RequestingSocket, RequestId, true,
|
|
220
|
+
TEXT("Fallback probe completed"), ResultObj,
|
|
221
|
+
FString());
|
|
222
|
+
return true;
|
|
223
|
+
#else
|
|
224
|
+
Self->SendAutomationResponse(RequestingSocket, RequestId, false,
|
|
225
|
+
TEXT("Blueprint probe requires editor build."),
|
|
226
|
+
nullptr, TEXT("NOT_IMPLEMENTED"));
|
|
227
|
+
return true;
|
|
228
|
+
#endif // WITH_EDITOR
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* @brief Applies JSON-defined property values to a UObject, recursively handling nested object properties.
|
|
233
|
+
*
|
|
234
|
+
* For each entry in Properties, this function looks up a property on TargetObj by name and sets it:
|
|
235
|
+
* - If the property is an object property and the JSON value is an object, the function recurses into that child object.
|
|
236
|
+
* - Otherwise JSON primitives (string, number, boolean) are converted to text and applied using ImportText_Direct.
|
|
237
|
+
* Unknown property names are silently ignored and no errors are thrown.
|
|
238
|
+
*
|
|
239
|
+
* @param TargetObj The UObject to modify. No action is performed if null.
|
|
240
|
+
* @param Properties JSON object mapping property names to values; nested JSON objects map to subobjects/components.
|
|
241
|
+
*/
|
|
242
|
+
static void ApplyPropertiesToObject(UObject *TargetObj,
|
|
243
|
+
const TSharedPtr<FJsonObject> &Properties) {
|
|
244
|
+
if (!TargetObj || !Properties.IsValid()) {
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
for (const auto &Pair : Properties->Values) {
|
|
249
|
+
FProperty *Property = TargetObj->GetClass()->FindPropertyByName(*Pair.Key);
|
|
250
|
+
if (!Property) {
|
|
251
|
+
continue;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// 1. Handle Object Properties (Recursion for Components/Subobjects)
|
|
255
|
+
if (FObjectProperty *ObjProp = CastField<FObjectProperty>(Property)) {
|
|
256
|
+
if (Pair.Value->Type == EJson::Object) {
|
|
257
|
+
// This is likely a component or subobject property we want to edit
|
|
258
|
+
// inline
|
|
259
|
+
UObject *ChildObj =
|
|
260
|
+
ObjProp->GetObjectPropertyValue_InContainer(TargetObj);
|
|
261
|
+
if (ChildObj) {
|
|
262
|
+
ApplyPropertiesToObject(ChildObj, Pair.Value->AsObject());
|
|
263
|
+
}
|
|
264
|
+
continue;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// 2. Handle generic property setting via text import
|
|
269
|
+
FString TextValue;
|
|
270
|
+
|
|
271
|
+
if (Pair.Value->Type == EJson::String) {
|
|
272
|
+
TextValue = Pair.Value->AsString();
|
|
273
|
+
} else if (Pair.Value->Type == EJson::Number) {
|
|
274
|
+
double Val = Pair.Value->AsNumber();
|
|
275
|
+
// Heuristic: check if target is integer to avoid floating point syntax
|
|
276
|
+
// issues if any
|
|
277
|
+
if (Property->IsA<FIntProperty>() || Property->IsA<FInt64Property>() ||
|
|
278
|
+
Property->IsA<FByteProperty>()) {
|
|
279
|
+
TextValue = FString::Printf(TEXT("%lld"), (long long)Val);
|
|
280
|
+
} else {
|
|
281
|
+
TextValue = FString::SanitizeFloat(Val);
|
|
282
|
+
}
|
|
283
|
+
} else if (Pair.Value->Type == EJson::Boolean) {
|
|
284
|
+
TextValue = Pair.Value->AsBool() ? TEXT("True") : TEXT("False");
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
if (!TextValue.IsEmpty()) {
|
|
288
|
+
Property->ImportText_Direct(
|
|
289
|
+
*TextValue, Property->ContainerPtrToValuePtr<void>(TargetObj),
|
|
290
|
+
TargetObj, 0);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* @brief Create a new Blueprint asset from the provided payload and send a completion response to the requester (coalesces concurrent requests for the same path).
|
|
297
|
+
*
|
|
298
|
+
* Expected payload fields:
|
|
299
|
+
* - "name" (string, required): asset name.
|
|
300
|
+
* - "savePath" (string, optional, default "/Game"): destination folder.
|
|
301
|
+
* - "parentClass" (string, optional): class path or name used as the Blueprint parent.
|
|
302
|
+
* - "blueprintType" (string, optional): hint like "actor", "pawn", or "character" used when parent class is not resolved.
|
|
303
|
+
* - "properties" (object, optional): JSON object of CDO properties to apply to the generated class default object.
|
|
304
|
+
* - "waitForCompletion" (bool, optional): whether the caller intends to wait for completion (affects coalescing behavior).
|
|
305
|
+
*
|
|
306
|
+
* Behavior notes:
|
|
307
|
+
* - Multiple concurrent requests that target the same SavePath/Name are coalesced so all waiters receive the same completion result.
|
|
308
|
+
* - In editor builds, attempts to create the Blueprint (or returns an existing asset if present), applies optional CDO properties, registers the asset with the Asset Registry, and attempts to ensure asset availability (save/scan).
|
|
309
|
+
* - In non-editor builds, responds with NOT_IMPLEMENTED indicating blueprint creation requires an editor build.
|
|
310
|
+
*
|
|
311
|
+
* @param Self Subsystem instance used to send responses and perform subsystem operations.
|
|
312
|
+
* @param RequestId Identifier for the request; included in the completion response.
|
|
313
|
+
* @param LocalPayload JSON payload describing the blueprint to create (see Expected payload fields above).
|
|
314
|
+
* @param RequestingSocket Optional socket to which the immediate response should be sent; coalesced waiters will also be notified.
|
|
315
|
+
* @return true if the request was handled and a response was sent to the requester (or coalesced waiters).
|
|
316
|
+
*/
|
|
317
|
+
bool FBlueprintCreationHandlers::HandleBlueprintCreate(
|
|
318
|
+
UMcpAutomationBridgeSubsystem *Self, const FString &RequestId,
|
|
319
|
+
const TSharedPtr<FJsonObject> &LocalPayload,
|
|
320
|
+
TSharedPtr<FMcpBridgeWebSocket> RequestingSocket) {
|
|
321
|
+
check(Self);
|
|
322
|
+
UE_LOG(LogMcpAutomationBridgeSubsystem, Log,
|
|
323
|
+
TEXT("HandleBlueprintCreate ENTRY: RequestId=%s"), *RequestId);
|
|
324
|
+
|
|
325
|
+
FString Name;
|
|
326
|
+
LocalPayload->TryGetStringField(TEXT("name"), Name);
|
|
327
|
+
if (Name.TrimStartAndEnd().IsEmpty()) {
|
|
328
|
+
Self->SendAutomationResponse(RequestingSocket, RequestId, false,
|
|
329
|
+
TEXT("blueprint_create requires a name."),
|
|
330
|
+
nullptr, TEXT("INVALID_ARGUMENT"));
|
|
331
|
+
return true;
|
|
332
|
+
}
|
|
333
|
+
FString SavePath;
|
|
334
|
+
LocalPayload->TryGetStringField(TEXT("savePath"), SavePath);
|
|
335
|
+
if (SavePath.TrimStartAndEnd().IsEmpty())
|
|
336
|
+
SavePath = TEXT("/Game");
|
|
337
|
+
FString ParentClassSpec;
|
|
338
|
+
LocalPayload->TryGetStringField(TEXT("parentClass"), ParentClassSpec);
|
|
339
|
+
FString BlueprintTypeSpec;
|
|
340
|
+
LocalPayload->TryGetStringField(TEXT("blueprintType"), BlueprintTypeSpec);
|
|
341
|
+
const double Now = FPlatformTime::Seconds();
|
|
342
|
+
const FString CreateKey = FString::Printf(TEXT("%s/%s"), *SavePath, *Name);
|
|
343
|
+
|
|
344
|
+
// Check if client wants to wait for completion
|
|
345
|
+
bool bWaitForCompletion = false;
|
|
346
|
+
LocalPayload->TryGetBoolField(TEXT("waitForCompletion"), bWaitForCompletion);
|
|
347
|
+
UE_LOG(
|
|
348
|
+
LogMcpAutomationBridgeSubsystem, Log,
|
|
349
|
+
TEXT("HandleBlueprintCreate: name=%s, savePath=%s, waitForCompletion=%s"),
|
|
350
|
+
*Name, *SavePath, bWaitForCompletion ? TEXT("true") : TEXT("false"));
|
|
351
|
+
|
|
352
|
+
// Track in-flight requests regardless so all waiters receive completion
|
|
353
|
+
{
|
|
354
|
+
FScopeLock Lock(&GBlueprintCreateMutex);
|
|
355
|
+
if (GBlueprintCreateInflight.Contains(CreateKey)) {
|
|
356
|
+
GBlueprintCreateInflight[CreateKey].Add(
|
|
357
|
+
TPair<FString, TSharedPtr<FMcpBridgeWebSocket>>(RequestId,
|
|
358
|
+
RequestingSocket));
|
|
359
|
+
UE_LOG(LogMcpAutomationBridgeSubsystem, Log,
|
|
360
|
+
TEXT("HandleBlueprintCreate: Coalescing request %s for %s"),
|
|
361
|
+
*RequestId, *CreateKey);
|
|
362
|
+
return true;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
GBlueprintCreateInflight.Add(
|
|
366
|
+
CreateKey, TArray<TPair<FString, TSharedPtr<FMcpBridgeWebSocket>>>());
|
|
367
|
+
GBlueprintCreateInflightTs.Add(CreateKey, Now);
|
|
368
|
+
GBlueprintCreateInflight[CreateKey].Add(
|
|
369
|
+
TPair<FString, TSharedPtr<FMcpBridgeWebSocket>>(RequestId,
|
|
370
|
+
RequestingSocket));
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
#if WITH_EDITOR
|
|
374
|
+
// Perform real creation (editor only)
|
|
375
|
+
UE_LOG(LogMcpAutomationBridgeSubsystem, Log,
|
|
376
|
+
TEXT("HandleBlueprintCreate: Starting blueprint creation "
|
|
377
|
+
"(WITH_EDITOR=1)"));
|
|
378
|
+
UBlueprint *CreatedBlueprint = nullptr;
|
|
379
|
+
FString CreatedNormalizedPath;
|
|
380
|
+
FString CreationError;
|
|
381
|
+
|
|
382
|
+
// Check if asset already exists to avoid "Overwrite" dialogs which can crash
|
|
383
|
+
// the editor/driver
|
|
384
|
+
FString PreExistingNormalized;
|
|
385
|
+
FString PreExistingError;
|
|
386
|
+
if (UBlueprint *PreExistingBP = LoadBlueprintAsset(
|
|
387
|
+
CreateKey, PreExistingNormalized, PreExistingError)) {
|
|
388
|
+
CreatedBlueprint = PreExistingBP;
|
|
389
|
+
CreatedNormalizedPath = !PreExistingNormalized.TrimStartAndEnd().IsEmpty()
|
|
390
|
+
? PreExistingNormalized
|
|
391
|
+
: PreExistingBP->GetPathName();
|
|
392
|
+
if (CreatedNormalizedPath.Contains(TEXT("."))) {
|
|
393
|
+
CreatedNormalizedPath =
|
|
394
|
+
CreatedNormalizedPath.Left(CreatedNormalizedPath.Find(TEXT(".")));
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
TSharedPtr<FJsonObject> ResultPayload = MakeShared<FJsonObject>();
|
|
398
|
+
ResultPayload->SetStringField(TEXT("path"), CreatedNormalizedPath);
|
|
399
|
+
ResultPayload->SetStringField(TEXT("assetPath"),
|
|
400
|
+
PreExistingBP->GetPathName());
|
|
401
|
+
ResultPayload->SetBoolField(TEXT("saved"), true);
|
|
402
|
+
|
|
403
|
+
FScopeLock Lock(&GBlueprintCreateMutex);
|
|
404
|
+
if (TArray<TPair<FString, TSharedPtr<FMcpBridgeWebSocket>>> *Subs =
|
|
405
|
+
GBlueprintCreateInflight.Find(CreateKey)) {
|
|
406
|
+
for (const TPair<FString, TSharedPtr<FMcpBridgeWebSocket>> &Pair :
|
|
407
|
+
*Subs) {
|
|
408
|
+
Self->SendAutomationResponse(Pair.Value, Pair.Key, true,
|
|
409
|
+
TEXT("Blueprint already exists"),
|
|
410
|
+
ResultPayload, FString());
|
|
411
|
+
}
|
|
412
|
+
GBlueprintCreateInflight.Remove(CreateKey);
|
|
413
|
+
GBlueprintCreateInflightTs.Remove(CreateKey);
|
|
414
|
+
UE_LOG(LogMcpAutomationBridgeSubsystem, Log,
|
|
415
|
+
TEXT("blueprint_create RequestId=%s completed (existing blueprint "
|
|
416
|
+
"found early)."),
|
|
417
|
+
*RequestId);
|
|
418
|
+
} else {
|
|
419
|
+
Self->SendAutomationResponse(RequestingSocket, RequestId, true,
|
|
420
|
+
TEXT("Blueprint already exists"),
|
|
421
|
+
ResultPayload, FString());
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
return true;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
UBlueprintFactory *Factory = NewObject<UBlueprintFactory>();
|
|
428
|
+
UClass *ResolvedParent = nullptr;
|
|
429
|
+
if (!ParentClassSpec.IsEmpty()) {
|
|
430
|
+
if (ParentClassSpec.StartsWith(TEXT("/Script/"))) {
|
|
431
|
+
ResolvedParent = LoadClass<UObject>(nullptr, *ParentClassSpec);
|
|
432
|
+
} else {
|
|
433
|
+
ResolvedParent = FindObject<UClass>(nullptr, *ParentClassSpec);
|
|
434
|
+
// Avoid calling StaticLoadClass on a bare short name like "Actor" which
|
|
435
|
+
// can generate engine warnings (e.g., "Class None.Actor"). For short
|
|
436
|
+
// names, try common /Script prefixes instead.
|
|
437
|
+
const bool bLooksPathLike = ParentClassSpec.Contains(TEXT("/")) ||
|
|
438
|
+
ParentClassSpec.Contains(TEXT("."));
|
|
439
|
+
if (!ResolvedParent && bLooksPathLike) {
|
|
440
|
+
ResolvedParent =
|
|
441
|
+
StaticLoadClass(UObject::StaticClass(), nullptr, *ParentClassSpec);
|
|
442
|
+
}
|
|
443
|
+
if (!ResolvedParent && !bLooksPathLike) {
|
|
444
|
+
const TArray<FString> PrefixGuesses = {
|
|
445
|
+
FString::Printf(TEXT("/Script/Engine.%s"), *ParentClassSpec),
|
|
446
|
+
FString::Printf(TEXT("/Script/GameFramework.%s"), *ParentClassSpec),
|
|
447
|
+
FString::Printf(TEXT("/Script/CoreUObject.%s"), *ParentClassSpec)};
|
|
448
|
+
for (const FString &Guess : PrefixGuesses) {
|
|
449
|
+
UClass *Loaded = FindObject<UClass>(nullptr, *Guess);
|
|
450
|
+
if (!Loaded) {
|
|
451
|
+
Loaded = StaticLoadClass(UObject::StaticClass(), nullptr, *Guess);
|
|
452
|
+
}
|
|
453
|
+
if (Loaded) {
|
|
454
|
+
ResolvedParent = Loaded;
|
|
455
|
+
break;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
if (!ResolvedParent) {
|
|
460
|
+
for (TObjectIterator<UClass> It; It; ++It) {
|
|
461
|
+
UClass *C = *It;
|
|
462
|
+
if (!C)
|
|
463
|
+
continue;
|
|
464
|
+
if (C->GetName().Equals(ParentClassSpec, ESearchCase::IgnoreCase)) {
|
|
465
|
+
ResolvedParent = C;
|
|
466
|
+
break;
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
if (!ResolvedParent && !BlueprintTypeSpec.IsEmpty()) {
|
|
473
|
+
const FString LowerType = BlueprintTypeSpec.ToLower();
|
|
474
|
+
if (LowerType == TEXT("actor"))
|
|
475
|
+
ResolvedParent = AActor::StaticClass();
|
|
476
|
+
else if (LowerType == TEXT("pawn"))
|
|
477
|
+
ResolvedParent = APawn::StaticClass();
|
|
478
|
+
else if (LowerType == TEXT("character"))
|
|
479
|
+
ResolvedParent = ACharacter::StaticClass();
|
|
480
|
+
}
|
|
481
|
+
if (ResolvedParent)
|
|
482
|
+
Factory->ParentClass = ResolvedParent;
|
|
483
|
+
else
|
|
484
|
+
Factory->ParentClass = AActor::StaticClass();
|
|
485
|
+
|
|
486
|
+
FAssetToolsModule &AssetToolsModule =
|
|
487
|
+
FModuleManager::LoadModuleChecked<FAssetToolsModule>(TEXT("AssetTools"));
|
|
488
|
+
UObject *NewObj = AssetToolsModule.Get().CreateAsset(
|
|
489
|
+
Name, SavePath, UBlueprint::StaticClass(), Factory);
|
|
490
|
+
if (NewObj) {
|
|
491
|
+
UE_LOG(LogMcpAutomationBridgeSubsystem, Log,
|
|
492
|
+
TEXT("CreateAsset returned object: name=%s path=%s class=%s"),
|
|
493
|
+
*NewObj->GetName(), *NewObj->GetPathName(),
|
|
494
|
+
*NewObj->GetClass()->GetName());
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
CreatedBlueprint = Cast<UBlueprint>(NewObj);
|
|
498
|
+
|
|
499
|
+
// Apply optional CDO properties immediately if provided
|
|
500
|
+
if (CreatedBlueprint && CreatedBlueprint->GeneratedClass) {
|
|
501
|
+
const TSharedPtr<FJsonObject> *PropertiesPtr;
|
|
502
|
+
if (LocalPayload->TryGetObjectField(TEXT("properties"), PropertiesPtr)) {
|
|
503
|
+
UObject *CDO = CreatedBlueprint->GeneratedClass->GetDefaultObject();
|
|
504
|
+
if (CDO) {
|
|
505
|
+
ApplyPropertiesToObject(CDO, *PropertiesPtr);
|
|
506
|
+
// Mark dirty
|
|
507
|
+
CreatedBlueprint->Modify();
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
if (!CreatedBlueprint) {
|
|
513
|
+
// If creation failed, check whether a Blueprint already exists at the
|
|
514
|
+
// target path. AssetTools will return nullptr when an asset with the
|
|
515
|
+
// same name already exists; in that case we should treat this as an
|
|
516
|
+
// idempotent success instead of a hard failure.
|
|
517
|
+
FString ExistingNormalized;
|
|
518
|
+
FString ExistingError;
|
|
519
|
+
UBlueprint *ExistingBP =
|
|
520
|
+
LoadBlueprintAsset(CreateKey, ExistingNormalized, ExistingError);
|
|
521
|
+
if (ExistingBP) {
|
|
522
|
+
CreatedBlueprint = ExistingBP;
|
|
523
|
+
CreatedNormalizedPath = !ExistingNormalized.TrimStartAndEnd().IsEmpty()
|
|
524
|
+
? ExistingNormalized
|
|
525
|
+
: ExistingBP->GetPathName();
|
|
526
|
+
if (CreatedNormalizedPath.Contains(TEXT("."))) {
|
|
527
|
+
CreatedNormalizedPath =
|
|
528
|
+
CreatedNormalizedPath.Left(CreatedNormalizedPath.Find(TEXT(".")));
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
TSharedPtr<FJsonObject> ResultPayload = MakeShared<FJsonObject>();
|
|
532
|
+
ResultPayload->SetStringField(TEXT("path"), CreatedNormalizedPath);
|
|
533
|
+
ResultPayload->SetStringField(TEXT("assetPath"),
|
|
534
|
+
ExistingBP->GetPathName());
|
|
535
|
+
ResultPayload->SetBoolField(TEXT("saved"), true);
|
|
536
|
+
|
|
537
|
+
FScopeLock Lock(&GBlueprintCreateMutex);
|
|
538
|
+
if (TArray<TPair<FString, TSharedPtr<FMcpBridgeWebSocket>>> *Subs =
|
|
539
|
+
GBlueprintCreateInflight.Find(CreateKey)) {
|
|
540
|
+
for (const TPair<FString, TSharedPtr<FMcpBridgeWebSocket>> &Pair :
|
|
541
|
+
*Subs) {
|
|
542
|
+
Self->SendAutomationResponse(Pair.Value, Pair.Key, true,
|
|
543
|
+
TEXT("Blueprint already exists"),
|
|
544
|
+
ResultPayload, FString());
|
|
545
|
+
}
|
|
546
|
+
GBlueprintCreateInflight.Remove(CreateKey);
|
|
547
|
+
GBlueprintCreateInflightTs.Remove(CreateKey);
|
|
548
|
+
UE_LOG(LogMcpAutomationBridgeSubsystem, Log,
|
|
549
|
+
TEXT("blueprint_create RequestId=%s completed (existing "
|
|
550
|
+
"blueprint)."),
|
|
551
|
+
*RequestId);
|
|
552
|
+
} else {
|
|
553
|
+
Self->SendAutomationResponse(RequestingSocket, RequestId, true,
|
|
554
|
+
TEXT("Blueprint already exists"),
|
|
555
|
+
ResultPayload, FString());
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
return true;
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
CreationError =
|
|
562
|
+
FString::Printf(TEXT("Created asset is not a Blueprint: %s"),
|
|
563
|
+
NewObj ? *NewObj->GetPathName() : TEXT("<null>"));
|
|
564
|
+
|
|
565
|
+
{
|
|
566
|
+
FScopeLock Lock(&GBlueprintCreateMutex);
|
|
567
|
+
if (TArray<TPair<FString, TSharedPtr<FMcpBridgeWebSocket>>> *Subs =
|
|
568
|
+
GBlueprintCreateInflight.Find(CreateKey)) {
|
|
569
|
+
for (const TPair<FString, TSharedPtr<FMcpBridgeWebSocket>> &Pair :
|
|
570
|
+
*Subs) {
|
|
571
|
+
Self->SendAutomationResponse(Pair.Value, Pair.Key, false,
|
|
572
|
+
CreationError, nullptr,
|
|
573
|
+
TEXT("CREATE_FAILED"));
|
|
574
|
+
}
|
|
575
|
+
GBlueprintCreateInflight.Remove(CreateKey);
|
|
576
|
+
GBlueprintCreateInflightTs.Remove(CreateKey);
|
|
577
|
+
} else {
|
|
578
|
+
Self->SendAutomationResponse(RequestingSocket, RequestId, false,
|
|
579
|
+
CreationError, nullptr,
|
|
580
|
+
TEXT("CREATE_FAILED"));
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
return true;
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
CreatedNormalizedPath = CreatedBlueprint->GetPathName();
|
|
587
|
+
if (CreatedNormalizedPath.Contains(TEXT(".")))
|
|
588
|
+
CreatedNormalizedPath =
|
|
589
|
+
CreatedNormalizedPath.Left(CreatedNormalizedPath.Find(TEXT(".")));
|
|
590
|
+
FAssetRegistryModule &AssetRegistryModule =
|
|
591
|
+
FModuleManager::LoadModuleChecked<FAssetRegistryModule>(
|
|
592
|
+
TEXT("AssetRegistry"));
|
|
593
|
+
AssetRegistryModule.AssetCreated(CreatedBlueprint);
|
|
594
|
+
|
|
595
|
+
TSharedPtr<FJsonObject> ResultPayload = MakeShared<FJsonObject>();
|
|
596
|
+
ResultPayload->SetStringField(TEXT("path"), CreatedNormalizedPath);
|
|
597
|
+
ResultPayload->SetStringField(TEXT("assetPath"),
|
|
598
|
+
CreatedBlueprint->GetPathName());
|
|
599
|
+
ResultPayload->SetBoolField(TEXT("saved"), true);
|
|
600
|
+
FScopeLock Lock(&GBlueprintCreateMutex);
|
|
601
|
+
if (TArray<TPair<FString, TSharedPtr<FMcpBridgeWebSocket>>> *Subs =
|
|
602
|
+
GBlueprintCreateInflight.Find(CreateKey)) {
|
|
603
|
+
for (const TPair<FString, TSharedPtr<FMcpBridgeWebSocket>> &Pair : *Subs) {
|
|
604
|
+
Self->SendAutomationResponse(Pair.Value, Pair.Key, true,
|
|
605
|
+
TEXT("Blueprint created"), ResultPayload,
|
|
606
|
+
FString());
|
|
607
|
+
}
|
|
608
|
+
GBlueprintCreateInflight.Remove(CreateKey);
|
|
609
|
+
GBlueprintCreateInflightTs.Remove(CreateKey);
|
|
610
|
+
UE_LOG(LogMcpAutomationBridgeSubsystem, Log,
|
|
611
|
+
TEXT("blueprint_create RequestId=%s completed (coalesced)."),
|
|
612
|
+
*RequestId);
|
|
613
|
+
} else {
|
|
614
|
+
Self->SendAutomationResponse(RequestingSocket, RequestId, true,
|
|
615
|
+
TEXT("Blueprint created"), ResultPayload,
|
|
616
|
+
FString());
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
TWeakObjectPtr<UBlueprint> WeakCreatedBp = CreatedBlueprint;
|
|
620
|
+
if (WeakCreatedBp.IsValid()) {
|
|
621
|
+
UBlueprint *BP = WeakCreatedBp.Get();
|
|
622
|
+
#if WITH_EDITOR
|
|
623
|
+
// Force immediate save and registry scan to ensure availability
|
|
624
|
+
SaveLoadedAssetThrottled(BP, -1.0, true);
|
|
625
|
+
ScanPathSynchronous(BP->GetOutermost()->GetName());
|
|
626
|
+
#endif
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
UE_LOG(LogMcpAutomationBridgeSubsystem, Log,
|
|
630
|
+
TEXT("HandleBlueprintCreate EXIT: RequestId=%s created successfully"),
|
|
631
|
+
*RequestId);
|
|
632
|
+
return true;
|
|
633
|
+
#else
|
|
634
|
+
UE_LOG(LogMcpAutomationBridgeSubsystem, Warning,
|
|
635
|
+
TEXT("HandleBlueprintCreate: WITH_EDITOR not defined - cannot create "
|
|
636
|
+
"blueprints"));
|
|
637
|
+
Self->SendAutomationResponse(
|
|
638
|
+
RequestingSocket, RequestId, false,
|
|
639
|
+
TEXT("Blueprint creation requires editor build."), nullptr,
|
|
640
|
+
TEXT("NOT_IMPLEMENTED"));
|
|
641
|
+
return true;
|
|
642
|
+
#endif
|
|
643
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include "CoreMinimal.h"
|
|
4
|
+
#include "Dom/JsonObject.h"
|
|
5
|
+
|
|
6
|
+
class UMcpAutomationBridgeSubsystem;
|
|
7
|
+
class FMcpBridgeWebSocket;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Handle a request to create or instantiate a Blueprint asset or Blueprint-derived object described in the payload.
|
|
11
|
+
* @param Self Pointer to the MCP automation bridge subsystem processing the request.
|
|
12
|
+
* @param RequestId Correlation identifier for the incoming request/response.
|
|
13
|
+
* @param LocalPayload JSON object containing the blueprint creation parameters and metadata.
|
|
14
|
+
* @param RequestingSocket WebSocket that originated the request (may be null).
|
|
15
|
+
* @returns `true` if the request was parsed and processing was initiated successfully, `false` otherwise.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Handle a request that probes for a handle or reference to a subobject inside a Blueprint instance.
|
|
20
|
+
* @param Self Pointer to the MCP automation bridge subsystem processing the request.
|
|
21
|
+
* @param RequestId Correlation identifier for the incoming request/response.
|
|
22
|
+
* @param LocalPayload JSON object containing the probe parameters (target blueprint instance and subobject identifiers).
|
|
23
|
+
* @param RequestingSocket WebSocket that originated the request (may be null).
|
|
24
|
+
* @returns `true` if the probe request was parsed and processing was initiated successfully, `false` otherwise.
|
|
25
|
+
*/
|
|
26
|
+
class FBlueprintCreationHandlers
|
|
27
|
+
{
|
|
28
|
+
public:
|
|
29
|
+
static bool HandleBlueprintCreate(UMcpAutomationBridgeSubsystem* Self, const FString& RequestId, const TSharedPtr<FJsonObject>& LocalPayload, TSharedPtr<FMcpBridgeWebSocket> RequestingSocket);
|
|
30
|
+
static bool HandleBlueprintProbeSubobjectHandle(UMcpAutomationBridgeSubsystem* Self, const FString& RequestId, const TSharedPtr<FJsonObject>& LocalPayload, TSharedPtr<FMcpBridgeWebSocket> RequestingSocket);
|
|
31
|
+
};
|