ue-mcp 1.3.8-beta.13 → 1.3.8-beta.14
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/dist/tool-counts.json +2 -2
- package/package.json +1 -1
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/HandlerJsonProperty.h +1 -1
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/HandlerPoseSearchSchema.h +29 -1
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_Depth.cpp +10 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_IKRigAuthoring.cpp +1 -1
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_MotionMatching.cpp +174 -36
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_Sequence.cpp +32 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_SkeletalLive.cpp +13 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_Skeleton.cpp +66 -5
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_StateMachine.cpp +34 -8
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_GeometryScript.cpp +4 -4
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Import.cpp +30 -4
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_MeshBoolean.cpp +4 -4
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Struct.cpp +1 -1
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AudioHandlers_Depth.cpp +85 -2
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AudioHandlers_MetaSound.cpp +126 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AudioHandlers_MetaSoundRead.cpp +78 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers.cpp +11 -2
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers_UserTypes.cpp +20 -1
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/ChooserHandlers.cpp +93 -8
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/ChooserHandlers_Nested.cpp +4 -3
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/EditorHandlers.cpp +84 -12
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/EditorHandlers_Build.cpp +10 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/EditorHandlers_Profiling.cpp +55 -5
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GameplayHandlers.cpp +11 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GameplayHandlers_BTAuthoring.cpp +15 -2
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GasHandlers.h +15 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GasHandlers_Runtime.cpp +1 -1
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GasHandlers_Snapshot.cpp +1 -1
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LandscapeHandlers.cpp +20 -1
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LandscapeHandlers_Sculpt.cpp +30 -9
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers.cpp +5 -5
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Query.cpp +2 -2
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Save.cpp +3 -1
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_WorldPartitionSettings.cpp +8 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/MaterialHandlers_Build.cpp +6 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/MaterialHandlers_RVT.cpp +45 -8
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/NiagaraHandlers.cpp +80 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/NiagaraHandlers_Advanced.cpp +10 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/ProjectHandlers_Plugins.cpp +15 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/SequencerHandlers.cpp +27 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/SkeletalMeshHandlers.cpp +7 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/StateTreeHandlers.cpp +1 -1
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/StateTreeHandlers_Depth.cpp +1 -3
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/AssetDeleteGuardTests.cpp +1 -1
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/AssetPropertyPersistTests.cpp +1 -1
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/AssetSubobjectTests.cpp +1 -1
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/DataTableRowWriteTests.cpp +9 -1
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/MCPInstancedStructPathTestTypes.h +1 -1
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/PackageWriteGuardTests.cpp +1 -1
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Public/HandlerPagination.h +15 -4
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Public/HandlerUtils.h +66 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Public/MCPEngineCompat.h +38 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/UE_MCP_Bridge.Build.cs +18 -2
- package/plugin/ue_mcp_bridge/UE_MCP_Bridge.uplugin +1 -1
package/dist/tool-counts.json
CHANGED
package/package.json
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
#include "UObject/UnrealType.h"
|
|
11
11
|
#include "UObject/PropertyPortFlags.h"
|
|
12
12
|
#include "UObject/SoftObjectPtr.h"
|
|
13
|
-
#include "
|
|
13
|
+
#include "MCPEngineCompat.h"
|
|
14
14
|
#include "GameplayTagContainer.h"
|
|
15
15
|
#include "GameplayTagsManager.h"
|
|
16
16
|
#include "Engine/Blueprint.h"
|
|
@@ -19,9 +19,37 @@
|
|
|
19
19
|
#include "CoreMinimal.h"
|
|
20
20
|
#include "UObject/UnrealType.h"
|
|
21
21
|
#include "PoseSearch/PoseSearchSchema.h"
|
|
22
|
+
#include "HandlerUtils.h"
|
|
22
23
|
|
|
23
24
|
namespace MCPPoseSearch
|
|
24
25
|
{
|
|
26
|
+
/** The schema's per-role skeletons.
|
|
27
|
+
*
|
|
28
|
+
* 5.5 added GetRoledSkeletons(). On 5.4 the Skeletons array is private
|
|
29
|
+
* with no accessor at all, so it is read through the property system -
|
|
30
|
+
* FPoseSearchRoledSkeleton itself is public there, only the member is not.
|
|
31
|
+
* Returned by value so both engines present the same signature; the
|
|
32
|
+
* callers are read paths over a handful of roles. */
|
|
33
|
+
inline TArray<FPoseSearchRoledSkeleton> RoledSkeletons(const UPoseSearchSchema* Schema)
|
|
34
|
+
{
|
|
35
|
+
TArray<FPoseSearchRoledSkeleton> Out;
|
|
36
|
+
if (!Schema) return Out;
|
|
37
|
+
#if UE_MCP_HAS_5_5_API
|
|
38
|
+
Out = Schema->GetRoledSkeletons();
|
|
39
|
+
#else
|
|
40
|
+
if (const FArrayProperty* Prop = FindFProperty<FArrayProperty>(UPoseSearchSchema::StaticClass(), TEXT("Skeletons")))
|
|
41
|
+
{
|
|
42
|
+
FScriptArrayHelper Helper(Prop, Prop->ContainerPtrToValuePtr<void>(Schema));
|
|
43
|
+
Out.Reserve(Helper.Num());
|
|
44
|
+
for (int32 Index = 0; Index < Helper.Num(); ++Index)
|
|
45
|
+
{
|
|
46
|
+
Out.Add(*reinterpret_cast<const FPoseSearchRoledSkeleton*>(Helper.GetRawPtr(Index)));
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
#endif
|
|
50
|
+
return Out;
|
|
51
|
+
}
|
|
52
|
+
|
|
25
53
|
/** Recompute FinalizedChannels and SchemaCardinality after a channel or
|
|
26
54
|
* skeleton edit. Finalize() itself is private; PostEditChangeProperty is
|
|
27
55
|
* the public door onto it. */
|
|
@@ -44,7 +72,7 @@ namespace MCPPoseSearch
|
|
|
44
72
|
TArray<FString> Problems;
|
|
45
73
|
|
|
46
74
|
bool bHasSkeleton = false;
|
|
47
|
-
for (const FPoseSearchRoledSkeleton& Roled : Schema
|
|
75
|
+
for (const FPoseSearchRoledSkeleton& Roled : RoledSkeletons(Schema))
|
|
48
76
|
{
|
|
49
77
|
if (Roled.Skeleton)
|
|
50
78
|
{
|
package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_Depth.cpp
CHANGED
|
@@ -282,7 +282,17 @@ TSharedPtr<FJsonValue> FAnimationHandlers::SetStateMachineEntry(const TSharedPtr
|
|
|
282
282
|
TEXT("Recreate it with animation(create_state_machine)."), *SMName));
|
|
283
283
|
}
|
|
284
284
|
|
|
285
|
+
#if UE_MCP_HAS_5_5_API
|
|
285
286
|
UEdGraphPin* EntryPin = Entry->GetOutputPin();
|
|
287
|
+
#else
|
|
288
|
+
// 5.4's UAnimStateEntryNode has no GetOutputPin(); the entry node allocates
|
|
289
|
+
// exactly one output pin, which is the same pin that accessor returns.
|
|
290
|
+
UEdGraphPin* EntryPin = nullptr;
|
|
291
|
+
for (UEdGraphPin* Pin : Entry->Pins)
|
|
292
|
+
{
|
|
293
|
+
if (Pin && Pin->Direction == EGPD_Output) { EntryPin = Pin; break; }
|
|
294
|
+
}
|
|
295
|
+
#endif
|
|
286
296
|
if (!EntryPin)
|
|
287
297
|
{
|
|
288
298
|
return MCPError(TEXT("The state machine's entry node has no output pin."));
|
|
@@ -15,8 +15,17 @@
|
|
|
15
15
|
#include "PoseSearch/PoseSearchSchema.h"
|
|
16
16
|
#include "HandlerPoseSearchSchema.h"
|
|
17
17
|
#include "PoseSearch/PoseSearchFeatureChannel.h"
|
|
18
|
+
#if UE_MCP_HAS_5_5_API
|
|
18
19
|
#include "PoseSearch/PoseSearchFeatureChannel_Pose.h"
|
|
19
20
|
#include "PoseSearch/PoseSearchFeatureChannel_Trajectory.h"
|
|
21
|
+
#else
|
|
22
|
+
// UE 5.4 keeps both channel headers (and the FPoseSearchBone /
|
|
23
|
+
// FPoseSearchTrajectorySample structs inside them) private to the PoseSearch
|
|
24
|
+
// module, so nothing outside it can name the types. The classes are still
|
|
25
|
+
// UCLASSes with reflected properties, so the two channel actions author them
|
|
26
|
+
// through the property system instead - same asset, same fields, no header.
|
|
27
|
+
#include "HandlerJsonProperty.h"
|
|
28
|
+
#endif
|
|
20
29
|
#include "PoseSearch/PoseSearchDatabase.h"
|
|
21
30
|
#include "PoseSearch/PoseSearchNormalizationSet.h"
|
|
22
31
|
#include "Animation/MirrorDataTable.h"
|
|
@@ -63,13 +72,47 @@ static int32 ParseFlagArray(const TSharedPtr<FJsonObject>& Obj, const TCHAR* Fie
|
|
|
63
72
|
return Flags == 0 ? Default : Flags;
|
|
64
73
|
}
|
|
65
74
|
|
|
75
|
+
// Bit values of EPoseSearchBoneFlags / EPoseSearchTrajectoryFlags. They are
|
|
76
|
+
// spelled out rather than taken from the enums because on 5.4 the enums are
|
|
77
|
+
// declared in the private channel headers; these are the values the asset
|
|
78
|
+
// serializes and they are the same from 5.4 through 5.8.
|
|
79
|
+
static constexpr int32 MCPBoneFlagVelocity = 1 << 0;
|
|
80
|
+
static constexpr int32 MCPBoneFlagPosition = 1 << 1;
|
|
81
|
+
static constexpr int32 MCPBoneFlagRotation = 1 << 2;
|
|
82
|
+
static constexpr int32 MCPBoneFlagPhase = 1 << 3;
|
|
83
|
+
|
|
84
|
+
static constexpr int32 MCPTrajFlagVelocity = 1 << 0;
|
|
85
|
+
static constexpr int32 MCPTrajFlagPosition = 1 << 1;
|
|
86
|
+
static constexpr int32 MCPTrajFlagVelocityDirection = 1 << 2;
|
|
87
|
+
static constexpr int32 MCPTrajFlagFacingDirection = 1 << 3;
|
|
88
|
+
static constexpr int32 MCPTrajFlagVelocityXY = 1 << 4;
|
|
89
|
+
static constexpr int32 MCPTrajFlagPositionXY = 1 << 5;
|
|
90
|
+
static constexpr int32 MCPTrajFlagVelocityDirectionXY = 1 << 6;
|
|
91
|
+
static constexpr int32 MCPTrajFlagFacingDirectionXY = 1 << 7;
|
|
92
|
+
|
|
93
|
+
#if UE_MCP_HAS_5_5_API
|
|
94
|
+
// Where the enums are reachable, hold the spelled-out values to them.
|
|
95
|
+
static_assert(MCPBoneFlagVelocity == int32(EPoseSearchBoneFlags::Velocity), "EPoseSearchBoneFlags::Velocity moved");
|
|
96
|
+
static_assert(MCPBoneFlagPosition == int32(EPoseSearchBoneFlags::Position), "EPoseSearchBoneFlags::Position moved");
|
|
97
|
+
static_assert(MCPBoneFlagRotation == int32(EPoseSearchBoneFlags::Rotation), "EPoseSearchBoneFlags::Rotation moved");
|
|
98
|
+
static_assert(MCPBoneFlagPhase == int32(EPoseSearchBoneFlags::Phase), "EPoseSearchBoneFlags::Phase moved");
|
|
99
|
+
static_assert(MCPTrajFlagVelocity == int32(EPoseSearchTrajectoryFlags::Velocity), "EPoseSearchTrajectoryFlags::Velocity moved");
|
|
100
|
+
static_assert(MCPTrajFlagPosition == int32(EPoseSearchTrajectoryFlags::Position), "EPoseSearchTrajectoryFlags::Position moved");
|
|
101
|
+
static_assert(MCPTrajFlagVelocityDirection == int32(EPoseSearchTrajectoryFlags::VelocityDirection), "EPoseSearchTrajectoryFlags::VelocityDirection moved");
|
|
102
|
+
static_assert(MCPTrajFlagFacingDirection == int32(EPoseSearchTrajectoryFlags::FacingDirection), "EPoseSearchTrajectoryFlags::FacingDirection moved");
|
|
103
|
+
static_assert(MCPTrajFlagVelocityXY == int32(EPoseSearchTrajectoryFlags::VelocityXY), "EPoseSearchTrajectoryFlags::VelocityXY moved");
|
|
104
|
+
static_assert(MCPTrajFlagPositionXY == int32(EPoseSearchTrajectoryFlags::PositionXY), "EPoseSearchTrajectoryFlags::PositionXY moved");
|
|
105
|
+
static_assert(MCPTrajFlagVelocityDirectionXY == int32(EPoseSearchTrajectoryFlags::VelocityDirectionXY), "EPoseSearchTrajectoryFlags::VelocityDirectionXY moved");
|
|
106
|
+
static_assert(MCPTrajFlagFacingDirectionXY == int32(EPoseSearchTrajectoryFlags::FacingDirectionXY), "EPoseSearchTrajectoryFlags::FacingDirectionXY moved");
|
|
107
|
+
#endif
|
|
108
|
+
|
|
66
109
|
static const TMap<FString, int32>& BoneFlagTable()
|
|
67
110
|
{
|
|
68
111
|
static const TMap<FString, int32> Table = {
|
|
69
|
-
{ TEXT("velocity"),
|
|
70
|
-
{ TEXT("position"),
|
|
71
|
-
{ TEXT("rotation"),
|
|
72
|
-
{ TEXT("phase"),
|
|
112
|
+
{ TEXT("velocity"), MCPBoneFlagVelocity },
|
|
113
|
+
{ TEXT("position"), MCPBoneFlagPosition },
|
|
114
|
+
{ TEXT("rotation"), MCPBoneFlagRotation },
|
|
115
|
+
{ TEXT("phase"), MCPBoneFlagPhase },
|
|
73
116
|
};
|
|
74
117
|
return Table;
|
|
75
118
|
}
|
|
@@ -77,18 +120,36 @@ static const TMap<FString, int32>& BoneFlagTable()
|
|
|
77
120
|
static const TMap<FString, int32>& TrajectoryFlagTable()
|
|
78
121
|
{
|
|
79
122
|
static const TMap<FString, int32> Table = {
|
|
80
|
-
{ TEXT("velocity"),
|
|
81
|
-
{ TEXT("position"),
|
|
82
|
-
{ TEXT("velocitydirection"),
|
|
83
|
-
{ TEXT("facingdirection"),
|
|
84
|
-
{ TEXT("velocityxy"),
|
|
85
|
-
{ TEXT("positionxy"),
|
|
86
|
-
{ TEXT("velocitydirectionxy"),
|
|
87
|
-
{ TEXT("facingdirectionxy"),
|
|
123
|
+
{ TEXT("velocity"), MCPTrajFlagVelocity },
|
|
124
|
+
{ TEXT("position"), MCPTrajFlagPosition },
|
|
125
|
+
{ TEXT("velocitydirection"), MCPTrajFlagVelocityDirection },
|
|
126
|
+
{ TEXT("facingdirection"), MCPTrajFlagFacingDirection },
|
|
127
|
+
{ TEXT("velocityxy"), MCPTrajFlagVelocityXY },
|
|
128
|
+
{ TEXT("positionxy"), MCPTrajFlagPositionXY },
|
|
129
|
+
{ TEXT("velocitydirectionxy"), MCPTrajFlagVelocityDirectionXY },
|
|
130
|
+
{ TEXT("facingdirectionxy"), MCPTrajFlagFacingDirectionXY },
|
|
88
131
|
};
|
|
89
132
|
return Table;
|
|
90
133
|
}
|
|
91
134
|
|
|
135
|
+
#if !UE_MCP_HAS_5_5_API
|
|
136
|
+
/** Construct one of the PoseSearch channel classes by its script path. On 5.4
|
|
137
|
+
* the concrete classes are private to the PoseSearch module, but the UClass is
|
|
138
|
+
* registered like any other, so the object is created through it. */
|
|
139
|
+
static UPoseSearchFeatureChannel* MCPNewPoseSearchChannel(UPoseSearchSchema* Schema, const TCHAR* ClassPath)
|
|
140
|
+
{
|
|
141
|
+
UClass* ChannelClass = FindObject<UClass>(nullptr, ClassPath);
|
|
142
|
+
if (!ChannelClass) return nullptr;
|
|
143
|
+
return NewObject<UPoseSearchFeatureChannel>(Schema, ChannelClass, NAME_None, RF_Transactional);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/** Write one reflected property of a channel from JSON. */
|
|
147
|
+
static bool MCPSetChannelProperty(UPoseSearchFeatureChannel* Channel, const TCHAR* PropertyName, const TSharedPtr<FJsonValue>& Value, FString& OutError)
|
|
148
|
+
{
|
|
149
|
+
return MCPJsonProperty::SetDottedPropertyFromJson(Channel, PropertyName, Value, OutError);
|
|
150
|
+
}
|
|
151
|
+
#endif
|
|
152
|
+
|
|
92
153
|
// ─── AnimGraph node authoring helpers ─────────────────────────────────────
|
|
93
154
|
|
|
94
155
|
// Anim graph nodes keep their settings in a private `Node` USTRUCT member. Reach
|
|
@@ -228,23 +289,22 @@ TSharedPtr<FJsonValue> FAnimationHandlers::AddPoseSearchSchemaPoseChannel(const
|
|
|
228
289
|
return MCPError(TEXT("Missing 'bones' (array of {bone, flags?:[velocity,position,rotation,phase], weight?})"));
|
|
229
290
|
}
|
|
230
291
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
292
|
+
// Parse first, engine-independently, then write the parsed bones into the
|
|
293
|
+
// channel the way the running engine allows.
|
|
294
|
+
struct FParsedBone { FString Name; int32 Flags; float Weight; };
|
|
295
|
+
TArray<FParsedBone> ParsedBones;
|
|
236
296
|
TArray<TSharedPtr<FJsonValue>> Added;
|
|
237
297
|
for (const TSharedPtr<FJsonValue>& V : *Bones)
|
|
238
298
|
{
|
|
239
299
|
const TSharedPtr<FJsonObject>* BoneObj = nullptr;
|
|
240
300
|
FString BoneName;
|
|
241
|
-
int32 Flags =
|
|
301
|
+
int32 Flags = MCPBoneFlagPosition;
|
|
242
302
|
float Weight = 1.f;
|
|
243
303
|
if (V->TryGetObject(BoneObj) && BoneObj && (*BoneObj).IsValid())
|
|
244
304
|
{
|
|
245
305
|
if (!(*BoneObj)->TryGetStringField(TEXT("bone"), BoneName))
|
|
246
306
|
return MCPError(TEXT("Each bone entry needs a 'bone' name"));
|
|
247
|
-
Flags = ParseFlagArray(*BoneObj, TEXT("flags"), BoneFlagTable(),
|
|
307
|
+
Flags = ParseFlagArray(*BoneObj, TEXT("flags"), BoneFlagTable(), MCPBoneFlagPosition);
|
|
248
308
|
double W = 0.0;
|
|
249
309
|
if ((*BoneObj)->TryGetNumberField(TEXT("weight"), W)) Weight = (float)W;
|
|
250
310
|
}
|
|
@@ -253,13 +313,52 @@ TSharedPtr<FJsonValue> FAnimationHandlers::AddPoseSearchSchemaPoseChannel(const
|
|
|
253
313
|
return MCPError(TEXT("Each bone entry must be an object or a bone-name string"));
|
|
254
314
|
}
|
|
255
315
|
|
|
316
|
+
ParsedBones.Add({ BoneName, Flags, Weight });
|
|
317
|
+
Added.Add(MakeShared<FJsonValueString>(BoneName));
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
Schema->Modify();
|
|
321
|
+
double ChannelWeight = 0.0;
|
|
322
|
+
const bool bHasChannelWeight = Params->TryGetNumberField(TEXT("weight"), ChannelWeight);
|
|
323
|
+
|
|
324
|
+
#if UE_MCP_HAS_5_5_API
|
|
325
|
+
UPoseSearchFeatureChannel_Pose* Channel = NewObject<UPoseSearchFeatureChannel_Pose>(Schema, NAME_None, RF_Transactional);
|
|
326
|
+
if (bHasChannelWeight) Channel->Weight = (float)ChannelWeight;
|
|
327
|
+
for (const FParsedBone& Parsed : ParsedBones)
|
|
328
|
+
{
|
|
256
329
|
FPoseSearchBone Bone;
|
|
257
|
-
Bone.Reference.BoneName = FName(*
|
|
258
|
-
Bone.Flags = Flags;
|
|
259
|
-
Bone.Weight = Weight;
|
|
330
|
+
Bone.Reference.BoneName = FName(*Parsed.Name);
|
|
331
|
+
Bone.Flags = Parsed.Flags;
|
|
332
|
+
Bone.Weight = Parsed.Weight;
|
|
260
333
|
Channel->SampledBones.Add(Bone);
|
|
261
|
-
Added.Add(MakeShared<FJsonValueString>(BoneName));
|
|
262
334
|
}
|
|
335
|
+
#else
|
|
336
|
+
UPoseSearchFeatureChannel* Channel = MCPNewPoseSearchChannel(Schema, TEXT("/Script/PoseSearch.PoseSearchFeatureChannel_Pose"));
|
|
337
|
+
if (!Channel) return MCPError(TEXT("PoseSearchFeatureChannel_Pose class is not loaded - is the PoseSearch plugin enabled?"));
|
|
338
|
+
|
|
339
|
+
FString PropertyError;
|
|
340
|
+
if (bHasChannelWeight && !MCPSetChannelProperty(Channel, TEXT("Weight"), MakeShared<FJsonValueNumber>(ChannelWeight), PropertyError))
|
|
341
|
+
{
|
|
342
|
+
return MCPError(FString::Printf(TEXT("Could not set channel weight: %s"), *PropertyError));
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
TArray<TSharedPtr<FJsonValue>> BoneStructs;
|
|
346
|
+
for (const FParsedBone& Parsed : ParsedBones)
|
|
347
|
+
{
|
|
348
|
+
TSharedPtr<FJsonObject> Reference = MakeShared<FJsonObject>();
|
|
349
|
+
Reference->SetStringField(TEXT("BoneName"), Parsed.Name);
|
|
350
|
+
|
|
351
|
+
TSharedPtr<FJsonObject> Bone = MakeShared<FJsonObject>();
|
|
352
|
+
Bone->SetObjectField(TEXT("Reference"), Reference);
|
|
353
|
+
Bone->SetNumberField(TEXT("Flags"), Parsed.Flags);
|
|
354
|
+
Bone->SetNumberField(TEXT("Weight"), Parsed.Weight);
|
|
355
|
+
BoneStructs.Add(MakeShared<FJsonValueObject>(Bone));
|
|
356
|
+
}
|
|
357
|
+
if (!MCPSetChannelProperty(Channel, TEXT("SampledBones"), MakeShared<FJsonValueArray>(BoneStructs), PropertyError))
|
|
358
|
+
{
|
|
359
|
+
return MCPError(FString::Printf(TEXT("Could not set SampledBones: %s"), *PropertyError));
|
|
360
|
+
}
|
|
361
|
+
#endif
|
|
263
362
|
|
|
264
363
|
Schema->AddChannel(Channel);
|
|
265
364
|
MCPPoseSearch::Finalize(Schema);
|
|
@@ -292,28 +391,62 @@ TSharedPtr<FJsonValue> FAnimationHandlers::AddPoseSearchSchemaTrajectoryChannel(
|
|
|
292
391
|
return MCPError(TEXT("Missing 'samples' (array of {offset, flags?:[position,velocity,facingDirection,...], weight?}). Negative offsets are history, positive are prediction."));
|
|
293
392
|
}
|
|
294
393
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
double ChannelWeight = 0.0;
|
|
298
|
-
if (Params->TryGetNumberField(TEXT("weight"), ChannelWeight)) Channel->Weight = (float)ChannelWeight;
|
|
299
|
-
|
|
300
|
-
int32 Count = 0;
|
|
394
|
+
struct FParsedSample { float Offset; int32 Flags; float Weight; };
|
|
395
|
+
TArray<FParsedSample> ParsedSamples;
|
|
301
396
|
for (const TSharedPtr<FJsonValue>& V : *Samples)
|
|
302
397
|
{
|
|
303
398
|
const TSharedPtr<FJsonObject>* SampleObj = nullptr;
|
|
304
399
|
if (!V->TryGetObject(SampleObj) || !SampleObj || !(*SampleObj).IsValid())
|
|
305
400
|
return MCPError(TEXT("Each sample must be an object {offset, flags?, weight?}"));
|
|
306
401
|
|
|
307
|
-
FPoseSearchTrajectorySample Sample;
|
|
308
402
|
double Offset = 0.0;
|
|
309
403
|
(*SampleObj)->TryGetNumberField(TEXT("offset"), Offset);
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
404
|
+
const int32 Flags = ParseFlagArray(*SampleObj, TEXT("flags"), TrajectoryFlagTable(), MCPTrajFlagPosition);
|
|
405
|
+
double W = 1.0;
|
|
406
|
+
(*SampleObj)->TryGetNumberField(TEXT("weight"), W);
|
|
407
|
+
ParsedSamples.Add({ (float)Offset, Flags, (float)W });
|
|
408
|
+
}
|
|
409
|
+
const int32 Count = ParsedSamples.Num();
|
|
410
|
+
|
|
411
|
+
Schema->Modify();
|
|
412
|
+
double ChannelWeight = 0.0;
|
|
413
|
+
const bool bHasChannelWeight = Params->TryGetNumberField(TEXT("weight"), ChannelWeight);
|
|
414
|
+
|
|
415
|
+
#if UE_MCP_HAS_5_5_API
|
|
416
|
+
UPoseSearchFeatureChannel_Trajectory* Channel = NewObject<UPoseSearchFeatureChannel_Trajectory>(Schema, NAME_None, RF_Transactional);
|
|
417
|
+
if (bHasChannelWeight) Channel->Weight = (float)ChannelWeight;
|
|
418
|
+
for (const FParsedSample& Parsed : ParsedSamples)
|
|
419
|
+
{
|
|
420
|
+
FPoseSearchTrajectorySample Sample;
|
|
421
|
+
Sample.Offset = Parsed.Offset;
|
|
422
|
+
Sample.Flags = Parsed.Flags;
|
|
423
|
+
Sample.Weight = Parsed.Weight;
|
|
314
424
|
Channel->Samples.Add(Sample);
|
|
315
|
-
++Count;
|
|
316
425
|
}
|
|
426
|
+
#else
|
|
427
|
+
UPoseSearchFeatureChannel* Channel = MCPNewPoseSearchChannel(Schema, TEXT("/Script/PoseSearch.PoseSearchFeatureChannel_Trajectory"));
|
|
428
|
+
if (!Channel) return MCPError(TEXT("PoseSearchFeatureChannel_Trajectory class is not loaded - is the PoseSearch plugin enabled?"));
|
|
429
|
+
|
|
430
|
+
FString PropertyError;
|
|
431
|
+
if (bHasChannelWeight && !MCPSetChannelProperty(Channel, TEXT("Weight"), MakeShared<FJsonValueNumber>(ChannelWeight), PropertyError))
|
|
432
|
+
{
|
|
433
|
+
return MCPError(FString::Printf(TEXT("Could not set channel weight: %s"), *PropertyError));
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
TArray<TSharedPtr<FJsonValue>> SampleStructs;
|
|
437
|
+
for (const FParsedSample& Parsed : ParsedSamples)
|
|
438
|
+
{
|
|
439
|
+
TSharedPtr<FJsonObject> Sample = MakeShared<FJsonObject>();
|
|
440
|
+
Sample->SetNumberField(TEXT("Offset"), Parsed.Offset);
|
|
441
|
+
Sample->SetNumberField(TEXT("Flags"), Parsed.Flags);
|
|
442
|
+
Sample->SetNumberField(TEXT("Weight"), Parsed.Weight);
|
|
443
|
+
SampleStructs.Add(MakeShared<FJsonValueObject>(Sample));
|
|
444
|
+
}
|
|
445
|
+
if (!MCPSetChannelProperty(Channel, TEXT("Samples"), MakeShared<FJsonValueArray>(SampleStructs), PropertyError))
|
|
446
|
+
{
|
|
447
|
+
return MCPError(FString::Printf(TEXT("Could not set Samples: %s"), *PropertyError));
|
|
448
|
+
}
|
|
449
|
+
#endif
|
|
317
450
|
|
|
318
451
|
Schema->AddChannel(Channel);
|
|
319
452
|
MCPPoseSearch::Finalize(Schema);
|
|
@@ -344,7 +477,7 @@ TSharedPtr<FJsonValue> FAnimationHandlers::ReadPoseSearchSchema(const TSharedPtr
|
|
|
344
477
|
Res->SetNumberField(TEXT("sampleRate"), Schema->SampleRate);
|
|
345
478
|
|
|
346
479
|
TArray<TSharedPtr<FJsonValue>> Skeletons;
|
|
347
|
-
for (const FPoseSearchRoledSkeleton& Roled : Schema
|
|
480
|
+
for (const FPoseSearchRoledSkeleton& Roled : MCPPoseSearch::RoledSkeletons(Schema))
|
|
348
481
|
{
|
|
349
482
|
TSharedPtr<FJsonObject> S = MakeShared<FJsonObject>();
|
|
350
483
|
S->SetStringField(TEXT("role"), Roled.Role.ToString());
|
|
@@ -526,7 +659,10 @@ TSharedPtr<FJsonValue> FAnimationHandlers::SetPoseSearchDatabaseSettings(const T
|
|
|
526
659
|
FString PrevPoseSearchModeName = TEXT("BruteForce");
|
|
527
660
|
if (PrevPoseSearchMode == EPoseSearchMode::PCAKDTree) PrevPoseSearchModeName = TEXT("PCAKDTree");
|
|
528
661
|
else if (PrevPoseSearchMode == EPoseSearchMode::VPTree) PrevPoseSearchModeName = TEXT("VPTree");
|
|
662
|
+
#if UE_MCP_HAS_5_5_API
|
|
663
|
+
// EPoseSearchMode::EventOnly is a later addition to the enum.
|
|
529
664
|
else if (PrevPoseSearchMode == EPoseSearchMode::EventOnly) PrevPoseSearchModeName = TEXT("EventOnly");
|
|
665
|
+
#endif
|
|
530
666
|
#if WITH_EDITORONLY_DATA
|
|
531
667
|
const int32 PrevNumberOfPrincipalComponents = Database->NumberOfPrincipalComponents;
|
|
532
668
|
const FString PrevNormalizationSetPath =
|
|
@@ -547,7 +683,9 @@ TSharedPtr<FJsonValue> FAnimationHandlers::SetPoseSearchDatabaseSettings(const T
|
|
|
547
683
|
if (Mode.Equals(TEXT("bruteforce"), ESearchCase::IgnoreCase)) Database->PoseSearchMode = EPoseSearchMode::BruteForce;
|
|
548
684
|
else if (Mode.Equals(TEXT("pcakdtree"), ESearchCase::IgnoreCase)) Database->PoseSearchMode = EPoseSearchMode::PCAKDTree;
|
|
549
685
|
else if (Mode.Equals(TEXT("vptree"), ESearchCase::IgnoreCase)) Database->PoseSearchMode = EPoseSearchMode::VPTree;
|
|
686
|
+
#if UE_MCP_HAS_5_5_API
|
|
550
687
|
else if (Mode.Equals(TEXT("eventonly"), ESearchCase::IgnoreCase)) Database->PoseSearchMode = EPoseSearchMode::EventOnly;
|
|
688
|
+
#endif
|
|
551
689
|
}
|
|
552
690
|
|
|
553
691
|
#if WITH_EDITORONLY_DATA
|
package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_Sequence.cpp
CHANGED
|
@@ -1187,8 +1187,40 @@ TSharedPtr<FJsonValue> FAnimationHandlers::ApplyAnimationModifier(const TSharedP
|
|
|
1187
1187
|
bool bRegistered = false;
|
|
1188
1188
|
if (!Instance)
|
|
1189
1189
|
{
|
|
1190
|
+
#if UE_MCP_HAS_5_5_API
|
|
1190
1191
|
UAnimationModifiersAssetUserData::AddAnimationModifierOfClass(Seq, ModClass);
|
|
1191
1192
|
bRegistered = true;
|
|
1193
|
+
#else
|
|
1194
|
+
// 5.4 has no static AddAnimationModifierOfClass, and its member
|
|
1195
|
+
// AddAnimationModifier is protected. That member does exactly one
|
|
1196
|
+
// thing - append to the reflected AnimationModifierInstances array -
|
|
1197
|
+
// so the registration is done through the property system here, and
|
|
1198
|
+
// the sequence keeps the same modifier list the editor tab shows.
|
|
1199
|
+
bRegistered = false;
|
|
1200
|
+
{
|
|
1201
|
+
UAnimationModifiersAssetUserData* Data = Seq->GetAssetUserData<UAnimationModifiersAssetUserData>();
|
|
1202
|
+
if (!Data)
|
|
1203
|
+
{
|
|
1204
|
+
Data = NewObject<UAnimationModifiersAssetUserData>(
|
|
1205
|
+
Seq, UAnimationModifiersAssetUserData::StaticClass(), NAME_None, RF_Transactional);
|
|
1206
|
+
Seq->AddAssetUserData(Data);
|
|
1207
|
+
}
|
|
1208
|
+
FArrayProperty* InstancesProp = FindFProperty<FArrayProperty>(
|
|
1209
|
+
UAnimationModifiersAssetUserData::StaticClass(), TEXT("AnimationModifierInstances"));
|
|
1210
|
+
FObjectProperty* InstanceEntryProp = InstancesProp
|
|
1211
|
+
? CastField<FObjectProperty>(InstancesProp->Inner) : nullptr;
|
|
1212
|
+
if (Data && InstanceEntryProp)
|
|
1213
|
+
{
|
|
1214
|
+
UAnimationModifier* NewModifier = NewObject<UAnimationModifier>(
|
|
1215
|
+
Data, ModClass, NAME_None, RF_Transactional);
|
|
1216
|
+
Data->Modify();
|
|
1217
|
+
FScriptArrayHelper ArrayHelper(InstancesProp, InstancesProp->ContainerPtrToValuePtr<void>(Data));
|
|
1218
|
+
const int32 NewIndex = ArrayHelper.AddValue();
|
|
1219
|
+
InstanceEntryProp->SetObjectPropertyValue(ArrayHelper.GetRawPtr(NewIndex), NewModifier);
|
|
1220
|
+
bRegistered = true;
|
|
1221
|
+
}
|
|
1222
|
+
}
|
|
1223
|
+
#endif
|
|
1192
1224
|
UserData = Seq->GetAssetUserData<UAnimationModifiersAssetUserData>();
|
|
1193
1225
|
if (UserData)
|
|
1194
1226
|
{
|
|
@@ -507,6 +507,18 @@ TSharedPtr<FJsonValue> FAnimationHandlers::PreviewAnimation(const TSharedPtr<FJs
|
|
|
507
507
|
// or template and disappears when that component is reconstructed.
|
|
508
508
|
TSharedPtr<FJsonValue> FAnimationHandlers::SetLivePostProcessAnimBlueprint(const TSharedPtr<FJsonObject>& Params)
|
|
509
509
|
{
|
|
510
|
+
#if !UE_MCP_HAS_5_5_API
|
|
511
|
+
// USkeletalMeshComponent::OverridePostProcessAnimBP, its setter, and
|
|
512
|
+
// GetPostProcessAnimBPClassToBeUsed all arrived in 5.5. On 5.4 the
|
|
513
|
+
// post-process AnimBP belongs to the SkeletalMesh asset and a component
|
|
514
|
+
// carries no override to set or clear, so there is no live override to
|
|
515
|
+
// report on either.
|
|
516
|
+
auto Result = MakeShared<FJsonObject>();
|
|
517
|
+
Result->SetBoolField(TEXT("success"), false);
|
|
518
|
+
Result->SetStringField(TEXT("errorCode"), TEXT("unsupported_engine_version"));
|
|
519
|
+
Result->SetStringField(TEXT("error"), TEXT("set_live_post_process_anim_blueprint requires Unreal Engine 5.5 or newer, because the per-component post-process AnimBP override does not exist in 5.4. Set the post-process AnimBP on the SkeletalMesh asset instead."));
|
|
520
|
+
return MCPResult(Result);
|
|
521
|
+
#else
|
|
510
522
|
FString ActorLabel;
|
|
511
523
|
if (auto Err = RequireStringAlt(Params, TEXT("actorLabel"), TEXT("actorPath"), ActorLabel)) return Err;
|
|
512
524
|
const FString ComponentName = OptionalString(Params, TEXT("componentName"));
|
|
@@ -612,6 +624,7 @@ TSharedPtr<FJsonValue> FAnimationHandlers::SetLivePostProcessAnimBlueprint(const
|
|
|
612
624
|
}
|
|
613
625
|
MCPSetRollback(Result, TEXT("set_live_post_process_anim_blueprint"), Rollback);
|
|
614
626
|
return MCPResult(Result);
|
|
627
|
+
#endif
|
|
615
628
|
}
|
|
616
629
|
|
|
617
630
|
|
package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_Skeleton.cpp
CHANGED
|
@@ -823,6 +823,62 @@ static TArray<FString> SkeletonBoneNames(const USkeleton* Skeleton)
|
|
|
823
823
|
return Out;
|
|
824
824
|
}
|
|
825
825
|
|
|
826
|
+
// ── Curve metadata flags ─────────────────────────────────────────────────────
|
|
827
|
+
//
|
|
828
|
+
// 5.5 added the named accessors (GetCurveMetaDataMaterial and friends). On 5.4
|
|
829
|
+
// the same two bits live in FCurveMetaData::Type, reached through the mutable
|
|
830
|
+
// GetCurveMetaData, so the flags read and write the same asset data either way.
|
|
831
|
+
|
|
832
|
+
static bool MCPGetCurveFlagMaterial(const USkeleton* Skeleton, FName CurveName)
|
|
833
|
+
{
|
|
834
|
+
if (!Skeleton) return false;
|
|
835
|
+
#if UE_MCP_HAS_5_5_API
|
|
836
|
+
return Skeleton->GetCurveMetaDataMaterial(CurveName);
|
|
837
|
+
#else
|
|
838
|
+
const FCurveMetaData* MetaData = Skeleton->GetCurveMetaData(CurveName);
|
|
839
|
+
return MetaData ? MetaData->Type.bMaterial : false;
|
|
840
|
+
#endif
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
static bool MCPGetCurveFlagMorphTarget(const USkeleton* Skeleton, FName CurveName)
|
|
844
|
+
{
|
|
845
|
+
if (!Skeleton) return false;
|
|
846
|
+
#if UE_MCP_HAS_5_5_API
|
|
847
|
+
return Skeleton->GetCurveMetaDataMorphTarget(CurveName);
|
|
848
|
+
#else
|
|
849
|
+
const FCurveMetaData* MetaData = Skeleton->GetCurveMetaData(CurveName);
|
|
850
|
+
return MetaData ? MetaData->Type.bMorphtarget : false;
|
|
851
|
+
#endif
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
static void MCPSetCurveFlagMaterial(USkeleton* Skeleton, FName CurveName, bool bValue)
|
|
855
|
+
{
|
|
856
|
+
if (!Skeleton) return;
|
|
857
|
+
#if UE_MCP_HAS_5_5_API
|
|
858
|
+
Skeleton->SetCurveMetaDataMaterial(CurveName, bValue);
|
|
859
|
+
#else
|
|
860
|
+
if (FCurveMetaData* MetaData = Skeleton->GetCurveMetaData(CurveName))
|
|
861
|
+
{
|
|
862
|
+
Skeleton->Modify();
|
|
863
|
+
MetaData->Type.bMaterial = bValue;
|
|
864
|
+
}
|
|
865
|
+
#endif
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
static void MCPSetCurveFlagMorphTarget(USkeleton* Skeleton, FName CurveName, bool bValue)
|
|
869
|
+
{
|
|
870
|
+
if (!Skeleton) return;
|
|
871
|
+
#if UE_MCP_HAS_5_5_API
|
|
872
|
+
Skeleton->SetCurveMetaDataMorphTarget(CurveName, bValue);
|
|
873
|
+
#else
|
|
874
|
+
if (FCurveMetaData* MetaData = Skeleton->GetCurveMetaData(CurveName))
|
|
875
|
+
{
|
|
876
|
+
Skeleton->Modify();
|
|
877
|
+
MetaData->Type.bMorphtarget = bValue;
|
|
878
|
+
}
|
|
879
|
+
#endif
|
|
880
|
+
}
|
|
881
|
+
|
|
826
882
|
} // namespace UE_MCP_SkeletonEdit
|
|
827
883
|
|
|
828
884
|
// ═════════════════════════════════════════════════════════════════════════════
|
|
@@ -2572,7 +2628,12 @@ TSharedPtr<FJsonValue> FAnimationHandlers::EditCurveMetadata(const TSharedPtr<FJ
|
|
|
2572
2628
|
Row->SetStringField(TEXT("curve"), Curve);
|
|
2573
2629
|
// Returns false when an entry already existed, which is the
|
|
2574
2630
|
// idempotent case rather than a failure.
|
|
2575
|
-
|
|
2631
|
+
#if UE_MCP_HAS_5_5_API
|
|
2632
|
+
const bool bNew = Skeleton->AddCurveMetaData(FName(*Curve), /*bTransact*/ false);
|
|
2633
|
+
#else
|
|
2634
|
+
// 5.4 has no bTransact parameter; the call transacts either way.
|
|
2635
|
+
const bool bNew = Skeleton->AddCurveMetaData(FName(*Curve));
|
|
2636
|
+
#endif
|
|
2576
2637
|
Row->SetBoolField(TEXT("created"), bNew);
|
|
2577
2638
|
Row->SetBoolField(TEXT("existed"), !bNew);
|
|
2578
2639
|
bNew ? ++Added : ++AlreadyPresent;
|
|
@@ -2587,23 +2648,23 @@ TSharedPtr<FJsonValue> FAnimationHandlers::EditCurveMetadata(const TSharedPtr<FJ
|
|
|
2587
2648
|
bool bChanged = false;
|
|
2588
2649
|
if (Flag.bMaterial.IsSet())
|
|
2589
2650
|
{
|
|
2590
|
-
const bool Prior = Skeleton
|
|
2651
|
+
const bool Prior = MCPGetCurveFlagMaterial(Skeleton, FName(*Flag.Curve));
|
|
2591
2652
|
Row->SetBoolField(TEXT("priorMaterial"), Prior);
|
|
2592
2653
|
Row->SetBoolField(TEXT("material"), Flag.bMaterial.GetValue());
|
|
2593
2654
|
if (Prior != Flag.bMaterial.GetValue())
|
|
2594
2655
|
{
|
|
2595
|
-
Skeleton
|
|
2656
|
+
MCPSetCurveFlagMaterial(Skeleton, FName(*Flag.Curve), Flag.bMaterial.GetValue());
|
|
2596
2657
|
bChanged = true;
|
|
2597
2658
|
}
|
|
2598
2659
|
}
|
|
2599
2660
|
if (Flag.bMorphTarget.IsSet())
|
|
2600
2661
|
{
|
|
2601
|
-
const bool Prior = Skeleton
|
|
2662
|
+
const bool Prior = MCPGetCurveFlagMorphTarget(Skeleton, FName(*Flag.Curve));
|
|
2602
2663
|
Row->SetBoolField(TEXT("priorMorphTarget"), Prior);
|
|
2603
2664
|
Row->SetBoolField(TEXT("morphTarget"), Flag.bMorphTarget.GetValue());
|
|
2604
2665
|
if (Prior != Flag.bMorphTarget.GetValue())
|
|
2605
2666
|
{
|
|
2606
|
-
Skeleton
|
|
2667
|
+
MCPSetCurveFlagMorphTarget(Skeleton, FName(*Flag.Curve), Flag.bMorphTarget.GetValue());
|
|
2607
2668
|
bChanged = true;
|
|
2608
2669
|
}
|
|
2609
2670
|
}
|