ue-mcp 1.2.3 → 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/index.js +41 -2
- package/dist/index.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/plugin/loader.d.ts +4 -0
- package/dist/plugin/loader.js +22 -8
- package/dist/plugin/loader.js.map +1 -1
- package/dist/plugin/manifest.d.ts +72 -52
- package/dist/plugin/manifest.js +118 -21
- package/dist/plugin/manifest.js.map +1 -1
- package/dist/plugin-cli.js +16 -3
- package/dist/plugin-cli.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/plugins.js +2 -0
- package/dist/tools/plugins.js.map +1 -1
- package/dist/tools/project.js +47 -20
- package/dist/tools/project.js.map +1 -1
- package/dist/types.d.ts +24 -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
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
#include "SequencerHandlers.h"
|
|
2
|
+
#include "SequencerHandlers_Internal.h"
|
|
2
3
|
#include "HandlerRegistry.h"
|
|
3
4
|
#include "HandlerUtils.h"
|
|
4
5
|
|
|
5
6
|
#include "LevelSequenceEditorBlueprintLibrary.h"
|
|
6
7
|
#include "MovieSceneSequencePlayer.h"
|
|
8
|
+
#include "MovieSceneTimeUnit.h"
|
|
7
9
|
|
|
8
10
|
#include "Subsystems/AssetEditorSubsystem.h"
|
|
9
11
|
#include "HandlerAssetCreate.h"
|
|
@@ -21,6 +23,7 @@
|
|
|
21
23
|
#include "Sections/MovieScene3DAttachSection.h"
|
|
22
24
|
#include "Sections/MovieScene3DTransformSection.h"
|
|
23
25
|
#include "Sections/MovieSceneCameraCutSection.h"
|
|
26
|
+
#include "Channels/MovieSceneChannel.h"
|
|
24
27
|
#include "Channels/MovieSceneDoubleChannel.h"
|
|
25
28
|
#include "Channels/MovieSceneFloatChannel.h"
|
|
26
29
|
#include "Channels/MovieSceneChannelProxy.h"
|
|
@@ -43,6 +46,7 @@ void FSequencerHandlers::RegisterHandlers(FMCPHandlerRegistry& Registry)
|
|
|
43
46
|
Registry.RegisterHandler(TEXT("get_sequence_info"), &ReadSequenceInfo);
|
|
44
47
|
Registry.RegisterHandler(TEXT("add_sequence_track"), &AddTrack);
|
|
45
48
|
Registry.RegisterHandler(TEXT("play_sequence"), &SequenceControl);
|
|
49
|
+
Registry.RegisterHandler(TEXT("scrub_sequence"), &ScrubSequence);
|
|
46
50
|
Registry.RegisterHandler(TEXT("set_sequence_playback_range"), &SetPlaybackRange);
|
|
47
51
|
Registry.RegisterHandler(TEXT("add_sequence_section"), &AddSection);
|
|
48
52
|
Registry.RegisterHandler(TEXT("set_sequence_keyframes"), &SetKeyframes);
|
|
@@ -66,13 +70,16 @@ namespace
|
|
|
66
70
|
return Seq;
|
|
67
71
|
}
|
|
68
72
|
|
|
69
|
-
// Resolve (creating if needed) the
|
|
70
|
-
|
|
73
|
+
// Resolve (creating if needed) the possessable binding GUID for an actor the
|
|
74
|
+
// caller already selected. #983: the selection happens through
|
|
75
|
+
// MCPResolveActor at the call site, so a duplicated label is refused before
|
|
76
|
+
// a binding is created against the wrong actor.
|
|
77
|
+
bool ResolveActorBinding(ULevelSequence* Sequence, UMovieScene* MovieScene, AActor* TargetActor, FGuid& OutGuid, FString& OutError)
|
|
71
78
|
{
|
|
72
79
|
UWorld* World = GetEditorWorld();
|
|
73
80
|
if (!World) { OutError = TEXT("No editor world available"); return false; }
|
|
74
|
-
|
|
75
|
-
|
|
81
|
+
if (!TargetActor) { OutError = TEXT("Target actor is null"); return false; }
|
|
82
|
+
const FString ActorLabel = TargetActor->GetActorLabel();
|
|
76
83
|
|
|
77
84
|
for (int32 i = 0; i < MovieScene->GetPossessableCount(); ++i)
|
|
78
85
|
{
|
|
@@ -158,15 +165,30 @@ TSharedPtr<FJsonValue> FSequencerHandlers::ReadSequenceInfo(const TSharedPtr<FJs
|
|
|
158
165
|
Result->SetStringField(TEXT("name"), Sequence->GetName());
|
|
159
166
|
Result->SetStringField(TEXT("path"), Sequence->GetPathName());
|
|
160
167
|
|
|
161
|
-
|
|
162
|
-
FFrameRate
|
|
168
|
+
const FFrameRate DisplayRate = MovieScene->GetDisplayRate();
|
|
169
|
+
const FFrameRate TickResolution = MovieScene->GetTickResolution();
|
|
170
|
+
if (!UEMCP::SequencerInfo::IsUsableFrameRate(DisplayRate) ||
|
|
171
|
+
!UEMCP::SequencerInfo::IsUsableFrameRate(TickResolution))
|
|
172
|
+
{
|
|
173
|
+
return MCPError(FString::Printf(
|
|
174
|
+
TEXT("LevelSequence has invalid timing rates (displayRate=%d/%d, tickResolution=%d/%d)"),
|
|
175
|
+
DisplayRate.Numerator,
|
|
176
|
+
DisplayRate.Denominator,
|
|
177
|
+
TickResolution.Numerator,
|
|
178
|
+
TickResolution.Denominator));
|
|
179
|
+
}
|
|
180
|
+
|
|
163
181
|
TSharedPtr<FJsonObject> DisplayRateObj = MakeShared<FJsonObject>();
|
|
164
|
-
DisplayRateObj
|
|
165
|
-
DisplayRateObj->SetNumberField(TEXT("denominator"), DisplayRate.Denominator);
|
|
182
|
+
UEMCP::SequencerInfo::SetFrameRateFields(*DisplayRateObj, DisplayRate);
|
|
166
183
|
Result->SetObjectField(TEXT("displayRate"), DisplayRateObj);
|
|
167
184
|
|
|
168
|
-
|
|
169
|
-
|
|
185
|
+
TSharedPtr<FJsonObject> TickResolutionObj = MakeShared<FJsonObject>();
|
|
186
|
+
UEMCP::SequencerInfo::SetFrameRateFields(*TickResolutionObj, TickResolution);
|
|
187
|
+
Result->SetObjectField(TEXT("tickResolution"), TickResolutionObj);
|
|
188
|
+
|
|
189
|
+
// Keep the legacy startFrame/endFrame values in tick-resolution units.
|
|
190
|
+
// The explicit fields below remove that ambiguity without changing callers.
|
|
191
|
+
const TRange<FFrameNumber> PlaybackRange = MovieScene->GetPlaybackRange();
|
|
170
192
|
TSharedPtr<FJsonObject> RangeObj = MakeShared<FJsonObject>();
|
|
171
193
|
if (PlaybackRange.HasLowerBound())
|
|
172
194
|
{
|
|
@@ -176,27 +198,62 @@ TSharedPtr<FJsonValue> FSequencerHandlers::ReadSequenceInfo(const TSharedPtr<FJs
|
|
|
176
198
|
{
|
|
177
199
|
RangeObj->SetNumberField(TEXT("endFrame"), PlaybackRange.GetUpperBoundValue().Value);
|
|
178
200
|
}
|
|
201
|
+
UEMCP::SequencerInfo::SetTimingRangeFields(*RangeObj, PlaybackRange, TickResolution, DisplayRate);
|
|
179
202
|
Result->SetObjectField(TEXT("playbackRange"), RangeObj);
|
|
180
203
|
|
|
181
|
-
// #52: optional section-level detail (attach sockets, first transform key values)
|
|
182
204
|
const bool bIncludeDetails = OptionalBool(Params, TEXT("includeSectionDetails"));
|
|
205
|
+
UEMCP::SequencerInfo::FDetailBudget DetailBudget;
|
|
183
206
|
|
|
184
|
-
|
|
207
|
+
if (bIncludeDetails)
|
|
208
|
+
{
|
|
209
|
+
TSharedPtr<FJsonObject> LimitsObj = MakeShared<FJsonObject>();
|
|
210
|
+
LimitsObj->SetNumberField(TEXT("maxSections"), UEMCP::SequencerInfo::MaxDetailedSections);
|
|
211
|
+
LimitsObj->SetNumberField(TEXT("maxChannels"), UEMCP::SequencerInfo::MaxDetailedChannels);
|
|
212
|
+
LimitsObj->SetNumberField(TEXT("maxKeyTimes"), UEMCP::SequencerInfo::MaxDetailedKeyTimes);
|
|
213
|
+
LimitsObj->SetNumberField(TEXT("maxKeyTimesPerChannel"), UEMCP::SequencerInfo::MaxKeyTimesPerChannel);
|
|
214
|
+
Result->SetObjectField(TEXT("detailLimits"), LimitsObj);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
auto ExtractSectionDetails = [&](UMovieSceneTrack* Track, const TSharedPtr<FJsonObject>& TrackObj)
|
|
185
218
|
{
|
|
186
219
|
if (!bIncludeDetails || !Track) return;
|
|
220
|
+
|
|
221
|
+
const TArray<UMovieSceneSection*>& AllSections = Track->GetAllSections();
|
|
187
222
|
TArray<TSharedPtr<FJsonValue>> SectionsArr;
|
|
188
|
-
for (
|
|
223
|
+
for (int32 SectionIndex = 0; SectionIndex < AllSections.Num(); ++SectionIndex)
|
|
189
224
|
{
|
|
190
|
-
if (
|
|
225
|
+
if (DetailBudget.Sections <= 0)
|
|
226
|
+
{
|
|
227
|
+
DetailBudget.bTruncated = true;
|
|
228
|
+
break;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
UMovieSceneSection* Section = AllSections[SectionIndex];
|
|
232
|
+
if (!Section)
|
|
233
|
+
{
|
|
234
|
+
DetailBudget.bTruncated = true;
|
|
235
|
+
continue;
|
|
236
|
+
}
|
|
237
|
+
--DetailBudget.Sections;
|
|
238
|
+
|
|
191
239
|
TSharedPtr<FJsonObject> SObj = MakeShared<FJsonObject>();
|
|
240
|
+
SObj->SetNumberField(TEXT("index"), SectionIndex);
|
|
241
|
+
SObj->SetStringField(TEXT("class"), Section->GetClass()->GetName());
|
|
242
|
+
UEMCP::SequencerInfo::SetTimingRangeFields(
|
|
243
|
+
*SObj,
|
|
244
|
+
Section->GetTrueRange(),
|
|
245
|
+
TickResolution,
|
|
246
|
+
DisplayRate);
|
|
247
|
+
|
|
192
248
|
if (UMovieScene3DAttachSection* Attach = Cast<UMovieScene3DAttachSection>(Section))
|
|
193
249
|
{
|
|
194
250
|
SObj->SetStringField(TEXT("attachSocket"), Attach->AttachSocketName.ToString());
|
|
195
251
|
SObj->SetStringField(TEXT("attachComponent"), Attach->AttachComponentName.ToString());
|
|
196
252
|
}
|
|
197
|
-
|
|
253
|
+
|
|
254
|
+
const FMovieSceneChannelProxy& Proxy = Section->GetChannelProxy();
|
|
255
|
+
if (Cast<UMovieScene3DTransformSection>(Section))
|
|
198
256
|
{
|
|
199
|
-
FMovieSceneChannelProxy& Proxy = Xf->GetChannelProxy();
|
|
200
257
|
TArray<FName> ChannelNames = {
|
|
201
258
|
TEXT("Location.X"), TEXT("Location.Y"), TEXT("Location.Z"),
|
|
202
259
|
TEXT("Rotation.X"), TEXT("Rotation.Y"), TEXT("Rotation.Z"),
|
|
@@ -229,12 +286,136 @@ TSharedPtr<FJsonValue> FSequencerHandlers::ReadSequenceInfo(const TSharedPtr<FJs
|
|
|
229
286
|
}
|
|
230
287
|
SObj->SetObjectField(TEXT("firstKeyValues"), FirstKeys);
|
|
231
288
|
}
|
|
232
|
-
|
|
289
|
+
|
|
290
|
+
const int32 ChannelCount = Proxy.NumChannels();
|
|
291
|
+
TArray<TSharedPtr<FJsonValue>> ChannelsArr;
|
|
292
|
+
bool bStopChannels = false;
|
|
293
|
+
for (const FMovieSceneChannelEntry& Entry : Proxy.GetAllEntries())
|
|
294
|
+
{
|
|
295
|
+
const FString ChannelType = Entry.GetChannelTypeName().ToString();
|
|
296
|
+
const TArrayView<FMovieSceneChannel* const> Channels = Entry.GetChannels();
|
|
297
|
+
const TArrayView<const FMovieSceneChannelMetaData> MetaData = Entry.GetMetaData();
|
|
298
|
+
|
|
299
|
+
for (int32 ChannelIndex = 0; ChannelIndex < Channels.Num(); ++ChannelIndex)
|
|
300
|
+
{
|
|
301
|
+
if (DetailBudget.Channels <= 0)
|
|
302
|
+
{
|
|
303
|
+
DetailBudget.bTruncated = true;
|
|
304
|
+
bStopChannels = true;
|
|
305
|
+
break;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
FMovieSceneChannel* Channel = Channels[ChannelIndex];
|
|
309
|
+
if (!Channel)
|
|
310
|
+
{
|
|
311
|
+
DetailBudget.bTruncated = true;
|
|
312
|
+
continue;
|
|
313
|
+
}
|
|
314
|
+
--DetailBudget.Channels;
|
|
315
|
+
|
|
316
|
+
FString ChannelName;
|
|
317
|
+
if (MetaData.IsValidIndex(ChannelIndex) && !MetaData[ChannelIndex].Name.IsNone())
|
|
318
|
+
{
|
|
319
|
+
ChannelName = MetaData[ChannelIndex].Name.ToString();
|
|
320
|
+
}
|
|
321
|
+
else
|
|
322
|
+
{
|
|
323
|
+
ChannelName = FString::Printf(TEXT("%s[%d]"), *ChannelType, ChannelIndex);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
TArray<FFrameNumber> KeyTimes;
|
|
327
|
+
if (DetailBudget.KeyTimes > 0)
|
|
328
|
+
{
|
|
329
|
+
Channel->GetKeys(TRange<FFrameNumber>::All(), &KeyTimes, nullptr);
|
|
330
|
+
KeyTimes.Sort([](const FFrameNumber A, const FFrameNumber B)
|
|
331
|
+
{
|
|
332
|
+
return A.Value < B.Value;
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
const int32 KeyCount = FMath::Max(Channel->GetNumKeys(), KeyTimes.Num());
|
|
337
|
+
const int32 KeyTimesToReturn = FMath::Min3(
|
|
338
|
+
KeyTimes.Num(),
|
|
339
|
+
UEMCP::SequencerInfo::MaxKeyTimesPerChannel,
|
|
340
|
+
DetailBudget.KeyTimes);
|
|
341
|
+
|
|
342
|
+
TArray<TSharedPtr<FJsonValue>> KeyTimesArr;
|
|
343
|
+
KeyTimesArr.Reserve(KeyTimesToReturn);
|
|
344
|
+
for (int32 KeyIndex = 0; KeyIndex < KeyTimesToReturn; ++KeyIndex)
|
|
345
|
+
{
|
|
346
|
+
KeyTimesArr.Add(MakeShared<FJsonValueObject>(
|
|
347
|
+
UEMCP::SequencerInfo::MakeKeyTimeObject(
|
|
348
|
+
KeyTimes[KeyIndex],
|
|
349
|
+
TickResolution,
|
|
350
|
+
DisplayRate)));
|
|
351
|
+
}
|
|
352
|
+
DetailBudget.KeyTimes -= KeyTimesToReturn;
|
|
353
|
+
|
|
354
|
+
const bool bKeyTimesTruncated = KeyTimesToReturn < KeyCount;
|
|
355
|
+
DetailBudget.bTruncated |= bKeyTimesTruncated;
|
|
356
|
+
|
|
357
|
+
TSharedPtr<FJsonObject> ChannelObj = MakeShared<FJsonObject>();
|
|
358
|
+
ChannelObj->SetNumberField(TEXT("index"), ChannelIndex);
|
|
359
|
+
ChannelObj->SetStringField(TEXT("name"), ChannelName);
|
|
360
|
+
ChannelObj->SetStringField(TEXT("type"), ChannelType);
|
|
361
|
+
ChannelObj->SetNumberField(TEXT("keyCount"), KeyCount);
|
|
362
|
+
ChannelObj->SetArrayField(TEXT("keyTimes"), KeyTimesArr);
|
|
363
|
+
ChannelObj->SetBoolField(TEXT("keyTimesTruncated"), bKeyTimesTruncated);
|
|
364
|
+
ChannelsArr.Add(MakeShared<FJsonValueObject>(ChannelObj));
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
if (bStopChannels) break;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
const bool bChannelsTruncated = ChannelsArr.Num() < ChannelCount;
|
|
371
|
+
DetailBudget.bTruncated |= bChannelsTruncated;
|
|
372
|
+
SObj->SetNumberField(TEXT("channelCount"), ChannelCount);
|
|
373
|
+
SObj->SetArrayField(TEXT("channels"), ChannelsArr);
|
|
374
|
+
SObj->SetBoolField(TEXT("channelsTruncated"), bChannelsTruncated);
|
|
233
375
|
SectionsArr.Add(MakeShared<FJsonValueObject>(SObj));
|
|
234
376
|
}
|
|
377
|
+
|
|
378
|
+
const bool bSectionsTruncated = SectionsArr.Num() < AllSections.Num();
|
|
379
|
+
DetailBudget.bTruncated |= bSectionsTruncated;
|
|
235
380
|
TrackObj->SetArrayField(TEXT("sections"), SectionsArr);
|
|
381
|
+
TrackObj->SetBoolField(TEXT("sectionsTruncated"), bSectionsTruncated);
|
|
382
|
+
};
|
|
383
|
+
|
|
384
|
+
auto MakeTrackObject = [&](UMovieSceneTrack* Track) -> TSharedPtr<FJsonObject>
|
|
385
|
+
{
|
|
386
|
+
TSharedPtr<FJsonObject> TrackObj = MakeShared<FJsonObject>();
|
|
387
|
+
TrackObj->SetStringField(TEXT("name"), Track->GetTrackName().ToString());
|
|
388
|
+
TrackObj->SetStringField(TEXT("class"), Track->GetClass()->GetName());
|
|
389
|
+
TrackObj->SetNumberField(TEXT("sectionCount"), Track->GetAllSections().Num());
|
|
390
|
+
ExtractSectionDetails(Track, TrackObj);
|
|
391
|
+
return TrackObj;
|
|
236
392
|
};
|
|
237
393
|
|
|
394
|
+
// Camera cuts are stored separately from UMovieScene::GetTracks(). Emit the
|
|
395
|
+
// camera-cut track first so the root-track inspection is never hidden behind
|
|
396
|
+
// the bounded detail budget, then append the ordinary root tracks once each.
|
|
397
|
+
TArray<UMovieSceneTrack*> RootTracks;
|
|
398
|
+
if (UMovieSceneTrack* CameraCutTrack = MovieScene->GetCameraCutTrack())
|
|
399
|
+
{
|
|
400
|
+
RootTracks.Add(CameraCutTrack);
|
|
401
|
+
}
|
|
402
|
+
for (UMovieSceneTrack* Track : MovieScene->GetTracks())
|
|
403
|
+
{
|
|
404
|
+
if (Track && !RootTracks.Contains(Track))
|
|
405
|
+
{
|
|
406
|
+
RootTracks.Add(Track);
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
TArray<TSharedPtr<FJsonValue>> MasterTracksArray;
|
|
411
|
+
for (UMovieSceneTrack* Track : RootTracks)
|
|
412
|
+
{
|
|
413
|
+
if (!Track) continue;
|
|
414
|
+
MasterTracksArray.Add(MakeShared<FJsonValueObject>(MakeTrackObject(Track)));
|
|
415
|
+
}
|
|
416
|
+
Result->SetArrayField(TEXT("masterTracks"), MasterTracksArray);
|
|
417
|
+
Result->SetNumberField(TEXT("masterTrackCount"), MasterTracksArray.Num());
|
|
418
|
+
|
|
238
419
|
// #556: collect the Sequencer binding tags (group labels) that reference a
|
|
239
420
|
// given binding guid, from the MovieScene's tagged-binding map.
|
|
240
421
|
auto TagsForGuid = [MovieScene](const FGuid& Guid) -> TArray<TSharedPtr<FJsonValue>>
|
|
@@ -254,80 +435,47 @@ TSharedPtr<FJsonValue> FSequencerHandlers::ReadSequenceInfo(const TSharedPtr<FJs
|
|
|
254
435
|
return Out;
|
|
255
436
|
};
|
|
256
437
|
|
|
257
|
-
// Bindings (possessables and spawnables)
|
|
258
438
|
TArray<TSharedPtr<FJsonValue>> BindingsArray;
|
|
259
|
-
|
|
439
|
+
auto AppendBinding = [&](const FString& Name, const FGuid& Guid, const TCHAR* Type)
|
|
260
440
|
{
|
|
261
|
-
const FMovieScenePossessable& Possessable = MovieScene->GetPossessable(i);
|
|
262
441
|
TSharedPtr<FJsonObject> BindingObj = MakeShared<FJsonObject>();
|
|
263
|
-
BindingObj->SetStringField(TEXT("name"),
|
|
264
|
-
BindingObj->SetStringField(TEXT("guid"),
|
|
265
|
-
BindingObj->SetStringField(TEXT("type"),
|
|
266
|
-
BindingObj->SetArrayField(TEXT("tags"), TagsForGuid(
|
|
442
|
+
BindingObj->SetStringField(TEXT("name"), Name);
|
|
443
|
+
BindingObj->SetStringField(TEXT("guid"), Guid.ToString());
|
|
444
|
+
BindingObj->SetStringField(TEXT("type"), Type);
|
|
445
|
+
BindingObj->SetArrayField(TEXT("tags"), TagsForGuid(Guid));
|
|
267
446
|
|
|
268
|
-
// List tracks for this binding (with optional section detail)
|
|
269
447
|
TArray<TSharedPtr<FJsonValue>> TrackArr;
|
|
270
|
-
const FMovieSceneBinding* Binding = MovieScene->FindBinding(
|
|
448
|
+
const FMovieSceneBinding* Binding = MovieScene->FindBinding(Guid);
|
|
271
449
|
if (Binding)
|
|
272
450
|
{
|
|
273
451
|
for (UMovieSceneTrack* Track : Binding->GetTracks())
|
|
274
452
|
{
|
|
275
453
|
if (!Track) continue;
|
|
276
|
-
|
|
277
|
-
TObj->SetStringField(TEXT("class"), Track->GetClass()->GetName());
|
|
278
|
-
TObj->SetStringField(TEXT("name"), Track->GetTrackName().ToString());
|
|
279
|
-
ExtractSectionDetails(Track, TObj);
|
|
280
|
-
TrackArr.Add(MakeShared<FJsonValueObject>(TObj));
|
|
454
|
+
TrackArr.Add(MakeShared<FJsonValueObject>(MakeTrackObject(Track)));
|
|
281
455
|
}
|
|
282
456
|
}
|
|
283
457
|
BindingObj->SetArrayField(TEXT("tracks"), TrackArr);
|
|
284
|
-
|
|
285
458
|
BindingsArray.Add(MakeShared<FJsonValueObject>(BindingObj));
|
|
459
|
+
};
|
|
460
|
+
|
|
461
|
+
for (int32 i = 0; i < MovieScene->GetPossessableCount(); ++i)
|
|
462
|
+
{
|
|
463
|
+
const FMovieScenePossessable& Possessable = MovieScene->GetPossessable(i);
|
|
464
|
+
AppendBinding(Possessable.GetName(), Possessable.GetGuid(), TEXT("possessable"));
|
|
286
465
|
}
|
|
287
466
|
|
|
288
467
|
for (int32 i = 0; i < MovieScene->GetSpawnableCount(); ++i)
|
|
289
468
|
{
|
|
290
469
|
const FMovieSceneSpawnable& Spawnable = MovieScene->GetSpawnable(i);
|
|
291
|
-
|
|
292
|
-
BindingObj->SetStringField(TEXT("name"), Spawnable.GetName());
|
|
293
|
-
BindingObj->SetStringField(TEXT("guid"), Spawnable.GetGuid().ToString());
|
|
294
|
-
BindingObj->SetStringField(TEXT("type"), TEXT("spawnable"));
|
|
295
|
-
BindingObj->SetArrayField(TEXT("tags"), TagsForGuid(Spawnable.GetGuid()));
|
|
296
|
-
|
|
297
|
-
TArray<TSharedPtr<FJsonValue>> TrackArr;
|
|
298
|
-
const FMovieSceneBinding* Binding = MovieScene->FindBinding(Spawnable.GetGuid());
|
|
299
|
-
if (Binding)
|
|
300
|
-
{
|
|
301
|
-
for (UMovieSceneTrack* Track : Binding->GetTracks())
|
|
302
|
-
{
|
|
303
|
-
if (!Track) continue;
|
|
304
|
-
TSharedPtr<FJsonObject> TObj = MakeShared<FJsonObject>();
|
|
305
|
-
TObj->SetStringField(TEXT("class"), Track->GetClass()->GetName());
|
|
306
|
-
TObj->SetStringField(TEXT("name"), Track->GetTrackName().ToString());
|
|
307
|
-
ExtractSectionDetails(Track, TObj);
|
|
308
|
-
TrackArr.Add(MakeShared<FJsonValueObject>(TObj));
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
BindingObj->SetArrayField(TEXT("tracks"), TrackArr);
|
|
312
|
-
|
|
313
|
-
BindingsArray.Add(MakeShared<FJsonValueObject>(BindingObj));
|
|
470
|
+
AppendBinding(Spawnable.GetName(), Spawnable.GetGuid(), TEXT("spawnable"));
|
|
314
471
|
}
|
|
315
472
|
Result->SetArrayField(TEXT("bindings"), BindingsArray);
|
|
316
473
|
Result->SetNumberField(TEXT("bindingCount"), BindingsArray.Num());
|
|
317
474
|
|
|
318
|
-
|
|
319
|
-
TArray<TSharedPtr<FJsonValue>> MasterTracksArray;
|
|
320
|
-
for (UMovieSceneTrack* Track : MovieScene->GetTracks())
|
|
475
|
+
if (bIncludeDetails)
|
|
321
476
|
{
|
|
322
|
-
|
|
323
|
-
TSharedPtr<FJsonObject> TrackObj = MakeShared<FJsonObject>();
|
|
324
|
-
TrackObj->SetStringField(TEXT("name"), Track->GetTrackName().ToString());
|
|
325
|
-
TrackObj->SetStringField(TEXT("class"), Track->GetClass()->GetName());
|
|
326
|
-
TrackObj->SetNumberField(TEXT("sectionCount"), Track->GetAllSections().Num());
|
|
327
|
-
MasterTracksArray.Add(MakeShared<FJsonValueObject>(TrackObj));
|
|
477
|
+
Result->SetBoolField(TEXT("detailsTruncated"), DetailBudget.bTruncated);
|
|
328
478
|
}
|
|
329
|
-
Result->SetArrayField(TEXT("masterTracks"), MasterTracksArray);
|
|
330
|
-
Result->SetNumberField(TEXT("masterTrackCount"), MasterTracksArray.Num());
|
|
331
479
|
|
|
332
480
|
return MCPResult(Result);
|
|
333
481
|
}
|
|
@@ -390,18 +538,18 @@ TSharedPtr<FJsonValue> FSequencerHandlers::AddTrack(const TSharedPtr<FJsonObject
|
|
|
390
538
|
|
|
391
539
|
// Check if we should add to an actor binding or as a master track
|
|
392
540
|
FString ActorLabel = OptionalString(Params, TEXT("actorLabel"));
|
|
541
|
+
const FString ActorPath = OptionalString(Params, TEXT("actorPath"));
|
|
393
542
|
auto Result = MCPSuccess();
|
|
394
543
|
|
|
395
|
-
if (!ActorLabel.IsEmpty())
|
|
544
|
+
if (!ActorLabel.IsEmpty() || !ActorPath.IsEmpty())
|
|
396
545
|
{
|
|
397
546
|
// Find the binding for this actor
|
|
398
547
|
REQUIRE_EDITOR_WORLD(World);
|
|
399
548
|
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
}
|
|
549
|
+
TSharedPtr<FJsonValue> ActorErr;
|
|
550
|
+
AActor* TargetActor = MCPResolveActor(World, Params, ActorErr);
|
|
551
|
+
if (!TargetActor) return ActorErr;
|
|
552
|
+
ActorLabel = TargetActor->GetActorLabel();
|
|
405
553
|
|
|
406
554
|
// Find or create a binding for this actor
|
|
407
555
|
FGuid BindingGuid;
|
|
@@ -431,6 +579,7 @@ TSharedPtr<FJsonValue> FSequencerHandlers::AddTrack(const TSharedPtr<FJsonObject
|
|
|
431
579
|
{
|
|
432
580
|
MCPSetExisted(Result);
|
|
433
581
|
Result->SetStringField(TEXT("actorLabel"), ActorLabel);
|
|
582
|
+
Result->SetStringField(TEXT("actorPath"), TargetActor->GetPathName());
|
|
434
583
|
Result->SetStringField(TEXT("bindingGuid"), BindingGuid.ToString());
|
|
435
584
|
Result->SetStringField(TEXT("trackType"), TrackType);
|
|
436
585
|
Result->SetStringField(TEXT("trackClass"), ExistingTrack->GetClass()->GetName());
|
|
@@ -447,6 +596,7 @@ TSharedPtr<FJsonValue> FSequencerHandlers::AddTrack(const TSharedPtr<FJsonObject
|
|
|
447
596
|
|
|
448
597
|
MCPSetCreated(Result);
|
|
449
598
|
Result->SetStringField(TEXT("actorLabel"), ActorLabel);
|
|
599
|
+
Result->SetStringField(TEXT("actorPath"), TargetActor->GetPathName());
|
|
450
600
|
Result->SetStringField(TEXT("bindingGuid"), BindingGuid.ToString());
|
|
451
601
|
Result->SetStringField(TEXT("trackType"), TrackType);
|
|
452
602
|
Result->SetStringField(TEXT("trackClass"), NewTrack->GetClass()->GetName());
|
|
@@ -559,6 +709,152 @@ TSharedPtr<FJsonValue> FSequencerHandlers::SequenceControl(const TSharedPtr<FJso
|
|
|
559
709
|
return MCPResult(Result);
|
|
560
710
|
}
|
|
561
711
|
|
|
712
|
+
// scrub_sequence (#881) - park the playhead on an exact time and evaluate there.
|
|
713
|
+
//
|
|
714
|
+
// Building a data-driven cinematic means capturing the evaluated world at a
|
|
715
|
+
// known frame, and play_sequence only offers play/pause/stop: realtime playback
|
|
716
|
+
// races capture_scene_png and the frame that lands is whatever the tick gave
|
|
717
|
+
// you. This puts the playhead on the frame that was asked for and forces the
|
|
718
|
+
// evaluation before answering, which is what makes scrub-then-capture
|
|
719
|
+
// reproducible.
|
|
720
|
+
//
|
|
721
|
+
// A separate action rather than a fourth verb on play_sequence: sequenceAction
|
|
722
|
+
// is a closed enum of play|pause|stop and widening it is a contract change on
|
|
723
|
+
// the transport, while a scrub carries a time argument the transport verbs have
|
|
724
|
+
// no use for.
|
|
725
|
+
TSharedPtr<FJsonValue> FSequencerHandlers::ScrubSequence(const TSharedPtr<FJsonObject>& Params)
|
|
726
|
+
{
|
|
727
|
+
// The Sequencer scripting surface acts on whatever is currently open, so a
|
|
728
|
+
// named sequence has to be opened first or the scrub would move a different
|
|
729
|
+
// one. Same rule as play_sequence.
|
|
730
|
+
const FString RequestedPath = OptionalString(Params, TEXT("sequencePath"), OptionalString(Params, TEXT("assetPath")));
|
|
731
|
+
if (!RequestedPath.IsEmpty())
|
|
732
|
+
{
|
|
733
|
+
ULevelSequence* Sequence = LoadAssetByPath<ULevelSequence>(RequestedPath);
|
|
734
|
+
if (!Sequence)
|
|
735
|
+
{
|
|
736
|
+
return MCPError(FString::Printf(TEXT("Level Sequence not found: %s"), *RequestedPath));
|
|
737
|
+
}
|
|
738
|
+
if (!ULevelSequenceEditorBlueprintLibrary::OpenLevelSequence(Sequence))
|
|
739
|
+
{
|
|
740
|
+
return MCPError(FString::Printf(TEXT("Failed to open '%s' in Sequencer."), *Sequence->GetPathName()));
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
ULevelSequence* Current = ULevelSequenceEditorBlueprintLibrary::GetCurrentLevelSequence();
|
|
745
|
+
if (!Current)
|
|
746
|
+
{
|
|
747
|
+
return MCPError(TEXT("No Level Sequence is open in Sequencer. Pass sequencePath to open one, or open it in the editor first."));
|
|
748
|
+
}
|
|
749
|
+
UMovieScene* MovieScene = Current->GetMovieScene();
|
|
750
|
+
if (!MovieScene)
|
|
751
|
+
{
|
|
752
|
+
return MCPError(TEXT("LevelSequence has no MovieScene"));
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
const FFrameRate DisplayRate = MovieScene->GetDisplayRate();
|
|
756
|
+
const FFrameRate TickResolution = MovieScene->GetTickResolution();
|
|
757
|
+
|
|
758
|
+
// Two units are in play and confusing them is an 800x error, so the unit is
|
|
759
|
+
// named rather than guessed: 'display' is the frame number Sequencer shows,
|
|
760
|
+
// 'tick' is what get_sequence_info's playbackRange reports.
|
|
761
|
+
const FString TimeUnit = OptionalString(Params, TEXT("timeUnit"), TEXT("display")).ToLower();
|
|
762
|
+
if (TimeUnit != TEXT("display") && TimeUnit != TEXT("tick"))
|
|
763
|
+
{
|
|
764
|
+
return MCPError(FString::Printf(
|
|
765
|
+
TEXT("Unknown timeUnit '%s'. Use 'display' (the frame numbers Sequencer shows) or 'tick' (the units get_sequence_info's playbackRange reports)."),
|
|
766
|
+
*TimeUnit));
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
double RequestedSeconds = 0.0;
|
|
770
|
+
double RequestedFrame = 0.0;
|
|
771
|
+
const bool bHasSeconds = Params->TryGetNumberField(TEXT("seconds"), RequestedSeconds);
|
|
772
|
+
const bool bHasFrame = Params->TryGetNumberField(TEXT("frame"), RequestedFrame);
|
|
773
|
+
if (bHasSeconds == bHasFrame)
|
|
774
|
+
{
|
|
775
|
+
return MCPError(TEXT("Provide exactly one of 'seconds' or 'frame'"));
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
// Everything resolves to a display-rate frame time, which is the unit
|
|
779
|
+
// SetGlobalPosition takes and the unit the Sequencer time field shows.
|
|
780
|
+
FFrameTime TargetDisplay;
|
|
781
|
+
if (bHasSeconds)
|
|
782
|
+
{
|
|
783
|
+
TargetDisplay = DisplayRate.AsFrameTime(RequestedSeconds);
|
|
784
|
+
}
|
|
785
|
+
else if (TimeUnit == TEXT("tick"))
|
|
786
|
+
{
|
|
787
|
+
const FFrameTime AsTicks(FFrameNumber(static_cast<int32>(FMath::RoundToDouble(RequestedFrame))));
|
|
788
|
+
TargetDisplay = FFrameRate::TransformTime(AsTicks, TickResolution, DisplayRate);
|
|
789
|
+
}
|
|
790
|
+
else
|
|
791
|
+
{
|
|
792
|
+
TargetDisplay = FFrameTime(FFrameNumber(static_cast<int32>(FMath::RoundToDouble(RequestedFrame))));
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
// Pause before scrubbing: a playing sequence moves the playhead again on the
|
|
796
|
+
// next tick, and the capture would not be at the time that was asked for.
|
|
797
|
+
ULevelSequenceEditorBlueprintLibrary::Pause();
|
|
798
|
+
const FMovieSceneSequencePlaybackParams ScrubTo(TargetDisplay, EUpdatePositionMethod::Scrub);
|
|
799
|
+
ULevelSequenceEditorBlueprintLibrary::SetGlobalPosition(ScrubTo, EMovieSceneTimeUnit::DisplayRate);
|
|
800
|
+
// Evaluate now instead of on the next tick. The playhead move alone does not
|
|
801
|
+
// write possessed-actor transforms; the evaluation does, and a capture taken
|
|
802
|
+
// before it would read the previous frame's world.
|
|
803
|
+
ULevelSequenceEditorBlueprintLibrary::ForceUpdate();
|
|
804
|
+
|
|
805
|
+
const FFrameTime TargetTicks = FFrameRate::TransformTime(TargetDisplay, DisplayRate, TickResolution);
|
|
806
|
+
const double EvaluatedSeconds = DisplayRate.AsSeconds(TargetDisplay);
|
|
807
|
+
|
|
808
|
+
auto Result = MCPSuccess();
|
|
809
|
+
Result->SetStringField(TEXT("sequencePath"), Current->GetPathName());
|
|
810
|
+
Result->SetStringField(TEXT("timeUnit"), TimeUnit);
|
|
811
|
+
Result->SetNumberField(TEXT("seconds"), EvaluatedSeconds);
|
|
812
|
+
Result->SetNumberField(TEXT("frame"), TargetDisplay.AsDecimal());
|
|
813
|
+
Result->SetNumberField(TEXT("tick"), TargetTicks.AsDecimal());
|
|
814
|
+
Result->SetBoolField(TEXT("evaluated"), true);
|
|
815
|
+
// Read the transport back rather than reporting what was asked for.
|
|
816
|
+
Result->SetBoolField(TEXT("playing"), ULevelSequenceEditorBlueprintLibrary::IsPlaying());
|
|
817
|
+
|
|
818
|
+
TSharedPtr<FJsonObject> DisplayRateObj = MakeShared<FJsonObject>();
|
|
819
|
+
DisplayRateObj->SetNumberField(TEXT("numerator"), DisplayRate.Numerator);
|
|
820
|
+
DisplayRateObj->SetNumberField(TEXT("denominator"), DisplayRate.Denominator);
|
|
821
|
+
Result->SetObjectField(TEXT("displayRate"), DisplayRateObj);
|
|
822
|
+
|
|
823
|
+
TSharedPtr<FJsonObject> TickRateObj = MakeShared<FJsonObject>();
|
|
824
|
+
TickRateObj->SetNumberField(TEXT("numerator"), TickResolution.Numerator);
|
|
825
|
+
TickRateObj->SetNumberField(TEXT("denominator"), TickResolution.Denominator);
|
|
826
|
+
Result->SetObjectField(TEXT("tickResolution"), TickRateObj);
|
|
827
|
+
|
|
828
|
+
// A scrub outside the playback range is legal and evaluates, but a track
|
|
829
|
+
// that has no section there reads as its nearest key, which presents as
|
|
830
|
+
// "the scrub did nothing". Say so rather than leaving it to be guessed.
|
|
831
|
+
const TRange<FFrameNumber> PlaybackRange = MovieScene->GetPlaybackRange();
|
|
832
|
+
TSharedPtr<FJsonObject> RangeObj = MakeShared<FJsonObject>();
|
|
833
|
+
if (PlaybackRange.HasLowerBound())
|
|
834
|
+
{
|
|
835
|
+
RangeObj->SetNumberField(TEXT("startTick"), PlaybackRange.GetLowerBoundValue().Value);
|
|
836
|
+
RangeObj->SetNumberField(TEXT("startSeconds"), TickResolution.AsSeconds(FFrameTime(PlaybackRange.GetLowerBoundValue())));
|
|
837
|
+
}
|
|
838
|
+
if (PlaybackRange.HasUpperBound())
|
|
839
|
+
{
|
|
840
|
+
RangeObj->SetNumberField(TEXT("endTick"), PlaybackRange.GetUpperBoundValue().Value);
|
|
841
|
+
RangeObj->SetNumberField(TEXT("endSeconds"), TickResolution.AsSeconds(FFrameTime(PlaybackRange.GetUpperBoundValue())));
|
|
842
|
+
}
|
|
843
|
+
Result->SetObjectField(TEXT("playbackRange"), RangeObj);
|
|
844
|
+
|
|
845
|
+
const bool bWithinRange = PlaybackRange.Contains(TargetTicks.FrameNumber);
|
|
846
|
+
Result->SetBoolField(TEXT("withinPlaybackRange"), bWithinRange);
|
|
847
|
+
if (!bWithinRange)
|
|
848
|
+
{
|
|
849
|
+
Result->SetStringField(TEXT("warning"), TEXT(
|
|
850
|
+
"The requested time is outside the sequence's playback range. The playhead moved and the sequence "
|
|
851
|
+
"evaluated, but a track with no section there holds its nearest key, which looks like a scrub that "
|
|
852
|
+
"did nothing. playbackRange above is in ticks; seconds are given alongside."));
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
return MCPResult(Result);
|
|
856
|
+
}
|
|
857
|
+
|
|
562
858
|
// set_sequence_playback_range -- set a Level Sequence's playback range in
|
|
563
859
|
// seconds. (#548) Params: sequencePath, startSeconds, endSeconds.
|
|
564
860
|
TSharedPtr<FJsonValue> FSequencerHandlers::SetPlaybackRange(const TSharedPtr<FJsonObject>& Params)
|
|
@@ -609,12 +905,17 @@ TSharedPtr<FJsonValue> FSequencerHandlers::AddSection(const TSharedPtr<FJsonObje
|
|
|
609
905
|
if (!TrackClass) return MCPError(FString::Printf(TEXT("Unknown track type: '%s'"), *TrackType));
|
|
610
906
|
|
|
611
907
|
const FString ActorLabel = OptionalString(Params, TEXT("actorLabel"));
|
|
908
|
+
const FString ActorPath = OptionalString(Params, TEXT("actorPath"));
|
|
612
909
|
|
|
613
910
|
UMovieSceneTrack* Track = nullptr;
|
|
614
911
|
FGuid BindingGuid;
|
|
615
|
-
if (!ActorLabel.IsEmpty())
|
|
912
|
+
if (!ActorLabel.IsEmpty() || !ActorPath.IsEmpty())
|
|
616
913
|
{
|
|
617
|
-
|
|
914
|
+
REQUIRE_EDITOR_WORLD(BindingWorld);
|
|
915
|
+
TSharedPtr<FJsonValue> ActorErr;
|
|
916
|
+
AActor* BoundActor = MCPResolveActor(BindingWorld, Params, ActorErr);
|
|
917
|
+
if (!BoundActor) return ActorErr;
|
|
918
|
+
if (!ResolveActorBinding(Sequence, MovieScene, BoundActor, BindingGuid, Err)) return MCPError(Err);
|
|
618
919
|
Track = MovieScene->FindTrack(TrackClass, BindingGuid);
|
|
619
920
|
if (!Track) Track = MovieScene->AddTrack(TrackClass, BindingGuid);
|
|
620
921
|
}
|
|
@@ -631,10 +932,18 @@ TSharedPtr<FJsonValue> FSequencerHandlers::AddSection(const TSharedPtr<FJsonObje
|
|
|
631
932
|
// Resolve the camera binding up front so a bad cameraActorLabel fails before
|
|
632
933
|
// we create an orphan section.
|
|
633
934
|
const FString CameraActorLabel = OptionalString(Params, TEXT("cameraActorLabel"));
|
|
935
|
+
const FString CameraActorPath = OptionalString(Params, TEXT("cameraActorPath"));
|
|
634
936
|
FGuid CamGuid;
|
|
635
|
-
if (!CameraActorLabel.IsEmpty())
|
|
937
|
+
if (!CameraActorLabel.IsEmpty() || !CameraActorPath.IsEmpty())
|
|
636
938
|
{
|
|
637
|
-
|
|
939
|
+
REQUIRE_EDITOR_WORLD(CameraWorld);
|
|
940
|
+
FMCPActorSelector CameraSel;
|
|
941
|
+
CameraSel.LabelKey = TEXT("cameraActorLabel");
|
|
942
|
+
CameraSel.PathKey = TEXT("cameraActorPath");
|
|
943
|
+
TSharedPtr<FJsonValue> CameraErr;
|
|
944
|
+
AActor* CameraActor = MCPResolveActor(CameraWorld, Params, CameraErr, CameraSel);
|
|
945
|
+
if (!CameraActor) return CameraErr;
|
|
946
|
+
if (!ResolveActorBinding(Sequence, MovieScene, CameraActor, CamGuid, Err)) return MCPError(Err);
|
|
638
947
|
}
|
|
639
948
|
|
|
640
949
|
UMovieSceneSection* Section = Track->CreateNewSection();
|
|
@@ -715,11 +1024,16 @@ TSharedPtr<FJsonValue> FSequencerHandlers::SetKeyframes(const TSharedPtr<FJsonOb
|
|
|
715
1024
|
}
|
|
716
1025
|
|
|
717
1026
|
const FString ActorLabel = OptionalString(Params, TEXT("actorLabel"));
|
|
1027
|
+
const FString ActorPath = OptionalString(Params, TEXT("actorPath"));
|
|
718
1028
|
UMovieSceneTrack* Track = nullptr;
|
|
719
|
-
if (!ActorLabel.IsEmpty())
|
|
1029
|
+
if (!ActorLabel.IsEmpty() || !ActorPath.IsEmpty())
|
|
720
1030
|
{
|
|
1031
|
+
REQUIRE_EDITOR_WORLD(BindingWorld);
|
|
1032
|
+
TSharedPtr<FJsonValue> ActorErr;
|
|
1033
|
+
AActor* BoundActor = MCPResolveActor(BindingWorld, Params, ActorErr);
|
|
1034
|
+
if (!BoundActor) return ActorErr;
|
|
721
1035
|
FGuid BindingGuid;
|
|
722
|
-
if (!ResolveActorBinding(Sequence, MovieScene,
|
|
1036
|
+
if (!ResolveActorBinding(Sequence, MovieScene, BoundActor, BindingGuid, Err)) return MCPError(Err);
|
|
723
1037
|
Track = MovieScene->FindTrack(TrackClass, BindingGuid);
|
|
724
1038
|
}
|
|
725
1039
|
else
|
|
@@ -16,6 +16,8 @@ private:
|
|
|
16
16
|
static TSharedPtr<FJsonValue> ReadSequenceInfo(const TSharedPtr<FJsonObject>& Params);
|
|
17
17
|
static TSharedPtr<FJsonValue> AddTrack(const TSharedPtr<FJsonObject>& Params);
|
|
18
18
|
static TSharedPtr<FJsonValue> SequenceControl(const TSharedPtr<FJsonObject>& Params);
|
|
19
|
+
// #881: move the playhead to an exact time and evaluate there.
|
|
20
|
+
static TSharedPtr<FJsonValue> ScrubSequence(const TSharedPtr<FJsonObject>& Params);
|
|
19
21
|
static TSharedPtr<FJsonValue> SetPlaybackRange(const TSharedPtr<FJsonObject>& Params);
|
|
20
22
|
static TSharedPtr<FJsonValue> AddSection(const TSharedPtr<FJsonObject>& Params);
|
|
21
23
|
static TSharedPtr<FJsonValue> SetKeyframes(const TSharedPtr<FJsonObject>& Params);
|