ue-mcp 1.2.4 → 1.3.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/README.md +4 -3
- package/dist/action-class.js +56 -3
- package/dist/action-class.js.map +1 -1
- package/dist/bridge-timeouts.d.ts +64 -0
- package/dist/bridge-timeouts.js +118 -0
- package/dist/bridge-timeouts.js.map +1 -0
- package/dist/bridge.js +10 -2
- package/dist/bridge.js.map +1 -1
- package/dist/editor-control.d.ts +72 -5
- package/dist/editor-control.js +164 -140
- package/dist/editor-control.js.map +1 -1
- package/dist/editor-target.d.ts +55 -1
- package/dist/editor-target.js +107 -10
- package/dist/editor-target.js.map +1 -1
- package/dist/engine-observer.d.ts +59 -5
- package/dist/engine-observer.js +249 -29
- package/dist/engine-observer.js.map +1 -1
- package/dist/engine-root.d.ts +91 -0
- package/dist/engine-root.js +448 -0
- package/dist/engine-root.js.map +1 -0
- package/dist/epic-enrich.js +16 -1
- package/dist/epic-enrich.js.map +1 -1
- package/dist/feedback-cli.js +4 -0
- package/dist/feedback-cli.js.map +1 -1
- package/dist/feedback-deferred.d.ts +9 -0
- package/dist/feedback-deferred.js +2 -0
- package/dist/feedback-deferred.js.map +1 -1
- package/dist/feedback-fallback.d.ts +99 -0
- package/dist/feedback-fallback.js +173 -0
- package/dist/feedback-fallback.js.map +1 -0
- package/dist/flow/write-methods.js +20 -0
- package/dist/flow/write-methods.js.map +1 -1
- package/dist/lean-context.js +8 -3
- package/dist/lean-context.js.map +1 -1
- package/dist/locking.js +11 -2
- package/dist/locking.js.map +1 -1
- package/dist/project.d.ts +11 -0
- package/dist/project.js +23 -2
- package/dist/project.js.map +1 -1
- package/dist/python-gate.d.ts +95 -0
- package/dist/python-gate.js +175 -0
- package/dist/python-gate.js.map +1 -0
- package/dist/tool-counts.json +16 -16
- package/dist/tools/animation.js +288 -24
- package/dist/tools/animation.js.map +1 -1
- package/dist/tools/asset.js +79 -14
- package/dist/tools/asset.js.map +1 -1
- package/dist/tools/audio.js +59 -5
- package/dist/tools/audio.js.map +1 -1
- package/dist/tools/blueprint.js +29 -12
- package/dist/tools/blueprint.js.map +1 -1
- package/dist/tools/chooser.js +4 -1
- package/dist/tools/chooser.js.map +1 -1
- package/dist/tools/editor.js +81 -43
- package/dist/tools/editor.js.map +1 -1
- package/dist/tools/feedback.js +214 -48
- package/dist/tools/feedback.js.map +1 -1
- package/dist/tools/foliage.js +27 -1
- package/dist/tools/foliage.js.map +1 -1
- package/dist/tools/gameplay.js +38 -11
- package/dist/tools/gameplay.js.map +1 -1
- package/dist/tools/gas.js +17 -5
- package/dist/tools/gas.js.map +1 -1
- package/dist/tools/landscape.js +22 -7
- package/dist/tools/landscape.js.map +1 -1
- package/dist/tools/level.js +322 -51
- package/dist/tools/level.js.map +1 -1
- package/dist/tools/material.js +10 -4
- package/dist/tools/material.js.map +1 -1
- package/dist/tools/niagara.js +3 -2
- package/dist/tools/niagara.js.map +1 -1
- package/dist/tools/pcg.js +6 -5
- package/dist/tools/pcg.js.map +1 -1
- package/dist/tools/project.js +47 -20
- package/dist/tools/project.js.map +1 -1
- package/dist/types.d.ts +21 -0
- package/dist/types.js +46 -3
- package/dist/types.js.map +1 -1
- package/dist/ue-mcp.default.yml +493 -125
- package/package.json +2 -2
- package/plugin/ue_mcp_bridge/NATIVE_RUNTIME_VISIBILITY.md +53 -0
- package/plugin/ue_mcp_bridge/NATIVE_STATIC_MESH_USAGE_PROGRESS.md +115 -0
- package/plugin/ue_mcp_bridge/README_MassHandlers.md +97 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/BridgeServer.cpp +14 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/GameThreadExecutor.cpp +21 -4
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/GameThreadExecutor.h +9 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/HandlerJsonProperty.h +395 -69
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers.cpp +79 -3
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers.h +25 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_ControlRig.cpp +3 -3
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_ControlRigSequencer.cpp +3061 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_IKRetargeterAuthoring.cpp +961 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_IKRigAuthoring.cpp +900 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_Pose.cpp +769 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_Sequence.cpp +44 -3
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_SkeletalLive.cpp +217 -11
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_StateMachine.cpp +551 -24
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_Validation.cpp +735 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers.cpp +352 -73
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers.h +8 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_BulkProperties.cpp +1 -1
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_BulkRead.cpp +503 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_BulkRead.h +21 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_BulkUpsert.cpp +2 -2
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Enum.cpp +2 -2
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Geometry.cpp +902 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Geometry.h +33 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Import.cpp +478 -134
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Mesh.cpp +5 -5
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_MeshBoolean.cpp +933 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_MeshBoolean.h +35 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Redirectors.cpp +478 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_RenderTarget.cpp +1 -1
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Sockets.cpp +4 -4
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Struct.cpp +2 -2
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Subobject.cpp +319 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AudioHandlers_SoundCue.cpp +3 -3
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers.cpp +482 -35
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers.h +10 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers_Collision.cpp +502 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers_Collision.h +43 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers_Functions.cpp +89 -7
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers_Graph.cpp +17 -51
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers_Internal.h +107 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers_Properties.cpp +10 -10
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers_Search.cpp +648 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/DemoHandlers.cpp +5 -1
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/DiffHandlers.cpp +252 -1
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/DiffHandlers.h +10 -2
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/EditorHandlers.cpp +252 -41
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/EditorHandlers.h +4 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/EditorHandlers_Build.cpp +250 -27
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/EditorHandlers_PIE.cpp +303 -125
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/EditorHandlers_PIERuntime.cpp +73 -50
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/EditorHandlers_RuntimeVisibility.cpp +757 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/FoliageHandlers.cpp +11 -2
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/FoliageHandlers.h +3 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/FoliageHandlers_Batch.cpp +419 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GameplayHandlers.cpp +39 -161
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GameplayHandlers.h +66 -1
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GameplayHandlers_BTAuthoring.cpp +1323 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GameplayHandlers_BehaviorTree.cpp +1211 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GasHandlers.cpp +2 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GasHandlers.h +60 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GasHandlers_Runtime.cpp +363 -12
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/HandlerEditorState.h +84 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LandscapeHandlers.cpp +1288 -36
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LandscapeHandlers.h +3 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LandscapeHandlers_Sculpt.cpp +41 -16
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers.cpp +959 -213
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers.h +66 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_BatchWrite.cpp +1571 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Convert.cpp +316 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Inspection.cpp +280 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_InstanceProjection.cpp +666 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_InstanceProjection_Internal.h +63 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Lights.cpp +43 -12
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_MultiLevel.cpp +13 -47
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_PostProcess.cpp +527 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Query.cpp +1169 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Refresh.cpp +723 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Save.cpp +325 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Spatial.cpp +360 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Trace.cpp +178 -58
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Transient.cpp +337 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Volumes.cpp +25 -12
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_WorldPartition.cpp +10 -9
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_WorldPartitionSettings.cpp +686 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/MassHandlers.cpp +467 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/MassHandlers.h +22 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/MaterialHandlers.cpp +452 -175
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/MaterialHandlers.h +5 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/MaterialHandlers_Build.cpp +597 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/NiagaraHandlers.cpp +17 -15
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/PCGHandlers.cpp +38 -168
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/PhysicsHandlers.cpp +39 -30
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/SequencerHandlers.cpp +392 -78
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/SequencerHandlers.h +2 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/SequencerHandlers_Internal.h +83 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/SkeletalMeshHandlers.cpp +200 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/SkeletalMeshHandlers.h +15 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/SplineHandlers.cpp +19 -12
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/StateTreeHandlers.cpp +31 -1
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/WidgetHandlers.cpp +307 -69
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/WidgetHandlers.h +84 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/WidgetHandlers_Extraction.cpp +8 -41
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/WidgetHandlers_Properties.cpp +33 -52
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/ActorSelectorTests.cpp +344 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/AnimationControlRigTimelineTests.cpp +60 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/AnimationPoseTests.cpp +115 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/AssetBulkReadTests.cpp +177 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/AssetDeleteGuardTests.cpp +276 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/AssetPathResolutionTests.cpp +243 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/AssetPropertyPersistTests.cpp +213 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/AssetSubobjectTests.cpp +235 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/AutomationRunnerTests.cpp +72 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/BehaviorTreeAuthoringTests.cpp +526 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/BehaviorTreeNodeTests.cpp +334 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/BlueprintHandlerSurfaceTests.cpp +362 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/BridgeProtocolTests.cpp +14 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/CollisionQueryTests.cpp +288 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/DataTableRowWriteTests.cpp +453 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/EditorFunctionCallTests.cpp +223 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/FoliageBatchTests.cpp +147 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/GameThreadGateTests.cpp +82 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/GasLiveAttributeTests.cpp +183 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LandscapeSampleTests.cpp +119 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelBatchWriteTests.cpp +176 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelComponentTreeInstanceCountTests.cpp +189 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelConvertBrushesTests.cpp +100 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelInstanceProjectionTests.cpp +265 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelPostProcessOverrideTests.cpp +258 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelQueryComponentsTests.cpp +195 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelRefreshTests.cpp +142 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelSaveReportTests.cpp +125 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelScriptHandlersTests.cpp +42 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelStaticMeshUsageTests.cpp +412 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelTraceWorldScopeTests.cpp +133 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelTransientActorTests.cpp +205 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelWorldPartitionSettingsTests.cpp +168 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/MCPInstancedStructPathTestTypes.h +51 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/MCPInstancedStructPathTests.cpp +379 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/MaterialBuildTests.cpp +238 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/MeshBooleanTests.cpp +170 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/MeshGeometryTests.cpp +116 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/PackageSaveExtensionTests.cpp +161 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/PackageWriteGuardTests.cpp +253 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/RuntimeVisibilityTests.cpp +143 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/SequencerHandlerTests.cpp +660 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/SequencerScrubTests.cpp +50 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/SkeletonDiffTests.cpp +685 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/WidgetBlueprintResolveTests.cpp +145 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/UE_MCP_Bridge.cpp +80 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Public/HandlerFunctionCall.h +509 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Public/HandlerQuery.h +407 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Public/HandlerUtils.h +1008 -77
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/UE_MCP_Bridge.Build.cs +87 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_BridgeStatus/Private/MCPEngineStatus.cpp +152 -14
- package/plugin/ue_mcp_bridge/Source/UE_MCP_BridgeStatus/Private/Tests/MCPEngineStatusTests.cpp +65 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_BridgeStatus/Public/MCPEngineStatus.h +32 -1
- package/plugin/ue_mcp_bridge/Source/UE_MCP_BridgeStatus/UE_MCP_BridgeStatus.Build.cs +2 -0
- package/skills/ue-mcp-animation/SKILL.md +154 -0
- package/skills/ue-mcp-blueprint/SKILL.md +71 -0
package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_Sequence.cpp
CHANGED
|
@@ -149,6 +149,23 @@ TSharedPtr<FJsonValue> FAnimationHandlers::ScanAnimationTracks(const TSharedPtr<
|
|
|
149
149
|
const FString Directory = OptionalString(Params, TEXT("directory"), TEXT(""));
|
|
150
150
|
const FString SkeletonFilter = OptionalString(Params, TEXT("skeletonPath"));
|
|
151
151
|
|
|
152
|
+
// #890: the filter used to be compared as a string against
|
|
153
|
+
// USkeleton::GetPathName(), which is always the object path form, so a
|
|
154
|
+
// package path matched zero sequences and the scan still answered success.
|
|
155
|
+
// A caller could not tell that from a project that genuinely has no
|
|
156
|
+
// sequences on that skeleton. Resolve the filter to the skeleton itself and
|
|
157
|
+
// compare objects, and refuse a filter that names no skeleton at all rather
|
|
158
|
+
// than reporting it as a legitimate empty result.
|
|
159
|
+
USkeleton* FilterSkeleton = nullptr;
|
|
160
|
+
if (!SkeletonFilter.IsEmpty())
|
|
161
|
+
{
|
|
162
|
+
FilterSkeleton = LoadAssetByPath<USkeleton>(SkeletonFilter);
|
|
163
|
+
if (!FilterSkeleton)
|
|
164
|
+
{
|
|
165
|
+
return MCPAssetLoadError(SkeletonFilter, TEXT("Skeleton"));
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
152
169
|
TArray<FString> AssetPaths;
|
|
153
170
|
const TArray<TSharedPtr<FJsonValue>>* PathsArray = nullptr;
|
|
154
171
|
if (Params->TryGetArrayField(TEXT("assetPaths"), PathsArray))
|
|
@@ -185,11 +202,11 @@ TSharedPtr<FJsonValue> FAnimationHandlers::ScanAnimationTracks(const TSharedPtr<
|
|
|
185
202
|
int32 ProblemCount = 0;
|
|
186
203
|
int32 InspectedCount = 0;
|
|
187
204
|
int32 FailureCount = 0;
|
|
205
|
+
int32 FilteredOutCount = 0;
|
|
188
206
|
|
|
189
207
|
for (const FString& AssetPath : AssetPaths)
|
|
190
208
|
{
|
|
191
|
-
|
|
192
|
-
UAnimSequence* AnimSeq = Cast<UAnimSequence>(LoadedAsset);
|
|
209
|
+
UAnimSequence* AnimSeq = LoadAssetByPath<UAnimSequence>(AssetPath);
|
|
193
210
|
if (!AnimSeq)
|
|
194
211
|
{
|
|
195
212
|
++FailureCount;
|
|
@@ -205,8 +222,9 @@ TSharedPtr<FJsonValue> FAnimationHandlers::ScanAnimationTracks(const TSharedPtr<
|
|
|
205
222
|
|
|
206
223
|
USkeleton* Skeleton = AnimSeq->GetSkeleton();
|
|
207
224
|
const FString SequenceSkeletonPath = Skeleton ? Skeleton->GetPathName() : FString();
|
|
208
|
-
if (
|
|
225
|
+
if (FilterSkeleton && Skeleton != FilterSkeleton)
|
|
209
226
|
{
|
|
227
|
+
++FilteredOutCount;
|
|
210
228
|
continue;
|
|
211
229
|
}
|
|
212
230
|
|
|
@@ -257,10 +275,25 @@ TSharedPtr<FJsonValue> FAnimationHandlers::ScanAnimationTracks(const TSharedPtr<
|
|
|
257
275
|
auto Result = MCPSuccess();
|
|
258
276
|
Result->SetStringField(TEXT("directory"), Directory);
|
|
259
277
|
Result->SetNumberField(TEXT("targetTrackCount"), TargetTrackCount);
|
|
278
|
+
Result->SetNumberField(TEXT("candidateCount"), AssetPaths.Num());
|
|
260
279
|
Result->SetNumberField(TEXT("inspectedCount"), InspectedCount);
|
|
261
280
|
Result->SetNumberField(TEXT("problemCount"), ProblemCount);
|
|
262
281
|
Result->SetNumberField(TEXT("failureCount"), FailureCount);
|
|
263
282
|
Result->SetArrayField(TEXT("sequences"), Sequences);
|
|
283
|
+
if (FilterSkeleton)
|
|
284
|
+
{
|
|
285
|
+
// The resolved form, so a caller who passed a package path can see
|
|
286
|
+
// which skeleton the filter actually became (#890).
|
|
287
|
+
Result->SetStringField(TEXT("skeletonPath"), FilterSkeleton->GetPathName());
|
|
288
|
+
Result->SetNumberField(TEXT("filteredOutCount"), FilteredOutCount);
|
|
289
|
+
if (InspectedCount == 0)
|
|
290
|
+
{
|
|
291
|
+
Result->SetStringField(TEXT("note"), FString::Printf(
|
|
292
|
+
TEXT("The skeletonPath filter resolved to '%s' and matched none of the %d AnimSequence(s) scanned. ")
|
|
293
|
+
TEXT("This is a real empty result, not a path-shape miss."),
|
|
294
|
+
*FilterSkeleton->GetPathName(), AssetPaths.Num()));
|
|
295
|
+
}
|
|
296
|
+
}
|
|
264
297
|
return MCPResult(Result);
|
|
265
298
|
}
|
|
266
299
|
|
|
@@ -398,6 +431,10 @@ TSharedPtr<FJsonValue> FAnimationHandlers::SetBoneKeyframes(const TSharedPtr<FJs
|
|
|
398
431
|
// Ensure bone track exists - add it if not present
|
|
399
432
|
const FName BoneFName(*BoneName);
|
|
400
433
|
const IAnimationDataModel* DataModel = AnimSeq->GetDataModel();
|
|
434
|
+
if (!DataModel)
|
|
435
|
+
{
|
|
436
|
+
return MCPError(TEXT("Animation sequence has no data model, so its bone tracks cannot be read or written"));
|
|
437
|
+
}
|
|
401
438
|
if (!DataModel->IsValidBoneTrackName(BoneFName))
|
|
402
439
|
{
|
|
403
440
|
Controller.AddBoneCurve(BoneFName);
|
|
@@ -530,6 +567,10 @@ TSharedPtr<FJsonValue> FAnimationHandlers::BakeKeyframesBatch(const TSharedPtr<F
|
|
|
530
567
|
// Critical: create the bone track before writing keys, otherwise
|
|
531
568
|
// SetBoneTrackKeys returns false and the asset stays a T-pose.
|
|
532
569
|
const IAnimationDataModel* DataModel = AnimSeq->GetDataModel();
|
|
570
|
+
if (!DataModel)
|
|
571
|
+
{
|
|
572
|
+
return MCPError(TEXT("Animation sequence has no data model, so its bone tracks cannot be read or written"));
|
|
573
|
+
}
|
|
533
574
|
if (!DataModel->IsValidBoneTrackName(BoneFName))
|
|
534
575
|
{
|
|
535
576
|
Controller.AddBoneCurve(BoneFName);
|
|
@@ -206,14 +206,36 @@ namespace
|
|
|
206
206
|
return MCPError(TEXT("world must be 'auto' (default), 'pie', 'game', or 'editor'"));
|
|
207
207
|
}
|
|
208
208
|
|
|
209
|
+
// #983: actorPath wins over the label token, and a label naming more
|
|
210
|
+
// than one actor in the world that answered is refused rather than
|
|
211
|
+
// read off whichever the iterator reached first.
|
|
212
|
+
const FString ActorPath = OptionalString(Params, TEXT("actorPath"));
|
|
209
213
|
TArray<TPair<FString, UWorld*>> Candidates = BuildWorldCandidates(RequestedScope);
|
|
210
214
|
for (const TPair<FString, UWorld*>& Candidate : Candidates)
|
|
211
215
|
{
|
|
212
|
-
|
|
213
|
-
|
|
216
|
+
if (!ActorPath.IsEmpty())
|
|
217
|
+
{
|
|
218
|
+
if (AActor* ByPath = MCPFindActorByPath(Candidate.Value, ActorPath))
|
|
219
|
+
{
|
|
220
|
+
OutWorld = Candidate.Value;
|
|
221
|
+
OutActor = ByPath;
|
|
222
|
+
OutResolvedScope = Candidate.Key;
|
|
223
|
+
return nullptr;
|
|
224
|
+
}
|
|
225
|
+
continue;
|
|
226
|
+
}
|
|
227
|
+
TArray<AActor*> Matches;
|
|
228
|
+
MCPCollectActorsByToken(Candidate.Value, ActorToken, EMCPActorMatch::LabelNameOrPath, Matches);
|
|
229
|
+
if (Matches.Num() > 1)
|
|
230
|
+
{
|
|
231
|
+
return MCPAmbiguousActorError(
|
|
232
|
+
ActorToken, TEXT("actorLabel"), TEXT("actorPath"),
|
|
233
|
+
MCPDescribeActorMatchTier(ActorToken, Matches[0]), Matches);
|
|
234
|
+
}
|
|
235
|
+
if (Matches.Num() == 1)
|
|
214
236
|
{
|
|
215
237
|
OutWorld = Candidate.Value;
|
|
216
|
-
OutActor =
|
|
238
|
+
OutActor = Matches[0];
|
|
217
239
|
OutResolvedScope = Candidate.Key;
|
|
218
240
|
return nullptr;
|
|
219
241
|
}
|
|
@@ -230,7 +252,7 @@ namespace
|
|
|
230
252
|
TSharedPtr<FJsonValue> FAnimationHandlers::GetBoneTransform(const TSharedPtr<FJsonObject>& Params)
|
|
231
253
|
{
|
|
232
254
|
FString ActorLabel;
|
|
233
|
-
if (auto Err =
|
|
255
|
+
if (auto Err = RequireStringAlt(Params, TEXT("actorLabel"), TEXT("actorPath"), ActorLabel)) return Err;
|
|
234
256
|
FString BoneName;
|
|
235
257
|
if (auto Err = RequireString(Params, TEXT("boneName"), BoneName)) return Err;
|
|
236
258
|
const FString ComponentName = OptionalString(Params, TEXT("componentName"));
|
|
@@ -240,6 +262,9 @@ TSharedPtr<FJsonValue> FAnimationHandlers::GetBoneTransform(const TSharedPtr<FJs
|
|
|
240
262
|
AActor* Actor = nullptr;
|
|
241
263
|
FString ResolvedWorldScope;
|
|
242
264
|
if (auto Err = ResolveSkeletalActorForQuery(Params, ActorLabel, TEXT("auto"), World, Actor, ResolvedWorldScope)) return Err;
|
|
265
|
+
// A caller who passed only actorPath left ActorLabel holding the path, and
|
|
266
|
+
// every message below reads better naming the actor that answered (#983).
|
|
267
|
+
ActorLabel = Actor->GetActorLabel();
|
|
243
268
|
USkeletalMeshComponent* SK = ResolveSkeletalMeshComp(Actor, ComponentName);
|
|
244
269
|
if (!SK) return MakeSkeletalComponentNotFoundError(Actor, ActorLabel, ComponentName);
|
|
245
270
|
|
|
@@ -292,13 +317,16 @@ TSharedPtr<FJsonValue> FAnimationHandlers::GetBoneTransform(const TSharedPtr<FJs
|
|
|
292
317
|
TSharedPtr<FJsonValue> FAnimationHandlers::ListBones(const TSharedPtr<FJsonObject>& Params)
|
|
293
318
|
{
|
|
294
319
|
FString ActorLabel;
|
|
295
|
-
if (auto Err =
|
|
320
|
+
if (auto Err = RequireStringAlt(Params, TEXT("actorLabel"), TEXT("actorPath"), ActorLabel)) return Err;
|
|
296
321
|
const FString ComponentName = OptionalString(Params, TEXT("componentName"));
|
|
297
322
|
|
|
298
323
|
UWorld* World = nullptr;
|
|
299
324
|
AActor* Actor = nullptr;
|
|
300
325
|
FString ResolvedWorldScope;
|
|
301
326
|
if (auto Err = ResolveSkeletalActorForQuery(Params, ActorLabel, TEXT("auto"), World, Actor, ResolvedWorldScope)) return Err;
|
|
327
|
+
// A caller who passed only actorPath left ActorLabel holding the path, and
|
|
328
|
+
// every message below reads better naming the actor that answered (#983).
|
|
329
|
+
ActorLabel = Actor->GetActorLabel();
|
|
302
330
|
USkeletalMeshComponent* SK = ResolveSkeletalMeshComp(Actor, ComponentName);
|
|
303
331
|
if (!SK) return MakeSkeletalComponentNotFoundError(Actor, ActorLabel, ComponentName);
|
|
304
332
|
if (!SK->GetSkeletalMeshAsset()) return MCPError(FString::Printf(TEXT("SkeletalMeshComponent '%s' on actor '%s' has no SkeletalMesh asset"), *SK->GetName(), *ActorLabel));
|
|
@@ -335,10 +363,12 @@ TSharedPtr<FJsonValue> FAnimationHandlers::RebindLeaderPose(const TSharedPtr<FJs
|
|
|
335
363
|
{
|
|
336
364
|
REQUIRE_EDITOR_WORLD(World);
|
|
337
365
|
FString ActorLabel;
|
|
338
|
-
if (auto Err =
|
|
366
|
+
if (auto Err = RequireStringAlt(Params, TEXT("actorLabel"), TEXT("actorPath"), ActorLabel)) return Err;
|
|
339
367
|
|
|
340
|
-
|
|
341
|
-
|
|
368
|
+
TSharedPtr<FJsonValue> ActorErr;
|
|
369
|
+
AActor* Actor = MCPResolveActor(World, Params, ActorErr);
|
|
370
|
+
if (!Actor) return ActorErr;
|
|
371
|
+
ActorLabel = Actor->GetActorLabel();
|
|
342
372
|
|
|
343
373
|
TArray<USkeletalMeshComponent*> Comps;
|
|
344
374
|
Actor->GetComponents<USkeletalMeshComponent>(Comps);
|
|
@@ -374,6 +404,7 @@ TSharedPtr<FJsonValue> FAnimationHandlers::RebindLeaderPose(const TSharedPtr<FJs
|
|
|
374
404
|
auto Result = MCPSuccess();
|
|
375
405
|
MCPSetUpdated(Result);
|
|
376
406
|
Result->SetStringField(TEXT("actorLabel"), ActorLabel);
|
|
407
|
+
Result->SetStringField(TEXT("actorPath"), Actor->GetPathName());
|
|
377
408
|
Result->SetStringField(TEXT("body"), Body->GetName());
|
|
378
409
|
Result->SetNumberField(TEXT("rebound"), Rebound);
|
|
379
410
|
Result->SetArrayField(TEXT("components"), Bound);
|
|
@@ -385,12 +416,14 @@ TSharedPtr<FJsonValue> FAnimationHandlers::PreviewAnimation(const TSharedPtr<FJs
|
|
|
385
416
|
{
|
|
386
417
|
REQUIRE_EDITOR_WORLD(World);
|
|
387
418
|
FString ActorLabel;
|
|
388
|
-
if (auto Err =
|
|
419
|
+
if (auto Err = RequireStringAlt(Params, TEXT("actorLabel"), TEXT("actorPath"), ActorLabel)) return Err;
|
|
389
420
|
bool bEnabled = true;
|
|
390
421
|
Params->TryGetBoolField(TEXT("enabled"), bEnabled);
|
|
391
422
|
|
|
392
|
-
|
|
393
|
-
|
|
423
|
+
TSharedPtr<FJsonValue> ActorErr;
|
|
424
|
+
AActor* Actor = MCPResolveActor(World, Params, ActorErr);
|
|
425
|
+
if (!Actor) return ActorErr;
|
|
426
|
+
ActorLabel = Actor->GetActorLabel();
|
|
394
427
|
|
|
395
428
|
TArray<USkeletalMeshComponent*> Comps;
|
|
396
429
|
Actor->GetComponents<USkeletalMeshComponent>(Comps);
|
|
@@ -413,12 +446,185 @@ TSharedPtr<FJsonValue> FAnimationHandlers::PreviewAnimation(const TSharedPtr<FJs
|
|
|
413
446
|
auto Result = MCPSuccess();
|
|
414
447
|
MCPSetUpdated(Result);
|
|
415
448
|
Result->SetStringField(TEXT("actorLabel"), ActorLabel);
|
|
449
|
+
Result->SetStringField(TEXT("actorPath"), Actor->GetPathName());
|
|
416
450
|
Result->SetBoolField(TEXT("enabled"), bEnabled);
|
|
417
451
|
Result->SetNumberField(TEXT("componentsUpdated"), Updated);
|
|
418
452
|
|
|
419
453
|
TSharedPtr<FJsonObject> Payload = MakeShared<FJsonObject>();
|
|
420
454
|
Payload->SetStringField(TEXT("actorLabel"), ActorLabel);
|
|
455
|
+
Payload->SetStringField(TEXT("actorPath"), Actor->GetPathName());
|
|
421
456
|
Payload->SetBoolField(TEXT("enabled"), !bEnabled);
|
|
422
457
|
MCPSetRollback(Result, TEXT("preview_animation"), Payload);
|
|
423
458
|
return MCPResult(Result);
|
|
424
459
|
}
|
|
460
|
+
|
|
461
|
+
|
|
462
|
+
// #922/#926: the EVALUATED pose off a live SkeletalMeshComponent, in the editor
|
|
463
|
+
// world or in PIE.
|
|
464
|
+
//
|
|
465
|
+
// get_bone_transforms reads a skeleton's REFERENCE pose, which is the read that
|
|
466
|
+
// looks correct while the running instance is wrong: in #922 a character lay
|
|
467
|
+
// flat on the floor and every transform the bridge could show read clean,
|
|
468
|
+
// because none of them were the pose the component was actually holding.
|
|
469
|
+
// get_bone_transform answers for one bone at a time. This answers for a set, off
|
|
470
|
+
// the component's own evaluated arrays, and reports what is driving the
|
|
471
|
+
// evaluation next to the numbers, so a flat character and a stopped anim
|
|
472
|
+
// instance are distinguishable from one call.
|
|
473
|
+
TSharedPtr<FJsonValue> FAnimationHandlers::GetLiveBoneTransforms(const TSharedPtr<FJsonObject>& Params)
|
|
474
|
+
{
|
|
475
|
+
// How many bones one response carries. A humanoid skeleton is a few hundred,
|
|
476
|
+
// so the whole thing fits; a crowd-scale or facial rig can be far more.
|
|
477
|
+
constexpr int32 LiveBoneTransformCap = 1000;
|
|
478
|
+
|
|
479
|
+
FString ActorLabel;
|
|
480
|
+
if (auto Err = RequireStringAlt(Params, TEXT("actorLabel"), TEXT("actorPath"), ActorLabel)) return Err;
|
|
481
|
+
const FString ComponentName = OptionalString(Params, TEXT("componentName"));
|
|
482
|
+
const FString Space = OptionalString(Params, TEXT("space"), TEXT("world")).ToLower();
|
|
483
|
+
if (!(Space == TEXT("world") || Space == TEXT("component") || Space == TEXT("local")))
|
|
484
|
+
{
|
|
485
|
+
return MCPError(TEXT("space must be 'world' (default), 'component', or 'local'"));
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
UWorld* World = nullptr;
|
|
489
|
+
AActor* Actor = nullptr;
|
|
490
|
+
FString ResolvedWorldScope;
|
|
491
|
+
if (auto Err = ResolveSkeletalActorForQuery(Params, ActorLabel, TEXT("auto"), World, Actor, ResolvedWorldScope)) return Err;
|
|
492
|
+
// A caller who passed only actorPath left ActorLabel holding the path, and
|
|
493
|
+
// every message below reads better naming the actor that answered (#983).
|
|
494
|
+
ActorLabel = Actor->GetActorLabel();
|
|
495
|
+
USkeletalMeshComponent* SK = ResolveSkeletalMeshComp(Actor, ComponentName);
|
|
496
|
+
if (!SK) return MakeSkeletalComponentNotFoundError(Actor, ActorLabel, ComponentName);
|
|
497
|
+
USkeletalMesh* Mesh = SK->GetSkeletalMeshAsset();
|
|
498
|
+
if (!Mesh)
|
|
499
|
+
{
|
|
500
|
+
return MCPError(FString::Printf(
|
|
501
|
+
TEXT("SkeletalMeshComponent '%s' on actor '%s' has no SkeletalMesh asset"), *SK->GetName(), *ActorLabel));
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
const FReferenceSkeleton& RefSkeleton = Mesh->GetRefSkeleton();
|
|
505
|
+
|
|
506
|
+
// boneNames selects a subset; omitting it returns every bone, which is what a
|
|
507
|
+
// caller diagnosing a pose wants and is a few hundred entries on a character.
|
|
508
|
+
TArray<FName> RequestedBones;
|
|
509
|
+
const TArray<TSharedPtr<FJsonValue>>* BonesArray = nullptr;
|
|
510
|
+
if (Params->TryGetArrayField(TEXT("boneNames"), BonesArray) && BonesArray)
|
|
511
|
+
{
|
|
512
|
+
for (const TSharedPtr<FJsonValue>& Entry : *BonesArray)
|
|
513
|
+
{
|
|
514
|
+
if (!Entry.IsValid()) continue;
|
|
515
|
+
const FString Name = Entry->AsString();
|
|
516
|
+
if (!Name.IsEmpty()) RequestedBones.Add(FName(*Name));
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
if (RequestedBones.Num() == 0)
|
|
520
|
+
{
|
|
521
|
+
for (int32 BoneIndex = 0; BoneIndex < RefSkeleton.GetNum(); ++BoneIndex)
|
|
522
|
+
{
|
|
523
|
+
RequestedBones.Add(RefSkeleton.GetBoneName(BoneIndex));
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
if (RequestedBones.Num() > LiveBoneTransformCap)
|
|
527
|
+
{
|
|
528
|
+
return MCPError(FString::Printf(
|
|
529
|
+
TEXT("%d bones requested, over the %d limit. Pass 'boneNames' with the bones you need."),
|
|
530
|
+
RequestedBones.Num(), LiveBoneTransformCap));
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
const TArray<FTransform>& ComponentSpace = SK->GetComponentSpaceTransforms();
|
|
534
|
+
const TArray<FTransform> BoneSpace = SK->GetBoneSpaceTransforms();
|
|
535
|
+
|
|
536
|
+
TArray<TSharedPtr<FJsonValue>> Bones;
|
|
537
|
+
TArray<TSharedPtr<FJsonValue>> Missing;
|
|
538
|
+
Bones.Reserve(RequestedBones.Num());
|
|
539
|
+
for (const FName& BoneName : RequestedBones)
|
|
540
|
+
{
|
|
541
|
+
const int32 BoneIndex = SK->GetBoneIndex(BoneName);
|
|
542
|
+
if (BoneIndex == INDEX_NONE)
|
|
543
|
+
{
|
|
544
|
+
Missing.Add(MakeShared<FJsonValueString>(BoneName.ToString()));
|
|
545
|
+
continue;
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
FTransform Transform;
|
|
549
|
+
if (Space == TEXT("world"))
|
|
550
|
+
{
|
|
551
|
+
Transform = SK->GetBoneTransform(BoneIndex);
|
|
552
|
+
}
|
|
553
|
+
else if (Space == TEXT("component"))
|
|
554
|
+
{
|
|
555
|
+
if (!ComponentSpace.IsValidIndex(BoneIndex))
|
|
556
|
+
{
|
|
557
|
+
Missing.Add(MakeShared<FJsonValueString>(BoneName.ToString()));
|
|
558
|
+
continue;
|
|
559
|
+
}
|
|
560
|
+
Transform = ComponentSpace[BoneIndex];
|
|
561
|
+
}
|
|
562
|
+
else
|
|
563
|
+
{
|
|
564
|
+
if (!BoneSpace.IsValidIndex(BoneIndex))
|
|
565
|
+
{
|
|
566
|
+
Missing.Add(MakeShared<FJsonValueString>(BoneName.ToString()));
|
|
567
|
+
continue;
|
|
568
|
+
}
|
|
569
|
+
Transform = BoneSpace[BoneIndex];
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
TSharedPtr<FJsonObject> BoneObj = MakeShared<FJsonObject>();
|
|
573
|
+
BoneObj->SetStringField(TEXT("name"), BoneName.ToString());
|
|
574
|
+
BoneObj->SetNumberField(TEXT("index"), BoneIndex);
|
|
575
|
+
const int32 ParentIndex = RefSkeleton.GetParentIndex(BoneIndex);
|
|
576
|
+
BoneObj->SetNumberField(TEXT("parentIndex"), ParentIndex);
|
|
577
|
+
if (ParentIndex != INDEX_NONE)
|
|
578
|
+
{
|
|
579
|
+
BoneObj->SetStringField(TEXT("parentName"), RefSkeleton.GetBoneName(ParentIndex).ToString());
|
|
580
|
+
}
|
|
581
|
+
BoneObj->SetObjectField(TEXT("location"), MCPVec3ToJsonObject(Transform.GetLocation()));
|
|
582
|
+
BoneObj->SetObjectField(TEXT("rotation"), MCPRotatorToJsonObject(Transform.GetRotation().Rotator()));
|
|
583
|
+
BoneObj->SetObjectField(TEXT("scale"), MCPVec3ToJsonObject(Transform.GetScale3D()));
|
|
584
|
+
Bones.Add(MakeShared<FJsonValueObject>(BoneObj));
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
auto Result = MCPSuccess();
|
|
588
|
+
Result->SetStringField(TEXT("actorLabel"), ActorLabel);
|
|
589
|
+
Result->SetStringField(TEXT("actorName"), Actor->GetName());
|
|
590
|
+
Result->SetStringField(TEXT("actorPath"), Actor->GetPathName());
|
|
591
|
+
Result->SetStringField(TEXT("world"), ResolvedWorldScope);
|
|
592
|
+
Result->SetStringField(TEXT("worldName"), World ? World->GetName() : TEXT(""));
|
|
593
|
+
AddSkeletalComponentMetadata(Result, SK);
|
|
594
|
+
Result->SetStringField(TEXT("space"), Space);
|
|
595
|
+
Result->SetNumberField(TEXT("boneCount"), Bones.Num());
|
|
596
|
+
Result->SetArrayField(TEXT("bones"), Bones);
|
|
597
|
+
if (Missing.Num() > 0)
|
|
598
|
+
{
|
|
599
|
+
Result->SetArrayField(TEXT("unresolvedBones"), Missing);
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
// The component's own placement, so a component-space read lifts to world
|
|
603
|
+
// without a second call, and a component transform that reads clean while
|
|
604
|
+
// the pose does not is visible side by side (#922).
|
|
605
|
+
const FTransform ComponentToWorld = SK->GetComponentTransform();
|
|
606
|
+
TSharedPtr<FJsonObject> ComponentTransform = MakeShared<FJsonObject>();
|
|
607
|
+
ComponentTransform->SetObjectField(TEXT("location"), MCPVec3ToJsonObject(ComponentToWorld.GetLocation()));
|
|
608
|
+
ComponentTransform->SetObjectField(TEXT("rotation"), MCPRotatorToJsonObject(ComponentToWorld.GetRotation().Rotator()));
|
|
609
|
+
ComponentTransform->SetObjectField(TEXT("scale"), MCPVec3ToJsonObject(ComponentToWorld.GetScale3D()));
|
|
610
|
+
Result->SetObjectField(TEXT("componentTransform"), ComponentTransform);
|
|
611
|
+
|
|
612
|
+
// What is driving the pose. A stopped or absent anim instance is the usual
|
|
613
|
+
// reason an evaluated read matches the reference pose exactly.
|
|
614
|
+
TSharedPtr<FJsonObject> Evaluation = MakeShared<FJsonObject>();
|
|
615
|
+
const EAnimationMode::Type AnimationMode = SK->GetAnimationMode();
|
|
616
|
+
Evaluation->SetStringField(TEXT("animationMode"),
|
|
617
|
+
AnimationMode == EAnimationMode::AnimationBlueprint ? TEXT("AnimationBlueprint")
|
|
618
|
+
: AnimationMode == EAnimationMode::AnimationSingleNode ? TEXT("AnimationSingleNode")
|
|
619
|
+
: TEXT("AnimationCustomMode"));
|
|
620
|
+
if (UAnimInstance* AnimInstance = SK->GetAnimInstance())
|
|
621
|
+
{
|
|
622
|
+
Evaluation->SetStringField(TEXT("animInstanceClass"), AnimInstance->GetClass()->GetPathName());
|
|
623
|
+
}
|
|
624
|
+
Evaluation->SetNumberField(TEXT("componentSpaceTransformCount"), ComponentSpace.Num());
|
|
625
|
+
Evaluation->SetNumberField(TEXT("refSkeletonBoneCount"), RefSkeleton.GetNum());
|
|
626
|
+
Evaluation->SetBoolField(TEXT("componentVisible"), SK->IsVisible());
|
|
627
|
+
Result->SetObjectField(TEXT("evaluation"), Evaluation);
|
|
628
|
+
|
|
629
|
+
return MCPResult(Result);
|
|
630
|
+
}
|