ultimate-unreal-engine-mcp 0.1.1 → 0.1.2
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/package.json +1 -1
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/MCPBridgeEditor.Build.cs +6 -1
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPAICommands.cpp +14 -11
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPActorCommands.cpp +2 -2
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPAnimationCommands.cpp +18 -11
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPAudioCommands.cpp +1 -1
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPBlueprintHandlers.cpp +2 -2
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPBlueprintWriteHandlers.cpp +21 -9
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPChaosCommands.cpp +3 -3
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPCollisionPhysicsCommands.cpp +3 -3
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPEditorStateCommands.cpp +1 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPGASCommands.cpp +35 -15
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPImportExportCommands.cpp +13 -8
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPInputHandlers.cpp +14 -7
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPLiveLinkCommands.cpp +6 -6
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPMaterialCommands.cpp +38 -29
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPMotionDesignCommands.cpp +9 -9
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPMovieRenderCommands.cpp +4 -9
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPNetworkingCommands.cpp +4 -4
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPPieCommands.cpp +4 -3
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPSelectionCommands.cpp +1 -1
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPSequencerCommands.cpp +22 -44
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPValidationCommands.cpp +11 -11
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPViewportCommands.cpp +1 -1
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPWorldPartitionCommands.cpp +43 -26
package/package.json
CHANGED
|
@@ -27,6 +27,7 @@ public class MCPBridgeEditor : ModuleRules
|
|
|
27
27
|
"Kismet",
|
|
28
28
|
"BlueprintGraph",
|
|
29
29
|
"AssetRegistry",
|
|
30
|
+
"InputCore",
|
|
30
31
|
"EnhancedInput",
|
|
31
32
|
"LevelEditor",
|
|
32
33
|
"SlateCore",
|
|
@@ -41,10 +42,12 @@ public class MCPBridgeEditor : ModuleRules
|
|
|
41
42
|
"AnimGraphRuntime",
|
|
42
43
|
"IKRig",
|
|
43
44
|
"WorldPartitionEditor",
|
|
45
|
+
"DataLayerEditor",
|
|
44
46
|
"PhysicsCore",
|
|
45
47
|
"MetasoundEngine",
|
|
46
48
|
"MetasoundFrontend",
|
|
47
49
|
"InterchangeEngine",
|
|
50
|
+
"InterchangeCore", // UInterchangeSourceData
|
|
48
51
|
"InterchangePipelines",
|
|
49
52
|
"AIModule",
|
|
50
53
|
"StateTreeModule",
|
|
@@ -53,13 +56,15 @@ public class MCPBridgeEditor : ModuleRules
|
|
|
53
56
|
"GameplayTags", // Phase 25 - GAS
|
|
54
57
|
"GameplayTasks", // Phase 25 - GAS
|
|
55
58
|
"GeometryCollectionEngine", // Phase 26 - Chaos destruction (UGeometryCollectionComponent)
|
|
59
|
+
"Chaos", // Phase 26 - FManagedArrayCollection, FTransformCollection
|
|
60
|
+
"ClothingSystemRuntimeCommon", // Phase 26 - UClothingAssetCommon
|
|
56
61
|
"ChaosCloth", // Phase 26 - Chaos cloth simulation parameters
|
|
57
62
|
"LiveLinkInterface", // Phase 27 - ILiveLinkClient, FLiveLinkSubjectKey, FLiveLinkSubjectFrameData
|
|
58
63
|
"LiveLink", // Phase 27 - ULiveLinkSubjectSettings for per-subject enabled state control
|
|
59
|
-
"AvalancheRundown", // Phase 28 - Motion Design Scene State machines (experimental)
|
|
60
64
|
"AvalancheTransition", // Phase 28 - Motion Design Transition Logic trees (experimental)
|
|
61
65
|
"RemoteControl", // Phase 28 - Remote Control preset read/write
|
|
62
66
|
"MovieRenderPipelineCore", // Phase 29 - UMoviePipelineQueue, UMoviePipelineExecutorJob, config/settings types
|
|
67
|
+
"MovieRenderPipelineSettings", // Phase 29 - UMoviePipelineBurnInSetting
|
|
63
68
|
"MovieRenderPipelineEditor", // Phase 29 - UMoviePipelineQueueSubsystem
|
|
64
69
|
"OnlineSubsystem", // Phase 30 - IOnlineSubsystem, IOnlineSession, FOnlineSessionSettings
|
|
65
70
|
"OnlineSubsystemUtils", // Phase 30 - Online subsystem helper utilities
|
|
@@ -112,19 +112,22 @@ static TSharedPtr<FJsonObject> BuildBTCompositeNodeJson(UBTCompositeNode* Compos
|
|
|
112
112
|
NodeObj->SetStringField(TEXT("node_class"), Composite->GetClass()->GetName());
|
|
113
113
|
NodeObj->SetStringField(TEXT("node_type"), TEXT("Composite"));
|
|
114
114
|
|
|
115
|
-
// Build decorators array.
|
|
115
|
+
// Build decorators array from all children's decorators.
|
|
116
116
|
TArray<TSharedPtr<FJsonValue>> DecoratorsArray;
|
|
117
|
-
for (
|
|
117
|
+
for (const FBTCompositeChild& Child : Composite->Children)
|
|
118
118
|
{
|
|
119
|
-
|
|
119
|
+
for (UBTDecorator* Decorator : Child.Decorators)
|
|
120
120
|
{
|
|
121
|
-
|
|
121
|
+
if (!Decorator)
|
|
122
|
+
{
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
TSharedPtr<FJsonObject> DecObj = MakeShared<FJsonObject>();
|
|
126
|
+
DecObj->SetStringField(TEXT("node_name"), Decorator->GetNodeName());
|
|
127
|
+
DecObj->SetStringField(TEXT("node_class"), Decorator->GetClass()->GetName());
|
|
128
|
+
DecObj->SetStringField(TEXT("node_type"), TEXT("Decorator"));
|
|
129
|
+
DecoratorsArray.Add(MakeShared<FJsonValueObject>(DecObj));
|
|
122
130
|
}
|
|
123
|
-
TSharedPtr<FJsonObject> DecObj = MakeShared<FJsonObject>();
|
|
124
|
-
DecObj->SetStringField(TEXT("node_name"), Decorator->GetNodeName());
|
|
125
|
-
DecObj->SetStringField(TEXT("node_class"), Decorator->GetClass()->GetName());
|
|
126
|
-
DecObj->SetStringField(TEXT("node_type"), TEXT("Decorator"));
|
|
127
|
-
DecoratorsArray.Add(MakeShared<FJsonValueObject>(DecObj));
|
|
128
131
|
}
|
|
129
132
|
NodeObj->SetArrayField(TEXT("decorators"), DecoratorsArray);
|
|
130
133
|
|
|
@@ -680,7 +683,7 @@ void RegisterAICommands(FMCPCommandRouter& Router)
|
|
|
680
683
|
|
|
681
684
|
// Iterate the Options array.
|
|
682
685
|
TArray<TSharedPtr<FJsonValue>> OptionsArray;
|
|
683
|
-
for (UEnvQueryOption* Option : Query->
|
|
686
|
+
for (UEnvQueryOption* Option : Query->GetOptions())
|
|
684
687
|
{
|
|
685
688
|
if (!Option)
|
|
686
689
|
{
|
|
@@ -821,7 +824,7 @@ void RegisterAICommands(FMCPCommandRouter& Router)
|
|
|
821
824
|
}
|
|
822
825
|
|
|
823
826
|
// Get the main navigation data (e.g., RecastNavMesh).
|
|
824
|
-
ANavigationData* NavData = NavSys->
|
|
827
|
+
ANavigationData* NavData = NavSys->GetDefaultNavDataInstance(FNavigationSystem::DontCreate);
|
|
825
828
|
|
|
826
829
|
FString BuildStatus = TEXT("not_built");
|
|
827
830
|
FString NavDataClass = TEXT("None");
|
|
@@ -177,10 +177,10 @@ void RegisterActorCommands(FMCPCommandRouter& Router)
|
|
|
177
177
|
}
|
|
178
178
|
|
|
179
179
|
// Find actor class by name; try exact name then A-prefixed name.
|
|
180
|
-
UClass* ActorClass =
|
|
180
|
+
UClass* ActorClass = FindFirstObject<UClass>( *ClassName);
|
|
181
181
|
if (!ActorClass)
|
|
182
182
|
{
|
|
183
|
-
ActorClass =
|
|
183
|
+
ActorClass = FindFirstObject<UClass>( *(TEXT("A") + ClassName));
|
|
184
184
|
}
|
|
185
185
|
if (!ActorClass)
|
|
186
186
|
{
|
|
@@ -17,11 +17,14 @@
|
|
|
17
17
|
#include "Animation/AnimBlueprint.h"
|
|
18
18
|
#include "Animation/AnimMontage.h"
|
|
19
19
|
#include "Animation/BlendSpace.h"
|
|
20
|
+
#include "Animation/BlendSpace1D.h"
|
|
20
21
|
#include "Animation/AnimSequence.h"
|
|
21
22
|
|
|
22
23
|
// AnimGraph headers for state machine node access
|
|
23
24
|
#include "AnimGraphNode_StateMachine.h"
|
|
25
|
+
#include "AnimationStateMachineGraph.h"
|
|
24
26
|
#include "AnimStateNode.h"
|
|
27
|
+
#include "AnimStateTransitionNode.h"
|
|
25
28
|
|
|
26
29
|
// Asset Registry
|
|
27
30
|
#include "AssetRegistry/AssetRegistryModule.h"
|
|
@@ -30,6 +33,7 @@
|
|
|
30
33
|
// IKRetargeter -- from IKRig plugin
|
|
31
34
|
#if WITH_EDITOR
|
|
32
35
|
#include "Retargeter/IKRetargeter.h"
|
|
36
|
+
#include "Retargeter/IKRetargetChainMapping.h"
|
|
33
37
|
#endif
|
|
34
38
|
|
|
35
39
|
// JSON
|
|
@@ -268,8 +272,8 @@ void RegisterAnimationCommands(FMCPCommandRouter& Router)
|
|
|
268
272
|
TArray<TSharedPtr<FJsonValue>> StatesArray;
|
|
269
273
|
TArray<TSharedPtr<FJsonValue>> TransitionsArray;
|
|
270
274
|
|
|
271
|
-
// The state machine graph is referenced by
|
|
272
|
-
UEdGraph* SMGraph = SMNode->
|
|
275
|
+
// The state machine graph is referenced by EditorStateMachineGraph.
|
|
276
|
+
UEdGraph* SMGraph = Cast<UEdGraph>(SMNode->EditorStateMachineGraph.Get());
|
|
273
277
|
if (SMGraph)
|
|
274
278
|
{
|
|
275
279
|
for (UEdGraphNode* SMSubNode : SMGraph->Nodes)
|
|
@@ -427,9 +431,9 @@ void RegisterAnimationCommands(FMCPCommandRouter& Router)
|
|
|
427
431
|
for (const FCompositeSection& Section : Montage->CompositeSections)
|
|
428
432
|
{
|
|
429
433
|
FString LinkedSequenceName;
|
|
430
|
-
if (Section.
|
|
434
|
+
if (Section.GetLinkedSequence())
|
|
431
435
|
{
|
|
432
|
-
LinkedSequenceName = Section.
|
|
436
|
+
LinkedSequenceName = Section.GetLinkedSequence()->GetPathName();
|
|
433
437
|
}
|
|
434
438
|
|
|
435
439
|
TSharedPtr<FJsonObject> SectionObj = MakeShared<FJsonObject>();
|
|
@@ -536,7 +540,7 @@ void RegisterAnimationCommands(FMCPCommandRouter& Router)
|
|
|
536
540
|
const int32 NumAxes = bIs1D ? 1 : 2; // 1D uses 1 axis, 2D uses 2 axes (index 0 and 1).
|
|
537
541
|
for (int32 i = 0; i < NumAxes; ++i)
|
|
538
542
|
{
|
|
539
|
-
const FBlendParameter& Param = BlendSpace->
|
|
543
|
+
const FBlendParameter& Param = BlendSpace->GetBlendParameter(i);
|
|
540
544
|
TSharedPtr<FJsonObject> AxisObj = MakeShared<FJsonObject>();
|
|
541
545
|
AxisObj->SetStringField(TEXT("name"), Param.DisplayName);
|
|
542
546
|
AxisObj->SetNumberField(TEXT("min"), static_cast<double>(Param.Min));
|
|
@@ -547,7 +551,7 @@ void RegisterAnimationCommands(FMCPCommandRouter& Router)
|
|
|
547
551
|
|
|
548
552
|
// Build samples array from SampleData.
|
|
549
553
|
TArray<TSharedPtr<FJsonValue>> SamplesArray;
|
|
550
|
-
for (const FBlendSample& Sample : BlendSpace->
|
|
554
|
+
for (const FBlendSample& Sample : BlendSpace->GetBlendSamples())
|
|
551
555
|
{
|
|
552
556
|
FString AnimPath;
|
|
553
557
|
if (Sample.Animation)
|
|
@@ -617,13 +621,13 @@ void RegisterAnimationCommands(FMCPCommandRouter& Router)
|
|
|
617
621
|
FString SourceRigPath;
|
|
618
622
|
FString TargetRigPath;
|
|
619
623
|
|
|
620
|
-
const UIKRigDefinition* SourceRig = Retargeter->
|
|
624
|
+
const UIKRigDefinition* SourceRig = Retargeter->GetIKRig(ERetargetSourceOrTarget::Source);
|
|
621
625
|
if (SourceRig)
|
|
622
626
|
{
|
|
623
627
|
SourceRigPath = SourceRig->GetPathName();
|
|
624
628
|
}
|
|
625
629
|
|
|
626
|
-
const UIKRigDefinition* TargetRig = Retargeter->
|
|
630
|
+
const UIKRigDefinition* TargetRig = Retargeter->GetIKRig(ERetargetSourceOrTarget::Target);
|
|
627
631
|
if (TargetRig)
|
|
628
632
|
{
|
|
629
633
|
TargetRigPath = TargetRig->GetPathName();
|
|
@@ -631,11 +635,14 @@ void RegisterAnimationCommands(FMCPCommandRouter& Router)
|
|
|
631
635
|
|
|
632
636
|
// Collect chain mappings.
|
|
633
637
|
TArray<TSharedPtr<FJsonValue>> ChainMappingsArray;
|
|
634
|
-
|
|
638
|
+
PRAGMA_DISABLE_DEPRECATION_WARNINGS
|
|
639
|
+
const TArray<FRetargetChainPair>& ChainPairs = Retargeter->GetChainMapping().GetChainPairs();
|
|
640
|
+
PRAGMA_ENABLE_DEPRECATION_WARNINGS
|
|
641
|
+
for (const FRetargetChainPair& ChainPair : ChainPairs)
|
|
635
642
|
{
|
|
636
643
|
TSharedPtr<FJsonObject> MappingObj = MakeShared<FJsonObject>();
|
|
637
|
-
MappingObj->SetStringField(TEXT("source_chain"),
|
|
638
|
-
MappingObj->SetStringField(TEXT("target_chain"),
|
|
644
|
+
MappingObj->SetStringField(TEXT("source_chain"), ChainPair.SourceChainName.ToString());
|
|
645
|
+
MappingObj->SetStringField(TEXT("target_chain"), ChainPair.TargetChainName.ToString());
|
|
639
646
|
ChainMappingsArray.Add(MakeShared<FJsonValueObject>(MappingObj));
|
|
640
647
|
}
|
|
641
648
|
|
|
@@ -287,7 +287,7 @@ void RegisterAudioCommands(FMCPCommandRouter& Router)
|
|
|
287
287
|
AssetObj->SetNumberField(TEXT("sample_rate"), static_cast<double>(SoundWave->GetSampleRateForCurrentPlatform()));
|
|
288
288
|
AssetObj->SetNumberField(TEXT("num_channels"), static_cast<double>(SoundWave->NumChannels));
|
|
289
289
|
// Compression name from the compression format enum via Audio::ToName().
|
|
290
|
-
const FName CompressionFName = Audio::ToName(SoundWave->
|
|
290
|
+
const FName CompressionFName = Audio::ToName(SoundWave->GetSoundAssetCompressionType());
|
|
291
291
|
AssetObj->SetStringField(TEXT("compression_name"), CompressionFName.IsNone() ? TEXT("Unknown") : CompressionFName.ToString());
|
|
292
292
|
}
|
|
293
293
|
else
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
// Blueprint APIs
|
|
14
14
|
#include "Engine/Blueprint.h"
|
|
15
|
-
#include "BlueprintEditorUtils.h"
|
|
15
|
+
#include "Kismet2/BlueprintEditorUtils.h"
|
|
16
16
|
#include "EdGraph/EdGraph.h"
|
|
17
17
|
#include "EdGraph/EdGraphNode.h"
|
|
18
18
|
#include "EdGraph/EdGraphPin.h"
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
#include "AssetRegistry/AssetRegistryModule.h"
|
|
29
29
|
#include "AssetRegistry/IAssetRegistry.h"
|
|
30
30
|
#include "AssetRegistry/AssetData.h"
|
|
31
|
-
#include "Blueprint/
|
|
31
|
+
#include "Blueprint/BlueprintSupport.h"
|
|
32
32
|
|
|
33
33
|
// JSON APIs
|
|
34
34
|
#include "Dom/JsonObject.h"
|
package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPBlueprintWriteHandlers.cpp
CHANGED
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
// Asset APIs
|
|
32
32
|
#include "AssetRegistry/AssetRegistryModule.h"
|
|
33
33
|
#include "UObject/Package.h"
|
|
34
|
+
#include "UObject/SavePackage.h"
|
|
34
35
|
#include "Misc/PackageName.h"
|
|
35
36
|
|
|
36
37
|
// JSON APIs
|
|
@@ -146,17 +147,17 @@ void RegisterBlueprintWriteHandlers(FMCPCommandRouter& Router)
|
|
|
146
147
|
|
|
147
148
|
// T-10-01: Validate the asset path is a well-formed long package name.
|
|
148
149
|
// Rejects path traversal ("../") and bare filenames.
|
|
149
|
-
|
|
150
|
+
FText ValidationError;
|
|
150
151
|
if (!FPackageName::IsValidLongPackageName(AssetPath, /*bIncludeReadOnlyRoots=*/false, &ValidationError))
|
|
151
152
|
{
|
|
152
153
|
UE_LOG(LogTemp, Warning, TEXT("[MCPBridge] blueprint.create: Invalid asset path '%s': %s"),
|
|
153
|
-
*AssetPath, *ValidationError);
|
|
154
|
+
*AssetPath, *ValidationError.ToString());
|
|
154
155
|
SendError(SendResponse, CorrelationId, TEXT("invalid_asset_path"));
|
|
155
156
|
return;
|
|
156
157
|
}
|
|
157
158
|
|
|
158
159
|
// Resolve the parent class by name (try short name first, then full path).
|
|
159
|
-
UClass* ParentClass =
|
|
160
|
+
UClass* ParentClass = FindFirstObject<UClass>( *ParentClassName);
|
|
160
161
|
if (!ParentClass)
|
|
161
162
|
{
|
|
162
163
|
ParentClass = LoadObject<UClass>(nullptr, *ParentClassName);
|
|
@@ -214,8 +215,10 @@ void RegisterBlueprintWriteHandlers(FMCPCommandRouter& Router)
|
|
|
214
215
|
// Save the package to disk so the asset persists.
|
|
215
216
|
FString FilePath = FPackageName::LongPackageNameToFilename(
|
|
216
217
|
AssetPath, FPackageName::GetAssetPackageExtension());
|
|
217
|
-
|
|
218
|
-
|
|
218
|
+
FSavePackageArgs SaveArgs;
|
|
219
|
+
SaveArgs.TopLevelFlags = RF_Standalone;
|
|
220
|
+
SaveArgs.SaveFlags = SAVE_NoError;
|
|
221
|
+
UPackage::SavePackage(Pkg, NewBP, *FilePath, SaveArgs);
|
|
219
222
|
|
|
220
223
|
// Notify the Asset Registry so the asset appears in the Content Browser.
|
|
221
224
|
FAssetRegistryModule::AssetCreated(NewBP);
|
|
@@ -288,7 +291,7 @@ void RegisterBlueprintWriteHandlers(FMCPCommandRouter& Router)
|
|
|
288
291
|
}
|
|
289
292
|
|
|
290
293
|
// T-10-02: Resolve node class and validate it is a non-abstract UEdGraphNode subclass.
|
|
291
|
-
UClass* NodeClass =
|
|
294
|
+
UClass* NodeClass = FindFirstObject<UClass>( *NodeType);
|
|
292
295
|
if (!NodeClass)
|
|
293
296
|
{
|
|
294
297
|
UE_LOG(LogTemp, Warning, TEXT("[MCPBridge] blueprint.addNode: Node type '%s' not found"), *NodeType);
|
|
@@ -649,9 +652,18 @@ void RegisterBlueprintWriteHandlers(FMCPCommandRouter& Router)
|
|
|
649
652
|
return;
|
|
650
653
|
}
|
|
651
654
|
|
|
652
|
-
//
|
|
653
|
-
bool bSet =
|
|
654
|
-
|
|
655
|
+
// Find the variable in NewVariables and set its DefaultValue directly.
|
|
656
|
+
bool bSet = false;
|
|
657
|
+
const FName VarName(*TargetName);
|
|
658
|
+
for (FBPVariableDescription& VarDesc : BP->NewVariables)
|
|
659
|
+
{
|
|
660
|
+
if (VarDesc.VarName == VarName)
|
|
661
|
+
{
|
|
662
|
+
VarDesc.DefaultValue = DefaultValue;
|
|
663
|
+
bSet = true;
|
|
664
|
+
break;
|
|
665
|
+
}
|
|
666
|
+
}
|
|
655
667
|
if (!bSet)
|
|
656
668
|
{
|
|
657
669
|
UE_LOG(LogTemp, Warning, TEXT("[MCPBridge] blueprint.setDefault: Variable '%s' not found in '%s'"),
|
|
@@ -399,10 +399,10 @@ void RegisterChaosCommands(FMCPCommandRouter& Router)
|
|
|
399
399
|
GeoComp->Modify();
|
|
400
400
|
|
|
401
401
|
// Reset to initial unfractured state.
|
|
402
|
-
//
|
|
403
|
-
//
|
|
402
|
+
// ResetDynamicCollection() is protected in UE 5.7, so we use
|
|
403
|
+
// SetSimulatePhysics(false) + RecreatePhysicsState() as the public alternative.
|
|
404
404
|
GeoComp->SetSimulatePhysics(false);
|
|
405
|
-
GeoComp->
|
|
405
|
+
GeoComp->RecreatePhysicsState();
|
|
406
406
|
|
|
407
407
|
// Notify editor of the change.
|
|
408
408
|
GeoComp->PostEditChange();
|
package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPCollisionPhysicsCommands.cpp
CHANGED
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
#include "EngineUtils.h"
|
|
22
22
|
#include "Components/PrimitiveComponent.h"
|
|
23
23
|
#include "Engine/EngineTypes.h"
|
|
24
|
-
#include "CollisionProfile.h"
|
|
24
|
+
#include "Engine/CollisionProfile.h"
|
|
25
25
|
#include "PhysicsEngine/BodyInstance.h"
|
|
26
26
|
#include "PhysicalMaterials/PhysicalMaterial.h"
|
|
27
27
|
#include "PhysicsEngine/PhysicsAsset.h"
|
|
@@ -118,7 +118,7 @@ static TArray<TSharedPtr<FJsonValue>> BuildCollisionResponseArray(UPrimitiveComp
|
|
|
118
118
|
if (Profile)
|
|
119
119
|
{
|
|
120
120
|
// GetChannelName returns the display name for a given channel index.
|
|
121
|
-
ChannelName = Profile->
|
|
121
|
+
ChannelName = Profile->ReturnChannelNameFromContainerIndex(static_cast<int32>(Channel)).ToString();
|
|
122
122
|
}
|
|
123
123
|
if (ChannelName.IsEmpty())
|
|
124
124
|
{
|
|
@@ -148,7 +148,7 @@ static TSharedPtr<FJsonObject> BuildCollisionData(UPrimitiveComponent* Comp)
|
|
|
148
148
|
FString ObjectTypeName;
|
|
149
149
|
if (Profile)
|
|
150
150
|
{
|
|
151
|
-
ObjectTypeName = Profile->
|
|
151
|
+
ObjectTypeName = Profile->ReturnChannelNameFromContainerIndex(static_cast<int32>(ObjCh)).ToString();
|
|
152
152
|
}
|
|
153
153
|
if (ObjectTypeName.IsEmpty())
|
|
154
154
|
{
|
|
@@ -226,19 +226,35 @@ static void HandleGasAbilities(TSharedPtr<FJsonObject> Cmd, FMCPResponseSender S
|
|
|
226
226
|
AbilityObj->SetArrayField(TEXT("ability_tags"),
|
|
227
227
|
GameplayTagContainerToJsonArray(AbilityCDO->AbilityTags));
|
|
228
228
|
|
|
229
|
-
// Cancel / block tags
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
229
|
+
// Cancel / block tags (protected in UE 5.7, read via UE reflection)
|
|
230
|
+
{
|
|
231
|
+
TArray<TSharedPtr<FJsonValue>> CancelTagsArray;
|
|
232
|
+
TArray<TSharedPtr<FJsonValue>> BlockTagsArray;
|
|
233
|
+
if (FStructProperty* CancelProp = CastField<FStructProperty>(AbilityCDO->GetClass()->FindPropertyByName(TEXT("CancelAbilitiesWithTag"))))
|
|
234
|
+
{
|
|
235
|
+
const FGameplayTagContainer* CancelTags = CancelProp->ContainerPtrToValuePtr<FGameplayTagContainer>(AbilityCDO);
|
|
236
|
+
if (CancelTags)
|
|
237
|
+
{
|
|
238
|
+
CancelTagsArray = GameplayTagContainerToJsonArray(*CancelTags);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
if (FStructProperty* BlockProp = CastField<FStructProperty>(AbilityCDO->GetClass()->FindPropertyByName(TEXT("BlockAbilitiesWithTag"))))
|
|
242
|
+
{
|
|
243
|
+
const FGameplayTagContainer* BlockTags = BlockProp->ContainerPtrToValuePtr<FGameplayTagContainer>(AbilityCDO);
|
|
244
|
+
if (BlockTags)
|
|
245
|
+
{
|
|
246
|
+
BlockTagsArray = GameplayTagContainerToJsonArray(*BlockTags);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
AbilityObj->SetArrayField(TEXT("cancel_abilities_with_tag"), CancelTagsArray);
|
|
250
|
+
AbilityObj->SetArrayField(TEXT("block_abilities_with_tag"), BlockTagsArray);
|
|
251
|
+
}
|
|
234
252
|
|
|
235
253
|
// Cost and cooldown GE class references
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
FString CooldownGEName =
|
|
240
|
-
? AbilityCDO->CooldownGameplayEffectClass->GetName()
|
|
241
|
-
: TEXT("None");
|
|
254
|
+
UGameplayEffect* CostGE = AbilityCDO->GetCostGameplayEffect();
|
|
255
|
+
FString CostGEName = CostGE ? CostGE->GetClass()->GetName() : TEXT("None");
|
|
256
|
+
UGameplayEffect* CooldownGE = AbilityCDO->GetCooldownGameplayEffect();
|
|
257
|
+
FString CooldownGEName = CooldownGE ? CooldownGE->GetClass()->GetName() : TEXT("None");
|
|
242
258
|
AbilityObj->SetStringField(TEXT("cost_gameplay_effect_class"), CostGEName);
|
|
243
259
|
AbilityObj->SetStringField(TEXT("cooldown_gameplay_effect_class"), CooldownGEName);
|
|
244
260
|
|
|
@@ -415,13 +431,17 @@ static void HandleGasEffects(TSharedPtr<FJsonObject> Cmd, FMCPResponseSender Sen
|
|
|
415
431
|
Data->SetNumberField(TEXT("stack_limit_count"), (double)GEObj->StackLimitCount);
|
|
416
432
|
|
|
417
433
|
// Period interval (period is a FScalableFloat, extract base value)
|
|
418
|
-
float PeriodValue =
|
|
419
|
-
GEObj->Period.GetStaticValue(PeriodValue);
|
|
434
|
+
float PeriodValue = GEObj->Period.GetValue();
|
|
420
435
|
Data->SetNumberField(TEXT("period_interval"), (double)PeriodValue);
|
|
421
436
|
|
|
422
|
-
// Gameplay Cue tags
|
|
437
|
+
// Gameplay Cue tags (collected from all FGameplayEffectCue entries)
|
|
438
|
+
FGameplayTagContainer AllCueTags;
|
|
439
|
+
for (const FGameplayEffectCue& Cue : GEObj->GameplayCues)
|
|
440
|
+
{
|
|
441
|
+
AllCueTags.AppendTags(Cue.GameplayCueTags);
|
|
442
|
+
}
|
|
423
443
|
Data->SetArrayField(TEXT("gameplay_cue_tags"),
|
|
424
|
-
GameplayTagContainerToJsonArray(
|
|
444
|
+
GameplayTagContainerToJsonArray(AllCueTags));
|
|
425
445
|
|
|
426
446
|
SendResponse(BuildGASSuccessResponse(CorrId, Data) + TEXT("\n"));
|
|
427
447
|
}
|
|
@@ -21,14 +21,17 @@
|
|
|
21
21
|
#include "AssetToolsModule.h"
|
|
22
22
|
#include "IAssetTools.h"
|
|
23
23
|
#include "AssetImportTask.h"
|
|
24
|
-
#include "PackageName.h"
|
|
24
|
+
#include "Misc/PackageName.h"
|
|
25
25
|
|
|
26
26
|
// FBX Factory and Export
|
|
27
27
|
#include "Factories/FbxFactory.h"
|
|
28
|
+
#include "Factories/FbxImportUI.h"
|
|
29
|
+
#include "Factories/FbxStaticMeshImportData.h"
|
|
28
30
|
#include "Exporters/FbxExportOption.h"
|
|
29
31
|
|
|
30
32
|
// Interchange (USD import)
|
|
31
33
|
#include "InterchangeManager.h"
|
|
34
|
+
#include "InterchangeSourceData.h"
|
|
32
35
|
|
|
33
36
|
// Mesh types
|
|
34
37
|
#include "Engine/StaticMesh.h"
|
|
@@ -209,9 +212,9 @@ void RegisterImportExportCommands(FMCPCommandRouter& Router)
|
|
|
209
212
|
if (FbxFactory->ImportUI)
|
|
210
213
|
{
|
|
211
214
|
FbxFactory->ImportUI->bImportMaterials = bImportMaterials;
|
|
212
|
-
FbxFactory->ImportUI->bCombineMeshes = bCombineMeshes;
|
|
213
215
|
if (FbxFactory->ImportUI->StaticMeshImportData)
|
|
214
216
|
{
|
|
217
|
+
FbxFactory->ImportUI->StaticMeshImportData->bCombineMeshes = bCombineMeshes;
|
|
215
218
|
FbxFactory->ImportUI->StaticMeshImportData->ImportUniformScale = static_cast<float>(ScaleFactor);
|
|
216
219
|
}
|
|
217
220
|
}
|
|
@@ -301,12 +304,11 @@ void RegisterImportExportCommands(FMCPCommandRouter& Router)
|
|
|
301
304
|
|
|
302
305
|
if (GEditor && FModuleManager::Get().IsModuleLoaded(TEXT("InterchangeEngine")))
|
|
303
306
|
{
|
|
304
|
-
UInterchangeManager
|
|
305
|
-
if (InterchangeManager
|
|
307
|
+
UInterchangeManager& InterchangeManager = UInterchangeManager::GetInterchangeManager();
|
|
308
|
+
if (true) // InterchangeManager is always valid when module is loaded
|
|
306
309
|
{
|
|
307
|
-
// Use Interchange to import the USD file.
|
|
308
310
|
// Set up import parameters with the destination path.
|
|
309
|
-
|
|
311
|
+
FImportAssetParameters Params;
|
|
310
312
|
Params.bIsAutomated = true;
|
|
311
313
|
|
|
312
314
|
// Determine content path for Interchange. Normalize dest_path to directory.
|
|
@@ -320,9 +322,12 @@ void RegisterImportExportCommands(FMCPCommandRouter& Router)
|
|
|
320
322
|
ContentDir = FPackageName::GetLongPackagePath(ContentDir);
|
|
321
323
|
}
|
|
322
324
|
}
|
|
323
|
-
Params.OverrideDestinationPath = ContentDir;
|
|
324
325
|
|
|
325
|
-
|
|
326
|
+
// Create UInterchangeSourceData from the source file path.
|
|
327
|
+
UInterchangeSourceData* SourceData = NewObject<UInterchangeSourceData>(GetTransientPackage());
|
|
328
|
+
SourceData->SetFilename(SourceFile);
|
|
329
|
+
|
|
330
|
+
InterchangeManager.ImportAsset(ContentDir, SourceData, Params);
|
|
326
331
|
|
|
327
332
|
// Interchange is async; we report success with empty assets list.
|
|
328
333
|
// The engine will place assets at ContentDir when complete.
|
|
@@ -23,6 +23,9 @@
|
|
|
23
23
|
// Asset Registry APIs
|
|
24
24
|
#include "AssetRegistry/AssetRegistryModule.h"
|
|
25
25
|
|
|
26
|
+
// Package saving
|
|
27
|
+
#include "UObject/SavePackage.h"
|
|
28
|
+
|
|
26
29
|
// UObject/Package APIs
|
|
27
30
|
#include "UObject/Package.h"
|
|
28
31
|
#include "Misc/PackageName.h"
|
|
@@ -177,11 +180,11 @@ void RegisterInputHandlers(FMCPCommandRouter& Router)
|
|
|
177
180
|
|
|
178
181
|
// T-14-01: Validate the asset path is a well-formed long package name.
|
|
179
182
|
// Rejects path traversal ("../") and bare filenames.
|
|
180
|
-
|
|
183
|
+
FText ValidationError;
|
|
181
184
|
if (!FPackageName::IsValidLongPackageName(AssetPath, /*bIncludeReadOnlyRoots=*/false, &ValidationError))
|
|
182
185
|
{
|
|
183
186
|
UE_LOG(LogTemp, Warning, TEXT("[MCPBridge] input.createAction: Invalid asset path '%s': %s"),
|
|
184
|
-
*AssetPath, *ValidationError);
|
|
187
|
+
*AssetPath, *ValidationError.ToString());
|
|
185
188
|
SendError(SendResponse, CorrelationId, TEXT("invalid_asset_path"));
|
|
186
189
|
return;
|
|
187
190
|
}
|
|
@@ -227,8 +230,10 @@ void RegisterInputHandlers(FMCPCommandRouter& Router)
|
|
|
227
230
|
// Save the package to disk so the asset persists.
|
|
228
231
|
FString FilePath = FPackageName::LongPackageNameToFilename(
|
|
229
232
|
AssetPath, FPackageName::GetAssetPackageExtension());
|
|
230
|
-
|
|
231
|
-
|
|
233
|
+
FSavePackageArgs SaveArgs;
|
|
234
|
+
SaveArgs.TopLevelFlags = RF_Standalone;
|
|
235
|
+
SaveArgs.SaveFlags = SAVE_NoError;
|
|
236
|
+
UPackage::SavePackage(Pkg, Action, *FilePath, SaveArgs);
|
|
232
237
|
|
|
233
238
|
// Notify the Asset Registry so the asset appears in the Content Browser.
|
|
234
239
|
FAssetRegistryModule::AssetCreated(Action);
|
|
@@ -331,7 +336,7 @@ void RegisterInputHandlers(FMCPCommandRouter& Router)
|
|
|
331
336
|
|
|
332
337
|
// T-14-02: Validate that the key name resolves to a known FKey before calling MapKey.
|
|
333
338
|
// FKey constructor accepts any FName; IsValid() checks whether it is a registered key.
|
|
334
|
-
const FKey ResolvedKey(FName(*KeyName));
|
|
339
|
+
const FKey ResolvedKey = FKey(FName(*KeyName));
|
|
335
340
|
if (!ResolvedKey.IsValid())
|
|
336
341
|
{
|
|
337
342
|
UE_LOG(LogTemp, Warning, TEXT("[MCPBridge] input.addBinding: Key '%s' is not a valid FKey"), *KeyName);
|
|
@@ -369,8 +374,10 @@ void RegisterInputHandlers(FMCPCommandRouter& Router)
|
|
|
369
374
|
UPackage* Pkg = IMC->GetPackage();
|
|
370
375
|
FString FilePath = FPackageName::LongPackageNameToFilename(
|
|
371
376
|
AssetPath, FPackageName::GetAssetPackageExtension());
|
|
372
|
-
|
|
373
|
-
|
|
377
|
+
FSavePackageArgs SaveArgs2;
|
|
378
|
+
SaveArgs2.TopLevelFlags = RF_Standalone;
|
|
379
|
+
SaveArgs2.SaveFlags = SAVE_NoError;
|
|
380
|
+
UPackage::SavePackage(Pkg, IMC, *FilePath, SaveArgs2);
|
|
374
381
|
|
|
375
382
|
TSharedPtr<FJsonObject> Data = MakeShared<FJsonObject>();
|
|
376
383
|
Data->SetBoolField(TEXT("bound"), true);
|
|
@@ -206,7 +206,7 @@ void RegisterLiveLinkCommands(FMCPCommandRouter& Router)
|
|
|
206
206
|
ILiveLinkClient& Client = IModularFeatures::Get().GetModularFeature<ILiveLinkClient>(ILiveLinkClient::ModularFeatureName);
|
|
207
207
|
|
|
208
208
|
// Include disabled subjects so the full list is visible.
|
|
209
|
-
TArray<FLiveLinkSubjectKey> SubjectKeys = Client.GetSubjects(/*bIncludeDisabledSubjects=*/true);
|
|
209
|
+
TArray<FLiveLinkSubjectKey> SubjectKeys = Client.GetSubjects(/*bIncludeDisabledSubjects=*/true, /*bIncludeVirtualSubjects=*/true);
|
|
210
210
|
|
|
211
211
|
TArray<TSharedPtr<FJsonValue>> SubjectArray;
|
|
212
212
|
SubjectArray.Reserve(SubjectKeys.Num());
|
|
@@ -223,8 +223,8 @@ void RegisterLiveLinkCommands(FMCPCommandRouter& Router)
|
|
|
223
223
|
if (Settings)
|
|
224
224
|
{
|
|
225
225
|
RoleName = GetRoleFriendlyName(Settings->Role);
|
|
226
|
-
bEnabled = Settings->bEnabled;
|
|
227
226
|
}
|
|
227
|
+
bEnabled = Client.IsSubjectEnabled(SubjectKey, /*bForThisFrame=*/false);
|
|
228
228
|
|
|
229
229
|
TSharedPtr<FJsonObject> SubjectObj = MakeShared<FJsonObject>();
|
|
230
230
|
SubjectObj->SetStringField(TEXT("subject_name"), SubjectName);
|
|
@@ -278,7 +278,7 @@ void RegisterLiveLinkCommands(FMCPCommandRouter& Router)
|
|
|
278
278
|
ILiveLinkClient& Client = IModularFeatures::Get().GetModularFeature<ILiveLinkClient>(ILiveLinkClient::ModularFeatureName);
|
|
279
279
|
|
|
280
280
|
// T-27-01: Find subject by exact name match from GetSubjects() -- never use raw input as key.
|
|
281
|
-
TArray<FLiveLinkSubjectKey> SubjectKeys = Client.GetSubjects(/*bIncludeDisabledSubjects=*/true);
|
|
281
|
+
TArray<FLiveLinkSubjectKey> SubjectKeys = Client.GetSubjects(/*bIncludeDisabledSubjects=*/true, /*bIncludeVirtualSubjects=*/true);
|
|
282
282
|
|
|
283
283
|
bool bFound = false;
|
|
284
284
|
for (const FLiveLinkSubjectKey& SubjectKey : SubjectKeys)
|
|
@@ -294,7 +294,7 @@ void RegisterLiveLinkCommands(FMCPCommandRouter& Router)
|
|
|
294
294
|
}
|
|
295
295
|
|
|
296
296
|
// Toggle the enabled state (runtime-only; no Modify() needed for Live Link subject state).
|
|
297
|
-
|
|
297
|
+
Client.SetSubjectEnabled(SubjectKey, bEnabled);
|
|
298
298
|
|
|
299
299
|
const FString StateMessage = bEnabled
|
|
300
300
|
? TEXT("Subject resumed")
|
|
@@ -349,7 +349,7 @@ void RegisterLiveLinkCommands(FMCPCommandRouter& Router)
|
|
|
349
349
|
ILiveLinkClient& Client = IModularFeatures::Get().GetModularFeature<ILiveLinkClient>(ILiveLinkClient::ModularFeatureName);
|
|
350
350
|
|
|
351
351
|
// T-27-01: Find subject by exact name match from GetSubjects() -- never use raw input as key.
|
|
352
|
-
TArray<FLiveLinkSubjectKey> SubjectKeys = Client.GetSubjects(/*bIncludeDisabledSubjects=*/true);
|
|
352
|
+
TArray<FLiveLinkSubjectKey> SubjectKeys = Client.GetSubjects(/*bIncludeDisabledSubjects=*/true, /*bIncludeVirtualSubjects=*/true);
|
|
353
353
|
|
|
354
354
|
bool bFound = false;
|
|
355
355
|
for (const FLiveLinkSubjectKey& SubjectKey : SubjectKeys)
|
|
@@ -374,7 +374,7 @@ void RegisterLiveLinkCommands(FMCPCommandRouter& Router)
|
|
|
374
374
|
|
|
375
375
|
// Retrieve the latest frame data.
|
|
376
376
|
FLiveLinkSubjectFrameData FrameData;
|
|
377
|
-
const bool bHasData = Client.EvaluateFrame_AnyThread(SubjectKey, RoleClass, FrameData);
|
|
377
|
+
const bool bHasData = Client.EvaluateFrame_AnyThread(SubjectKey.SubjectName, RoleClass, FrameData);
|
|
378
378
|
|
|
379
379
|
if (!bHasData || !FrameData.StaticData.IsValid() || !FrameData.FrameData.IsValid())
|
|
380
380
|
{
|