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
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
// Coverage for foliage(batch_set_settings_where) (#988).
|
|
2
|
+
//
|
|
3
|
+
// run_automation_tests dispatches every EditorContext/EngineFilter test in the
|
|
4
|
+
// process against whatever project the bridge is attached to, and this action
|
|
5
|
+
// writes to FoliageType assets, so the assertions stay on argument rejection
|
|
6
|
+
// and the dry run, both of which are specified to write nothing.
|
|
7
|
+
|
|
8
|
+
#if WITH_DEV_AUTOMATION_TESTS
|
|
9
|
+
|
|
10
|
+
#include "HandlerRegistry.h"
|
|
11
|
+
#include "Handlers/FoliageHandlers.h"
|
|
12
|
+
#include "Misc/AutomationTest.h"
|
|
13
|
+
|
|
14
|
+
namespace
|
|
15
|
+
{
|
|
16
|
+
TSharedPtr<FJsonObject> MCPFoliageBatchTestRun(
|
|
17
|
+
FMCPHandlerRegistry& Registry,
|
|
18
|
+
const TSharedPtr<FJsonObject>& Request)
|
|
19
|
+
{
|
|
20
|
+
const TSharedPtr<FJsonValue> Response =
|
|
21
|
+
Registry.ExecuteHandler(TEXT("batch_set_foliage_settings_where"), Request);
|
|
22
|
+
if (!Response.IsValid() || Response->Type != EJson::Object)
|
|
23
|
+
{
|
|
24
|
+
return nullptr;
|
|
25
|
+
}
|
|
26
|
+
return Response->AsObject();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
TSharedPtr<FJsonObject> MCPFoliageBatchTestSettings()
|
|
30
|
+
{
|
|
31
|
+
TSharedPtr<FJsonObject> Settings = MakeShared<FJsonObject>();
|
|
32
|
+
Settings->SetBoolField(TEXT("bIncludeInHLOD"), false);
|
|
33
|
+
return Settings;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
IMPLEMENT_SIMPLE_AUTOMATION_TEST(
|
|
38
|
+
FFoliageBatchSettingsContractTest,
|
|
39
|
+
"UE.MCP.Foliage.BatchSetSettingsWhere.Contract",
|
|
40
|
+
EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter)
|
|
41
|
+
|
|
42
|
+
bool FFoliageBatchSettingsContractTest::RunTest(const FString& Parameters)
|
|
43
|
+
{
|
|
44
|
+
FMCPHandlerRegistry Registry;
|
|
45
|
+
FFoliageHandlers::RegisterHandlers(Registry);
|
|
46
|
+
|
|
47
|
+
TestTrue(TEXT("batch_set_foliage_settings_where is registered"),
|
|
48
|
+
Registry.HasHandler(TEXT("batch_set_foliage_settings_where")));
|
|
49
|
+
TestTrue(TEXT("it carries its own timeout, because scanning and saving hundreds of assets is slow"),
|
|
50
|
+
Registry.GetHandlerTimeout(TEXT("batch_set_foliage_settings_where")) > 0.0f);
|
|
51
|
+
|
|
52
|
+
// No settings means there is nothing to write.
|
|
53
|
+
{
|
|
54
|
+
const TSharedPtr<FJsonObject> Response =
|
|
55
|
+
MCPFoliageBatchTestRun(Registry, MakeShared<FJsonObject>());
|
|
56
|
+
if (Response.IsValid())
|
|
57
|
+
{
|
|
58
|
+
TestFalse(TEXT("no settings fails"), Response->GetBoolField(TEXT("success")));
|
|
59
|
+
TestTrue(TEXT("and names the parameter"),
|
|
60
|
+
Response->GetStringField(TEXT("error")).Contains(TEXT("settings")));
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// No predicate means "every foliage type in the project", which is not
|
|
65
|
+
// what anybody means by a conditional batch. The error points at the
|
|
66
|
+
// single-asset action for the case where one asset is what was wanted.
|
|
67
|
+
{
|
|
68
|
+
TSharedPtr<FJsonObject> Request = MakeShared<FJsonObject>();
|
|
69
|
+
Request->SetObjectField(TEXT("settings"), MCPFoliageBatchTestSettings());
|
|
70
|
+
const TSharedPtr<FJsonObject> Response = MCPFoliageBatchTestRun(Registry, Request);
|
|
71
|
+
if (Response.IsValid())
|
|
72
|
+
{
|
|
73
|
+
TestFalse(TEXT("no predicate fails"), Response->GetBoolField(TEXT("success")));
|
|
74
|
+
TestTrue(TEXT("and offers set_settings for the single-asset case"),
|
|
75
|
+
Response->GetStringField(TEXT("error")).Contains(TEXT("set_settings")));
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// A predicate but no candidate source.
|
|
80
|
+
{
|
|
81
|
+
TSharedPtr<FJsonObject> Predicate = MakeShared<FJsonObject>();
|
|
82
|
+
Predicate->SetStringField(TEXT("field"), TEXT("CullDistance.Max"));
|
|
83
|
+
Predicate->SetStringField(TEXT("op"), TEXT("gt"));
|
|
84
|
+
Predicate->SetNumberField(TEXT("value"), 0);
|
|
85
|
+
|
|
86
|
+
TSharedPtr<FJsonObject> Request = MakeShared<FJsonObject>();
|
|
87
|
+
Request->SetObjectField(TEXT("settings"), MCPFoliageBatchTestSettings());
|
|
88
|
+
Request->SetArrayField(TEXT("where"), { MakeShared<FJsonValueObject>(Predicate) });
|
|
89
|
+
const TSharedPtr<FJsonObject> Response = MCPFoliageBatchTestRun(Registry, Request);
|
|
90
|
+
if (Response.IsValid())
|
|
91
|
+
{
|
|
92
|
+
TestFalse(TEXT("no candidate source fails"), Response->GetBoolField(TEXT("success")));
|
|
93
|
+
TestTrue(TEXT("and lists all three"),
|
|
94
|
+
Response->GetStringField(TEXT("error")).Contains(TEXT("fromLevel")));
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return true;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
IMPLEMENT_SIMPLE_AUTOMATION_TEST(
|
|
102
|
+
FFoliageBatchSettingsPreviewTest,
|
|
103
|
+
"UE.MCP.Foliage.BatchSetSettingsWhere.PreviewsByDefault",
|
|
104
|
+
EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter)
|
|
105
|
+
|
|
106
|
+
bool FFoliageBatchSettingsPreviewTest::RunTest(const FString& Parameters)
|
|
107
|
+
{
|
|
108
|
+
FMCPHandlerRegistry Registry;
|
|
109
|
+
FFoliageHandlers::RegisterHandlers(Registry);
|
|
110
|
+
|
|
111
|
+
// A complete, valid request against a directory that exists in every
|
|
112
|
+
// project. dryRun is not passed, so the default decides, and the default
|
|
113
|
+
// has to be the preview.
|
|
114
|
+
TSharedPtr<FJsonObject> Predicate = MakeShared<FJsonObject>();
|
|
115
|
+
Predicate->SetStringField(TEXT("field"), TEXT("CullDistance.Max"));
|
|
116
|
+
Predicate->SetStringField(TEXT("op"), TEXT("gt"));
|
|
117
|
+
Predicate->SetNumberField(TEXT("value"), 0);
|
|
118
|
+
|
|
119
|
+
TSharedPtr<FJsonObject> Request = MakeShared<FJsonObject>();
|
|
120
|
+
Request->SetObjectField(TEXT("settings"), MCPFoliageBatchTestSettings());
|
|
121
|
+
Request->SetArrayField(TEXT("where"), { MakeShared<FJsonValueObject>(Predicate) });
|
|
122
|
+
Request->SetStringField(TEXT("directory"), TEXT("/Game"));
|
|
123
|
+
|
|
124
|
+
const TSharedPtr<FJsonObject> Response = MCPFoliageBatchTestRun(Registry, Request);
|
|
125
|
+
if (!Response.IsValid() || !Response->GetBoolField(TEXT("success")))
|
|
126
|
+
{
|
|
127
|
+
return true;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
TestTrue(TEXT("dryRun defaults to true"), Response->GetBoolField(TEXT("dryRun")));
|
|
131
|
+
TestTrue(TEXT("a preview reports what it would update"), Response->HasField(TEXT("wouldUpdate")));
|
|
132
|
+
TestFalse(TEXT("and does not claim to have updated anything"), Response->HasField(TEXT("updated")));
|
|
133
|
+
TestFalse(TEXT("and saves nothing"), Response->HasField(TEXT("saved")));
|
|
134
|
+
|
|
135
|
+
// The zero-match note has to explain the interval trap, because
|
|
136
|
+
// CullDistance is an FInt32Interval and comparing it as a number is the
|
|
137
|
+
// mistake this action invites.
|
|
138
|
+
if (static_cast<int32>(Response->GetNumberField(TEXT("matched"))) == 0 &&
|
|
139
|
+
static_cast<int32>(Response->GetNumberField(TEXT("scanned"))) > 0)
|
|
140
|
+
{
|
|
141
|
+
TestTrue(TEXT("a zero match explains itself"), Response->HasField(TEXT("zeroMatchNote")));
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return true;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
#endif // WITH_DEV_AUTOMATION_TESTS
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
#if WITH_DEV_AUTOMATION_TESTS
|
|
2
|
+
|
|
3
|
+
#include "GameThreadExecutor.h"
|
|
4
|
+
#include "Dom/JsonObject.h"
|
|
5
|
+
#include "Dom/JsonValue.h"
|
|
6
|
+
#include "Misc/AutomationTest.h"
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* The readiness gate, and the one class of call it must never close in front of.
|
|
10
|
+
*
|
|
11
|
+
* #968: a modal raised during editor startup (the "Restore Packages" prompt
|
|
12
|
+
* after an unclean shutdown) blocks the game thread before the editor is ever
|
|
13
|
+
* marked ready. Every handler then answered "Editor is still initializing" -
|
|
14
|
+
* including respond_to_dialog and set_dialog_policy, the two calls that could
|
|
15
|
+
* have dismissed it. The gate was held shut by the very dialog those calls
|
|
16
|
+
* exist to clear, and the only escape was an OS kill, which discards whatever
|
|
17
|
+
* the user was being asked about. Meanwhile get_engine_state described the
|
|
18
|
+
* dialog down to its button labels, because it answers off the game thread.
|
|
19
|
+
*
|
|
20
|
+
* These run on the game thread, so ExecuteOnGameThread dispatches inline and
|
|
21
|
+
* the assertions are about the gate itself rather than about ticker timing.
|
|
22
|
+
*/
|
|
23
|
+
IMPLEMENT_SIMPLE_AUTOMATION_TEST(
|
|
24
|
+
FMCPGameThreadReadyGateTest,
|
|
25
|
+
"UE.MCP.Bridge.GameThread.ReadyGate",
|
|
26
|
+
EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter)
|
|
27
|
+
|
|
28
|
+
bool FMCPGameThreadReadyGateTest::RunTest(const FString& Parameters)
|
|
29
|
+
{
|
|
30
|
+
FMCPGameThreadExecutor Executor;
|
|
31
|
+
TestFalse(TEXT("a fresh executor has not been told the editor is ready"), Executor.IsEditorReady());
|
|
32
|
+
|
|
33
|
+
bool bHandlerRan = false;
|
|
34
|
+
FMCPGameThreadExecutor::FHandlerFunction Handler =
|
|
35
|
+
[&bHandlerRan](const TSharedPtr<FJsonObject>&) -> TSharedPtr<FJsonValue>
|
|
36
|
+
{
|
|
37
|
+
bHandlerRan = true;
|
|
38
|
+
TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
|
|
39
|
+
Result->SetBoolField(TEXT("success"), true);
|
|
40
|
+
return MakeShared<FJsonValueObject>(Result);
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const TSharedPtr<FJsonObject> Params = MakeShared<FJsonObject>();
|
|
44
|
+
|
|
45
|
+
// An ordinary handler still waits. Refusing work that needs a built editor
|
|
46
|
+
// is the whole point of the gate and none of this weakens it.
|
|
47
|
+
TSharedPtr<FJsonValue> Gated = Executor.ExecuteOnGameThread(Handler, Params, 5.0f, /*bModalSafe*/ false);
|
|
48
|
+
TestTrue(TEXT("an ordinary handler is refused before the editor is ready"), Gated.IsValid() && Gated->Type == EJson::Object);
|
|
49
|
+
FString GatedError;
|
|
50
|
+
if (Gated.IsValid() && Gated->Type == EJson::Object)
|
|
51
|
+
{
|
|
52
|
+
Gated->AsObject()->TryGetStringField(TEXT("error"), GatedError);
|
|
53
|
+
}
|
|
54
|
+
TestTrue(TEXT("and told why"), GatedError.Contains(TEXT("still initializing")));
|
|
55
|
+
TestFalse(TEXT("and never reached the handler"), bHandlerRan);
|
|
56
|
+
|
|
57
|
+
// A modal-safe handler runs. It is the escape hatch from a blocked game
|
|
58
|
+
// thread, so nothing the block causes may stand in front of it.
|
|
59
|
+
bHandlerRan = false;
|
|
60
|
+
TSharedPtr<FJsonValue> Exempt = Executor.ExecuteOnGameThread(Handler, Params, 5.0f, /*bModalSafe*/ true);
|
|
61
|
+
TestTrue(TEXT("a modal-safe handler runs before the editor is ready"), bHandlerRan);
|
|
62
|
+
TestTrue(TEXT("and returns its own result, not the gate's error"),
|
|
63
|
+
Exempt.IsValid() && Exempt->Type == EJson::Object && Exempt->AsObject()->HasField(TEXT("success")));
|
|
64
|
+
|
|
65
|
+
FString ExemptError;
|
|
66
|
+
if (Exempt.IsValid() && Exempt->Type == EJson::Object)
|
|
67
|
+
{
|
|
68
|
+
Exempt->AsObject()->TryGetStringField(TEXT("error"), ExemptError);
|
|
69
|
+
}
|
|
70
|
+
TestTrue(TEXT("with no initializing error attached"), ExemptError.IsEmpty());
|
|
71
|
+
|
|
72
|
+
// Once the editor is ready both go through, so the exemption is about the
|
|
73
|
+
// window before readiness and changes nothing after it.
|
|
74
|
+
Executor.SetEditorReady();
|
|
75
|
+
bHandlerRan = false;
|
|
76
|
+
Executor.ExecuteOnGameThread(Handler, Params, 5.0f, /*bModalSafe*/ false);
|
|
77
|
+
TestTrue(TEXT("an ordinary handler runs once the editor is ready"), bHandlerRan);
|
|
78
|
+
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
#endif
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
#if WITH_DEV_AUTOMATION_TESTS
|
|
2
|
+
|
|
3
|
+
#include "Handlers/GasHandlers.h"
|
|
4
|
+
#include "HandlerRegistry.h"
|
|
5
|
+
#include "Misc/AutomationTest.h"
|
|
6
|
+
#include "AbilitySystemComponent.h"
|
|
7
|
+
#include "AbilitySystemTestAttributeSet.h"
|
|
8
|
+
#include "AttributeSet.h"
|
|
9
|
+
#include "Engine/Engine.h"
|
|
10
|
+
#include "Engine/World.h"
|
|
11
|
+
#include "GameFramework/Actor.h"
|
|
12
|
+
#include "Misc/ScopeExit.h"
|
|
13
|
+
#include "UObject/UnrealType.h"
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* #956: gas(get_live_attribute_value) / gas(set_live_attribute_value) must
|
|
17
|
+
* reach the attribute set instance REGISTERED on the actor's ASC, never a
|
|
18
|
+
* second one built alongside it.
|
|
19
|
+
*
|
|
20
|
+
* The case that makes this hard is the one these tests reproduce: an actor in
|
|
21
|
+
* a world that has not begun play never runs InitializeComponent, so its ASC
|
|
22
|
+
* has no registered sets at all even though the actor owns one. The only
|
|
23
|
+
* correct answer there is to register the actor's OWN instance. Constructing a
|
|
24
|
+
* fresh set instead compiles, runs, reports success, and writes to an object
|
|
25
|
+
* the gameplay code never reads, which is why the pointer-identity assertion
|
|
26
|
+
* below is the point of the whole file.
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
IMPLEMENT_SIMPLE_AUTOMATION_TEST(
|
|
30
|
+
FGasAdoptOwnerAttributeSetsTest,
|
|
31
|
+
"UE.MCP.Gas.LiveAttributes.AdoptsTheActorsOwnSet",
|
|
32
|
+
EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter)
|
|
33
|
+
|
|
34
|
+
bool FGasAdoptOwnerAttributeSetsTest::RunTest(const FString& Parameters)
|
|
35
|
+
{
|
|
36
|
+
// A private world, so nothing here touches whatever map the user has open.
|
|
37
|
+
UWorld* World = UWorld::CreateWorld(EWorldType::Editor, /*bInformEngineOfWorld=*/false);
|
|
38
|
+
if (!World)
|
|
39
|
+
{
|
|
40
|
+
AddError(TEXT("could not create a test world"));
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
ON_SCOPE_EXIT
|
|
44
|
+
{
|
|
45
|
+
World->DestroyWorld(false);
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
AActor* Actor = World->SpawnActor<AActor>();
|
|
49
|
+
if (!Actor)
|
|
50
|
+
{
|
|
51
|
+
AddError(TEXT("could not spawn the test actor"));
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
UAbilitySystemComponent* ASC = NewObject<UAbilitySystemComponent>(Actor);
|
|
56
|
+
ASC->RegisterComponent();
|
|
57
|
+
|
|
58
|
+
// The actor's own attribute set, outered to the actor exactly the way a
|
|
59
|
+
// CreateDefaultSubobject-created one is. This is the object the gameplay
|
|
60
|
+
// code would consult once the ASC knows about it.
|
|
61
|
+
// Constructed through the class pointer rather than the templated form:
|
|
62
|
+
// UAbilitySystemTestAttributeSet is MinimalAPI, so its class registration is
|
|
63
|
+
// exported and its constructor is not.
|
|
64
|
+
UAttributeSet* OwnSet = NewObject<UAttributeSet>(
|
|
65
|
+
Actor, UAbilitySystemTestAttributeSet::StaticClass());
|
|
66
|
+
|
|
67
|
+
// The whole premise: the world never began play, so nothing registered it.
|
|
68
|
+
TestNull(
|
|
69
|
+
TEXT("nothing is registered before adoption, even though the actor owns a set"),
|
|
70
|
+
ASC->GetAttributeSet(UAbilitySystemTestAttributeSet::StaticClass()));
|
|
71
|
+
|
|
72
|
+
TArray<FString> Adopted;
|
|
73
|
+
const int32 Count = MCPGas::AdoptOwnerAttributeSets(ASC, Actor, Adopted);
|
|
74
|
+
TestEqual(TEXT("one set was newly registered"), Count, 1);
|
|
75
|
+
TestEqual(TEXT("the registered set is named in the report"), Adopted.Num(), 1);
|
|
76
|
+
|
|
77
|
+
const UAttributeSet* Registered =
|
|
78
|
+
ASC->GetAttributeSet(UAbilitySystemTestAttributeSet::StaticClass());
|
|
79
|
+
TestNotNull(TEXT("the ASC now has a registered set"), Registered);
|
|
80
|
+
|
|
81
|
+
// THE assertion. A second, disconnected instance would satisfy every other
|
|
82
|
+
// check in this file and fail only this one.
|
|
83
|
+
TestTrue(
|
|
84
|
+
TEXT("the registered instance IS the actor's own object, not a copy"),
|
|
85
|
+
Registered == OwnSet);
|
|
86
|
+
|
|
87
|
+
// Idempotent: a second pass registers nothing and does not duplicate.
|
|
88
|
+
TArray<FString> Again;
|
|
89
|
+
TestEqual(TEXT("re-adopting registers nothing new"),
|
|
90
|
+
MCPGas::AdoptOwnerAttributeSets(ASC, Actor, Again), 0);
|
|
91
|
+
TestEqual(TEXT("the set appears exactly once"),
|
|
92
|
+
ASC->GetSpawnedAttributes().Num(), 1);
|
|
93
|
+
|
|
94
|
+
// A value written through the registered instance is the value the ASC's
|
|
95
|
+
// own accessor reads back, which is what "the gameplay code consults it"
|
|
96
|
+
// means in practice.
|
|
97
|
+
FStructProperty* ManaProp = MCPGas::FindAttributeDataProperty(
|
|
98
|
+
UAbilitySystemTestAttributeSet::StaticClass(), TEXT("Mana"));
|
|
99
|
+
TestNotNull(TEXT("Mana is found as an FGameplayAttributeData property"), ManaProp);
|
|
100
|
+
if (ManaProp)
|
|
101
|
+
{
|
|
102
|
+
const FGameplayAttribute Mana(ManaProp);
|
|
103
|
+
float NewValue = 42.0f;
|
|
104
|
+
Mana.SetNumericValueChecked(NewValue, const_cast<UAttributeSet*>(Registered));
|
|
105
|
+
// Read back through the ASC, which resolves the attribute's set on its
|
|
106
|
+
// own. It agreeing with the actor's object is the operational form of
|
|
107
|
+
// "the gameplay code consults this instance", and it is what a second,
|
|
108
|
+
// disconnected set would break.
|
|
109
|
+
TestEqual(TEXT("the ASC reads back what was written to the actor's own instance"),
|
|
110
|
+
ASC->GetNumericAttribute(Mana), Mana.GetNumericValue(OwnSet));
|
|
111
|
+
TestEqual(TEXT("the written value is what landed"),
|
|
112
|
+
Mana.GetNumericValue(OwnSet), 42.0f);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
IMPLEMENT_SIMPLE_AUTOMATION_TEST(
|
|
119
|
+
FGasAttributeDataPropertyLookupTest,
|
|
120
|
+
"UE.MCP.Gas.LiveAttributes.AttributePropertyLookup",
|
|
121
|
+
EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter)
|
|
122
|
+
|
|
123
|
+
bool FGasAttributeDataPropertyLookupTest::RunTest(const FString& Parameters)
|
|
124
|
+
{
|
|
125
|
+
UClass* SetClass = UAbilitySystemTestAttributeSet::StaticClass();
|
|
126
|
+
|
|
127
|
+
TestNotNull(TEXT("bare property name resolves"),
|
|
128
|
+
MCPGas::FindAttributeDataProperty(SetClass, TEXT("Mana")));
|
|
129
|
+
TestNotNull(TEXT("Set.Property spelling resolves"),
|
|
130
|
+
MCPGas::FindAttributeDataProperty(SetClass, TEXT("AbilitySystemTestAttributeSet.Mana")));
|
|
131
|
+
TestNotNull(TEXT("Set:Property spelling resolves"),
|
|
132
|
+
MCPGas::FindAttributeDataProperty(SetClass, TEXT("AbilitySystemTestAttributeSet:Mana")));
|
|
133
|
+
|
|
134
|
+
// Plain float UPROPERTYs on an attribute set are not FGameplayAttributeData
|
|
135
|
+
// and are not what these actions address, so they must miss rather than
|
|
136
|
+
// resolve to something the caller cannot read a base value from.
|
|
137
|
+
TestNull(TEXT("a plain float property is not an attribute data property"),
|
|
138
|
+
MCPGas::FindAttributeDataProperty(SetClass, TEXT("Health")));
|
|
139
|
+
TestNull(TEXT("an unknown name misses"),
|
|
140
|
+
MCPGas::FindAttributeDataProperty(SetClass, TEXT("NoSuchAttribute")));
|
|
141
|
+
TestNull(TEXT("a null class misses rather than crashing"),
|
|
142
|
+
MCPGas::FindAttributeDataProperty(nullptr, TEXT("Mana")));
|
|
143
|
+
|
|
144
|
+
const FString Names = MCPGas::ListAttributeDataPropertyNames(SetClass);
|
|
145
|
+
TestTrue(TEXT("the miss message lists the real attribute names"), Names.Contains(TEXT("Mana")));
|
|
146
|
+
TestEqual(TEXT("a null class lists nothing"),
|
|
147
|
+
*MCPGas::ListAttributeDataPropertyNames(nullptr), TEXT("(none)"));
|
|
148
|
+
|
|
149
|
+
return true;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
IMPLEMENT_SIMPLE_AUTOMATION_TEST(
|
|
153
|
+
FGasLiveAttributeRegistrationTest,
|
|
154
|
+
"UE.MCP.Gas.LiveAttributes.RegistrationAndPreflight",
|
|
155
|
+
EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter)
|
|
156
|
+
|
|
157
|
+
bool FGasLiveAttributeRegistrationTest::RunTest(const FString& Parameters)
|
|
158
|
+
{
|
|
159
|
+
FMCPHandlerRegistry Registry;
|
|
160
|
+
FGasHandlers::RegisterHandlers(Registry);
|
|
161
|
+
|
|
162
|
+
TestTrue(TEXT("get_live_attribute_value is registered"),
|
|
163
|
+
Registry.HasHandler(TEXT("get_live_attribute_value")));
|
|
164
|
+
TestTrue(TEXT("set_live_attribute_value is registered"),
|
|
165
|
+
Registry.HasHandler(TEXT("set_live_attribute_value")));
|
|
166
|
+
|
|
167
|
+
// Preflight runs before any world or actor lookup, so this is safe with no
|
|
168
|
+
// editor world and no PIE session.
|
|
169
|
+
const TSharedPtr<FJsonValue> Response =
|
|
170
|
+
Registry.ExecuteHandler(TEXT("get_live_attribute_value"), MakeShared<FJsonObject>());
|
|
171
|
+
TestTrue(TEXT("preflight returns an object"), Response.IsValid() && Response->Type == EJson::Object);
|
|
172
|
+
if (Response.IsValid() && Response->Type == EJson::Object)
|
|
173
|
+
{
|
|
174
|
+
const TSharedPtr<FJsonObject> Object = Response->AsObject();
|
|
175
|
+
TestFalse(TEXT("preflight is unsuccessful"), Object->GetBoolField(TEXT("success")));
|
|
176
|
+
TestTrue(TEXT("preflight names the first required field"),
|
|
177
|
+
Object->GetStringField(TEXT("error")).Contains(TEXT("attributeSet")));
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
return true;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
#endif
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
// Coverage for landscape(sample) parameter parity (#939).
|
|
2
|
+
//
|
|
3
|
+
// The action documented "Params: x, y" and the handler required an object
|
|
4
|
+
// called `point`, so every documented call shape answered "Missing 'point'
|
|
5
|
+
// parameter" and there was no working call at all. These assertions pin the
|
|
6
|
+
// contract rather than the terrain: each accepted position shape gets PAST
|
|
7
|
+
// parameter validation, and a request with no position at all is refused with
|
|
8
|
+
// an error that names every shape that would have worked.
|
|
9
|
+
//
|
|
10
|
+
// The terrain half (heights, weights) needs a landscape in the level and is
|
|
11
|
+
// exercised by the live smoke run; what regressed here was the parameter
|
|
12
|
+
// handling, and that is checkable with no landscape at all.
|
|
13
|
+
|
|
14
|
+
#if WITH_DEV_AUTOMATION_TESTS
|
|
15
|
+
|
|
16
|
+
#include "HandlerRegistry.h"
|
|
17
|
+
#include "Handlers/LandscapeHandlers.h"
|
|
18
|
+
#include "Misc/AutomationTest.h"
|
|
19
|
+
|
|
20
|
+
namespace
|
|
21
|
+
{
|
|
22
|
+
TSharedPtr<FJsonObject> MCPLandscapeSampleTestRun(
|
|
23
|
+
FMCPHandlerRegistry& Registry,
|
|
24
|
+
const TSharedPtr<FJsonObject>& Request)
|
|
25
|
+
{
|
|
26
|
+
const TSharedPtr<FJsonValue> Response = Registry.ExecuteHandler(TEXT("sample_landscape"), Request);
|
|
27
|
+
if (!Response.IsValid() || Response->Type != EJson::Object)
|
|
28
|
+
{
|
|
29
|
+
return nullptr;
|
|
30
|
+
}
|
|
31
|
+
return Response->AsObject();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** The error text a request is refused with, or empty when it succeeded. */
|
|
35
|
+
FString MCPLandscapeSampleTestError(const TSharedPtr<FJsonObject>& Response)
|
|
36
|
+
{
|
|
37
|
+
if (!Response.IsValid()) return FString();
|
|
38
|
+
if (Response->GetBoolField(TEXT("success"))) return FString();
|
|
39
|
+
return Response->GetStringField(TEXT("error"));
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
IMPLEMENT_SIMPLE_AUTOMATION_TEST(
|
|
44
|
+
FLandscapeSampleAcceptsItsDocumentedArgumentsTest,
|
|
45
|
+
"UE.MCP.Landscape.Sample.AcceptsItsDocumentedArguments",
|
|
46
|
+
EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter)
|
|
47
|
+
|
|
48
|
+
bool FLandscapeSampleAcceptsItsDocumentedArgumentsTest::RunTest(const FString& Parameters)
|
|
49
|
+
{
|
|
50
|
+
FMCPHandlerRegistry Registry;
|
|
51
|
+
FLandscapeHandlers::RegisterHandlers(Registry);
|
|
52
|
+
TestTrue(TEXT("sample_landscape is registered"), Registry.HasHandler(TEXT("sample_landscape")));
|
|
53
|
+
|
|
54
|
+
// No position at all is the one request that SHOULD be refused, and the
|
|
55
|
+
// refusal has to name every shape that works. The old message named only
|
|
56
|
+
// `point`, which is the shape the schema never advertised.
|
|
57
|
+
{
|
|
58
|
+
const TSharedPtr<FJsonObject> Response =
|
|
59
|
+
MCPLandscapeSampleTestRun(Registry, MakeShared<FJsonObject>());
|
|
60
|
+
if (Response.IsValid())
|
|
61
|
+
{
|
|
62
|
+
TestFalse(TEXT("a request with no position is refused"), Response->GetBoolField(TEXT("success")));
|
|
63
|
+
const FString Error = Response->GetStringField(TEXT("error"));
|
|
64
|
+
TestTrue(TEXT("and the refusal names the x/y shape"), Error.Contains(TEXT("x and y")));
|
|
65
|
+
TestTrue(TEXT("and the point shape"), Error.Contains(TEXT("point")));
|
|
66
|
+
TestTrue(TEXT("and the worldX/worldY shape"), Error.Contains(TEXT("worldX")));
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Every accepted shape must get past parameter validation. Whether a
|
|
71
|
+
// landscape exists in the level is a separate question, so the assertion is
|
|
72
|
+
// on the error NOT being the missing-position one.
|
|
73
|
+
auto TestShapeIsAccepted = [this, &Registry](const TCHAR* What, const TSharedPtr<FJsonObject>& Request)
|
|
74
|
+
{
|
|
75
|
+
const TSharedPtr<FJsonObject> Response = MCPLandscapeSampleTestRun(Registry, Request);
|
|
76
|
+
if (!Response.IsValid()) return;
|
|
77
|
+
const FString Error = MCPLandscapeSampleTestError(Response);
|
|
78
|
+
TestFalse(FString::Printf(TEXT("%s is not refused as a missing position"), What),
|
|
79
|
+
Error.Contains(TEXT("Missing sample position")));
|
|
80
|
+
TestFalse(FString::Printf(TEXT("%s is not refused for a missing 'point'"), What),
|
|
81
|
+
Error.Contains(TEXT("Missing 'point'")));
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
{
|
|
85
|
+
TSharedPtr<FJsonObject> Request = MakeShared<FJsonObject>();
|
|
86
|
+
Request->SetNumberField(TEXT("x"), 1000.0);
|
|
87
|
+
Request->SetNumberField(TEXT("y"), 2000.0);
|
|
88
|
+
TestShapeIsAccepted(TEXT("x + y"), Request);
|
|
89
|
+
}
|
|
90
|
+
{
|
|
91
|
+
TSharedPtr<FJsonObject> Point = MakeShared<FJsonObject>();
|
|
92
|
+
Point->SetNumberField(TEXT("x"), 1000.0);
|
|
93
|
+
Point->SetNumberField(TEXT("y"), 2000.0);
|
|
94
|
+
Point->SetNumberField(TEXT("z"), 0.0);
|
|
95
|
+
TSharedPtr<FJsonObject> Request = MakeShared<FJsonObject>();
|
|
96
|
+
Request->SetObjectField(TEXT("point"), Point);
|
|
97
|
+
TestShapeIsAccepted(TEXT("point {x, y, z}"), Request);
|
|
98
|
+
}
|
|
99
|
+
{
|
|
100
|
+
// The z is optional: the surface height is what the action answers, so
|
|
101
|
+
// requiring one as an input would be a riddle.
|
|
102
|
+
TSharedPtr<FJsonObject> Point = MakeShared<FJsonObject>();
|
|
103
|
+
Point->SetNumberField(TEXT("x"), 1000.0);
|
|
104
|
+
Point->SetNumberField(TEXT("y"), 2000.0);
|
|
105
|
+
TSharedPtr<FJsonObject> Request = MakeShared<FJsonObject>();
|
|
106
|
+
Request->SetObjectField(TEXT("point"), Point);
|
|
107
|
+
TestShapeIsAccepted(TEXT("point {x, y}"), Request);
|
|
108
|
+
}
|
|
109
|
+
{
|
|
110
|
+
TSharedPtr<FJsonObject> Request = MakeShared<FJsonObject>();
|
|
111
|
+
Request->SetNumberField(TEXT("worldX"), 1000.0);
|
|
112
|
+
Request->SetNumberField(TEXT("worldY"), 2000.0);
|
|
113
|
+
TestShapeIsAccepted(TEXT("worldX + worldY"), Request);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return true;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
#endif // WITH_DEV_AUTOMATION_TESTS
|