ue-mcp 1.3.1-beta.1 → 1.3.1-beta.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/README.md +1 -1
- package/dist/action-class.js +46 -2
- package/dist/action-class.js.map +1 -1
- package/dist/tool-counts.json +2 -2
- package/package.json +1 -1
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_IKRetargeterAuthoring.cpp +41 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_IKRigAuthoring.cpp +45 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_Validation.cpp +28 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers.cpp +64 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Redirectors.cpp +11 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Sockets.cpp +55 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Subobject.cpp +12 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_UV.cpp +31 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AudioHandlers_Depth.cpp +17 -4
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AudioHandlers_MetaSound.cpp +5 -1
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AudioHandlers_MetaSoundRead.cpp +6 -1
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers.cpp +32 -1
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers_Graph.cpp +17 -6
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/ChooserHandlers_Nested.cpp +14 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/DialogHandlers.cpp +87 -5
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/EditorHandlers_Build.cpp +9 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/EditorHandlers_RuntimeVisibility.cpp +41 -2
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/EpicHandlers.cpp +22 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/FoliageHandlers.cpp +75 -7
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GameplayHandlers_BTAuthoring.cpp +12 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GameplayHandlers_Input.cpp +19 -4
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GameplayHandlers_Perception.cpp +17 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LandscapeHandlers_Sculpt.cpp +13 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers.cpp +5 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_BatchWrite.cpp +1 -1
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Convert.cpp +6 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_InstanceProjection.cpp +37 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Lights.cpp +64 -1
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_MultiLevel.cpp +13 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Query.cpp +1 -1
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Refresh.cpp +3 -3
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Save.cpp +9 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Transient.cpp +54 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/MaterialHandlers_Build.cpp +30 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/NiagaraHandlers_Compile.cpp +17 -2
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/SkeletalMeshHandlers.cpp +65 -3
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/WidgetHandlers.cpp +46 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Public/HandlerUtils.h +55 -0
- package/plugin/ue_mcp_bridge/UE_MCP_Bridge.uplugin +1 -1
package/README.md
CHANGED
|
@@ -177,7 +177,7 @@ Details: [Guards](https://ue-mcp.com/docs/plugins-guards/) and [Handler Conventi
|
|
|
177
177
|
|
|
178
178
|
| | |
|
|
179
179
|
|---|---|
|
|
180
|
-
| **Unreal Engine** | 5.4-5.8 (Windows), 5.6+ (Linux and macOS). `epic` category needs 5.8+. |
|
|
180
|
+
| **Unreal Engine** | 5.4-5.8 (Windows), 5.6+ (Linux and macOS). Compiled and verified on 5.7 and 5.8; 5.4 to 5.6 are version-gated in source but not built here. `epic` category needs 5.8+. |
|
|
181
181
|
| **Node.js** | 18 or newer |
|
|
182
182
|
| **UE plugins** | `PythonScriptPlugin` (ships with the engine); `init` enables the rest for you |
|
|
183
183
|
| **C++ toolchain** | Required - the bridge is a C++ plugin and compiles on first editor launch. On Windows that means Visual Studio with the C++ workload; on macOS, Xcode command line tools. |
|
package/dist/action-class.js
CHANGED
|
@@ -267,7 +267,13 @@ const OVERRIDES = {
|
|
|
267
267
|
// terrain, but a file appearing on disk is an external side effect and the
|
|
268
268
|
// taxonomy above counts that as a mutation.
|
|
269
269
|
"landscape.export_heightmap": "mutate",
|
|
270
|
-
|
|
270
|
+
// Not one of the exports above, despite sitting next to them here since it
|
|
271
|
+
// was written. It decodes a USoundWave's imported audio into memory and
|
|
272
|
+
// returns the samples base64-encoded in the response: no intermediate file,
|
|
273
|
+
// no path parameter to write one to, nothing dirtied and nothing saved. It
|
|
274
|
+
// was classified `mutate` by association with the file-writing exports, and
|
|
275
|
+
// the handler body settles it the other way.
|
|
276
|
+
"audio.extract_pcm": "read",
|
|
271
277
|
// Rebuilds the full-text index in the editor's own database.
|
|
272
278
|
"asset.reindex_fts": "mutate",
|
|
273
279
|
// Loads, rewrites and saves the packages that reference a set of
|
|
@@ -288,6 +294,31 @@ const OVERRIDES = {
|
|
|
288
294
|
// The verb says read; what it can do says mutate, and the gate follows what
|
|
289
295
|
// it can do.
|
|
290
296
|
"gas.get_live_attribute_value": "mutate",
|
|
297
|
+
// Runs an EQS query through FEnvQueryManager::RunInstantQuery against an
|
|
298
|
+
// already-spawned querier and serialises the scored items. `run` is a mutate
|
|
299
|
+
// verb and this one does not: no spawn, no Modify, no save, nothing written
|
|
300
|
+
// back to the query asset or the world. Landing it in the wrong editor
|
|
301
|
+
// returns the wrong scores and changes nothing.
|
|
302
|
+
"gameplay.run_eqs_query": "read",
|
|
303
|
+
// ── Reads whose name leads with a subsystem, not a verb ─────────────
|
|
304
|
+
// The lexicon only trusts a read verb in the leading segment, so these say
|
|
305
|
+
// out loud what they read. Each one was confirmed against its handler: they
|
|
306
|
+
// open an asset, walk a graph or a document, and write nothing back.
|
|
307
|
+
"audio.metasound_get_graph": "read",
|
|
308
|
+
"audio.metasound_read_document": "read",
|
|
309
|
+
"audio.metasound_list_node_classes": "read",
|
|
310
|
+
"audio.metasound_list_node_pins": "read",
|
|
311
|
+
"audio.metasound_list_connections": "read",
|
|
312
|
+
"audio.metasound_list_variables": "read",
|
|
313
|
+
"audio.metasound_search_nodes": "read",
|
|
314
|
+
"audio.metasound_inspect_node": "read",
|
|
315
|
+
// Runs the MetaSound builder's own validation over a document and reports
|
|
316
|
+
// the errors. It builds nothing and saves nothing.
|
|
317
|
+
"audio.metasound_validate": "read",
|
|
318
|
+
"audio.cue_get_graph": "read",
|
|
319
|
+
// Answers whether a named weightmap layer is present on a landscape. The
|
|
320
|
+
// `exists` question never creates the layer it asks about.
|
|
321
|
+
"landscape.layer_exists": "read",
|
|
291
322
|
// ── The workflow journal and the skill packs ────────────────────────
|
|
292
323
|
// Neither reaches a bridge, so nothing here can land in the wrong EDITOR.
|
|
293
324
|
// Both are still per project: the journal file is keyed by absolute project
|
|
@@ -333,7 +364,20 @@ export function classifyActionClass(tool, action) {
|
|
|
333
364
|
const segments = action.toLowerCase().split(/[._]/).filter(Boolean);
|
|
334
365
|
if (segments.some((s) => MUTATE_VERBS.has(s)))
|
|
335
366
|
return { class: "mutate", source: "lexicon" };
|
|
336
|
-
|
|
367
|
+
// A read verb only settles the question from the FRONT of the name. Anywhere
|
|
368
|
+
// else it is a noun as often as a verb, and the direction of that mistake is
|
|
369
|
+
// the dangerous one: `wire_rvt_sample` was a mutation that classified as a
|
|
370
|
+
// read on the strength of `sample`, and untargeted dispatch would have let it
|
|
371
|
+
// edit whichever editor happened to be active. It reached a human review
|
|
372
|
+
// rather than a release, and was renamed to `add_rvt_sampler`, which is a fix
|
|
373
|
+
// to one name and not to the rule that produced it.
|
|
374
|
+
//
|
|
375
|
+
// So a trailing read verb now decides nothing and falls through to
|
|
376
|
+
// `unresolved`, which is gated exactly like a mutation and which the drift
|
|
377
|
+
// guard fails on. The cost is an override line for every genuine read whose
|
|
378
|
+
// name leads with a subsystem instead of a verb; those are below, each saying
|
|
379
|
+
// what it reads. The alternative costs a silent wrong-editor write.
|
|
380
|
+
if (READ_VERBS.has(segments[0] ?? ""))
|
|
337
381
|
return { class: "read", source: "lexicon" };
|
|
338
382
|
// Epic's wrapped engine tools are injected at runtime from a live catalog, so
|
|
339
383
|
// no build-time guard can enumerate them: enrichment can invent whole
|
package/dist/action-class.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"action-class.js","sourceRoot":"","sources":["../src/action-class.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"action-class.js","sourceRoot":"","sources":["../src/action-class.ts"],"names":[],"mappings":"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"}
|
package/dist/tool-counts.json
CHANGED
package/package.json
CHANGED
|
@@ -655,6 +655,13 @@ TSharedPtr<FJsonValue> FAnimationHandlers::ConfigureIKRetargeter(const TSharedPt
|
|
|
655
655
|
PreparedPose = MoveTemp(Pose);
|
|
656
656
|
}
|
|
657
657
|
|
|
658
|
+
// Read before the transaction reassigns them. A rollback payload built after
|
|
659
|
+
// the write would carry the values this call just installed.
|
|
660
|
+
const UIKRigDefinition* PreviousSourceRig = Controller->GetIKRig(ERetargetSourceOrTarget::Source);
|
|
661
|
+
const UIKRigDefinition* PreviousTargetRig = Controller->GetIKRig(ERetargetSourceOrTarget::Target);
|
|
662
|
+
USkeletalMesh* PreviousSourcePreview = Controller->GetPreviewMesh(ERetargetSourceOrTarget::Source);
|
|
663
|
+
USkeletalMesh* PreviousTargetPreview = Controller->GetPreviewMesh(ERetargetSourceOrTarget::Target);
|
|
664
|
+
|
|
658
665
|
bool bMutationFailed = false;
|
|
659
666
|
FString MutationError;
|
|
660
667
|
bool bAddedDefaultOps = false;
|
|
@@ -948,6 +955,40 @@ TSharedPtr<FJsonValue> FAnimationHandlers::ConfigureIKRetargeter(const TSharedPt
|
|
|
948
955
|
Result->SetObjectField(TEXT("pose"), BuildPoseJson(Controller, Pose.Side, Pose.Name, Pose.bAutoAlignAll));
|
|
949
956
|
}
|
|
950
957
|
|
|
958
|
+
// Only the assignment half of this action is reversible: the rigs and preview
|
|
959
|
+
// meshes each had a previous asset that a replay of this same action can
|
|
960
|
+
// point back at. ensureDefaultOps is forced off in that replay so a pure
|
|
961
|
+
// assignment restore cannot install an op stack of its own.
|
|
962
|
+
const bool bAssignmentsOnly = !bAddedDefaultOps && !bHasAutoMap
|
|
963
|
+
&& PreparedMappings.IsEmpty() && !PreparedPose.IsSet();
|
|
964
|
+
const bool bAssignedAnything = bHasSourceRig || bHasTargetRig || bHasSourcePreview || bHasTargetPreview;
|
|
965
|
+
const bool bAssignmentsRestorable =
|
|
966
|
+
(!bHasSourceRig || PreviousSourceRig != nullptr)
|
|
967
|
+
&& (!bHasTargetRig || PreviousTargetRig != nullptr)
|
|
968
|
+
&& (!bHasSourcePreview || PreviousSourcePreview != nullptr)
|
|
969
|
+
&& (!bHasTargetPreview || PreviousTargetPreview != nullptr);
|
|
970
|
+
if (bAssignmentsOnly && bAssignedAnything && bAssignmentsRestorable)
|
|
971
|
+
{
|
|
972
|
+
auto Payload = MakeShared<FJsonObject>();
|
|
973
|
+
Payload->SetStringField(TEXT("retargeterPath"), Retargeter->GetPathName());
|
|
974
|
+
Payload->SetBoolField(TEXT("ensureDefaultOps"), false);
|
|
975
|
+
if (bHasSourceRig) Payload->SetStringField(TEXT("sourceRig"), PreviousSourceRig->GetPathName());
|
|
976
|
+
if (bHasTargetRig) Payload->SetStringField(TEXT("targetRig"), PreviousTargetRig->GetPathName());
|
|
977
|
+
if (bHasSourcePreview) Payload->SetStringField(TEXT("sourcePreviewMesh"), PreviousSourcePreview->GetPathName());
|
|
978
|
+
if (bHasTargetPreview) Payload->SetStringField(TEXT("targetPreviewMesh"), PreviousTargetPreview->GetPathName());
|
|
979
|
+
MCPSetRollback(Result, TEXT("configure_ik_retargeter"), Payload);
|
|
980
|
+
}
|
|
981
|
+
else
|
|
982
|
+
{
|
|
983
|
+
TArray<FString> Causes;
|
|
984
|
+
if (bAddedDefaultOps) Causes.Add(TEXT("a default retarget op stack was installed and no action removes a retarget op"));
|
|
985
|
+
if (bHasAutoMap || !PreparedMappings.IsEmpty()) Causes.Add(TEXT("chain mappings were rewritten over mappings this call did not capture"));
|
|
986
|
+
if (PreparedPose.IsSet()) Causes.Add(TEXT("a retarget pose was created, reset or realigned and no action deletes a pose"));
|
|
987
|
+
if (!bAssignmentsRestorable) Causes.Add(TEXT("a rig or preview mesh this call assigned had none before, and configure_ik_retargeter takes asset paths so it cannot clear one back to unset"));
|
|
988
|
+
if (Causes.IsEmpty()) Causes.Add(TEXT("this call assigned no rig or preview mesh, so there is no previous asset for a replay to point back at"));
|
|
989
|
+
MCPSetNoRollback(Result, FString::Join(Causes, TEXT("; ")) + TEXT("."));
|
|
990
|
+
}
|
|
991
|
+
|
|
951
992
|
auto Validation = MakeShared<FJsonObject>();
|
|
952
993
|
Validation->SetBoolField(TEXT("ran"), bValidationRan);
|
|
953
994
|
Validation->SetBoolField(TEXT("initialized"), bValidationInitialized);
|
|
@@ -620,6 +620,11 @@ TSharedPtr<FJsonValue> FAnimationHandlers::ConfigureIKRig(const TSharedPtr<FJson
|
|
|
620
620
|
const int32 BeforeGoalCount = Controller->GetAllGoals().Num();
|
|
621
621
|
const int32 BeforeSolverCount = Controller->GetNumSolvers();
|
|
622
622
|
const TSet<FName> BeforeExcluded(Skeleton.ExcludedBones);
|
|
623
|
+
// Read before the transaction writes over them, because the rollback payload
|
|
624
|
+
// below has to carry the bones this rig used to name, not the ones it names
|
|
625
|
+
// after this call succeeds.
|
|
626
|
+
const FName BeforeRetargetRoot = Controller->GetRetargetRoot();
|
|
627
|
+
const FName BeforeRootMotionBone = Controller->GetRootMotionBone();
|
|
623
628
|
UPackage* Package = Rig->GetOutermost();
|
|
624
629
|
const bool bWasDirty = Package && Package->IsDirty();
|
|
625
630
|
bool bFailed = false;
|
|
@@ -892,6 +897,46 @@ TSharedPtr<FJsonValue> FAnimationHandlers::ConfigureIKRig(const TSharedPtr<FJson
|
|
|
892
897
|
Result->SetNumberField(TEXT("fullBodyIKSolverIndex"), SolverIndex);
|
|
893
898
|
Result->SetBoolField(TEXT("fullBodyIKSolverCreated"), Controller->GetNumSolvers() > BeforeSolverCount);
|
|
894
899
|
}
|
|
900
|
+
// Only the settings half of this action is reversible. retargetRoot,
|
|
901
|
+
// rootMotionBone and bone exclusions each had a previous value that a replay
|
|
902
|
+
// of this same action can write back. The rest of what it does is creation,
|
|
903
|
+
// and creation is what no registered action can take back.
|
|
904
|
+
const bool bSettingsOnly = !bAutoRetarget && Chains.IsEmpty() && !FullBody.bPresent
|
|
905
|
+
&& (RetargetRoot.IsSet() || RootMotionBone.IsSet() || !Exclusions.IsEmpty());
|
|
906
|
+
const bool bBonesRestorable =
|
|
907
|
+
(!RetargetRoot.IsSet() || !BeforeRetargetRoot.IsNone())
|
|
908
|
+
&& (!RootMotionBone.IsSet() || !BeforeRootMotionBone.IsNone());
|
|
909
|
+
if (bSettingsOnly && bBonesRestorable)
|
|
910
|
+
{
|
|
911
|
+
TSharedPtr<FJsonObject> Payload = MakeShared<FJsonObject>();
|
|
912
|
+
Payload->SetStringField(TEXT("rigPath"), Rig->GetPathName());
|
|
913
|
+
if (RetargetRoot.IsSet()) Payload->SetStringField(TEXT("retargetRoot"), BeforeRetargetRoot.ToString());
|
|
914
|
+
if (RootMotionBone.IsSet()) Payload->SetStringField(TEXT("rootMotionBone"), BeforeRootMotionBone.ToString());
|
|
915
|
+
if (!Exclusions.IsEmpty())
|
|
916
|
+
{
|
|
917
|
+
TArray<TSharedPtr<FJsonValue>> PreviousExclusions;
|
|
918
|
+
for (const FExclusionRequest& Request : Exclusions)
|
|
919
|
+
{
|
|
920
|
+
TSharedPtr<FJsonObject> Entry = MakeShared<FJsonObject>();
|
|
921
|
+
Entry->SetStringField(TEXT("bone"), Request.Bone.ToString());
|
|
922
|
+
Entry->SetBoolField(TEXT("excluded"), BeforeExcluded.Contains(Request.Bone));
|
|
923
|
+
PreviousExclusions.Add(MakeShared<FJsonValueObject>(Entry));
|
|
924
|
+
}
|
|
925
|
+
Payload->SetArrayField(TEXT("exclusions"), PreviousExclusions);
|
|
926
|
+
}
|
|
927
|
+
MCPSetRollback(Result, TEXT("configure_ik_rig"), Payload);
|
|
928
|
+
}
|
|
929
|
+
else
|
|
930
|
+
{
|
|
931
|
+
TArray<FString> Causes;
|
|
932
|
+
if (bAutoRetarget) Causes.Add(TEXT("autoSetup replaced the rig's retarget definition and no action restores the previous one"));
|
|
933
|
+
if (!Chains.IsEmpty()) Causes.Add(TEXT("retarget chains were upserted and no action removes a chain"));
|
|
934
|
+
if (FullBody.bPresent) Causes.Add(TEXT("IK goals and a Full Body IK solver were upserted and no action removes a goal or a solver"));
|
|
935
|
+
if (!bBonesRestorable) Causes.Add(TEXT("retargetRoot or rootMotionBone had no previous bone, and configure_ik_rig takes a bone name so it cannot clear one back to none"));
|
|
936
|
+
if (Causes.IsEmpty()) Causes.Add(TEXT("this call changed nothing whose previous value a replay could write back"));
|
|
937
|
+
MCPSetNoRollback(Result, FString::Join(Causes, TEXT("; ")) + TEXT("."));
|
|
938
|
+
}
|
|
939
|
+
|
|
895
940
|
TArray<TSharedPtr<FJsonValue>> WarningValues;
|
|
896
941
|
for (const FString& Warning : Warnings) WarningValues.Add(MakeShared<FJsonValueString>(Warning));
|
|
897
942
|
Result->SetArrayField(TEXT("warnings"), WarningValues);
|
package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_Validation.cpp
CHANGED
|
@@ -730,6 +730,34 @@ TSharedPtr<FJsonValue> FAnimationHandlers::AnalyzeAnimation(const TSharedPtr<FJs
|
|
|
730
730
|
Result->SetStringField(TEXT("outputDirectory"), OutputDirectory);
|
|
731
731
|
Result->SetStringField(TEXT("manifestPath"), ManifestPath);
|
|
732
732
|
Result->SetStringField(TEXT("samplesPath"), SamplesPath);
|
|
733
|
+
|
|
734
|
+
// The only effect this call has outside the response, and it happens
|
|
735
|
+
// only when the caller named a directory. The sequence, its skeleton
|
|
736
|
+
// and the preview mesh are read and never written: the pose evaluation
|
|
737
|
+
// runs against a stack-local FCompactPose.
|
|
738
|
+
//
|
|
739
|
+
// No inverse is named because deleting a report this same call
|
|
740
|
+
// regenerates on demand is not a meaningful undo, and the bridge has no
|
|
741
|
+
// delete-file action to name anyway. The files are safe to leave: the
|
|
742
|
+
// handler refuses to run when either already exists, so a replay cannot
|
|
743
|
+
// overwrite a report somebody is reading.
|
|
744
|
+
MCPSetNoRollback(Result, FString::Printf(TEXT(
|
|
745
|
+
"Wrote the analysis report '%s' and its samples file '%s', and changed no animation, skeleton or "
|
|
746
|
+
"asset state. An analysis report is an output artifact rather than project state, and this call "
|
|
747
|
+
"regenerates it on demand, so no inverse is named. Nothing in the bridge deletes a file outside "
|
|
748
|
+
"the content browser."), *ManifestPath, *SamplesPath));
|
|
749
|
+
MCPSetCreated(Result);
|
|
750
|
+
}
|
|
751
|
+
else
|
|
752
|
+
{
|
|
753
|
+
// The whole call is a read on this path: it opens the sequence, samples
|
|
754
|
+
// poses into a local buffer and reports. Said out loud because a caller
|
|
755
|
+
// reading a body with neither a rollback nor a note cannot tell that
|
|
756
|
+
// from a handler that forgot one.
|
|
757
|
+
MCPSetNoRollback(Result, TEXT(
|
|
758
|
+
"Read the sequence and reported on it. No file was written and no asset, skeleton or world state "
|
|
759
|
+
"changed, so there is nothing to undo."));
|
|
760
|
+
Result->SetBoolField(TEXT("unchanged"), true);
|
|
733
761
|
}
|
|
734
762
|
return MCPResult(Result);
|
|
735
763
|
}
|
|
@@ -2566,6 +2566,15 @@ TSharedPtr<FJsonValue> FAssetHandlers::SaveAsset(const TSharedPtr<FJsonObject>&
|
|
|
2566
2566
|
Result->SetStringField(TEXT("path"), AssetPath);
|
|
2567
2567
|
Result->SetBoolField(TEXT("force"), bForce);
|
|
2568
2568
|
|
|
2569
|
+
// The dirty flag is the only honest answer to "did this call change
|
|
2570
|
+
// anything", and it has to be read before the save, because afterwards
|
|
2571
|
+
// every package is clean and a save that wrote nothing is
|
|
2572
|
+
// indistinguishable from one that flushed an edit.
|
|
2573
|
+
UObject* PreSaveAsset = MCPLoadAssetObject(AssetPath);
|
|
2574
|
+
UPackage* PreSavePackage = PreSaveAsset ? PreSaveAsset->GetOutermost() : nullptr;
|
|
2575
|
+
const bool bWasDirty = PreSavePackage && PreSavePackage->IsDirty();
|
|
2576
|
+
Result->SetBoolField(TEXT("wasDirty"), bWasDirty);
|
|
2577
|
+
|
|
2569
2578
|
bool bSuccess = false;
|
|
2570
2579
|
if (bForce)
|
|
2571
2580
|
{
|
|
@@ -2598,6 +2607,35 @@ TSharedPtr<FJsonValue> FAssetHandlers::SaveAsset(const TSharedPtr<FJsonObject>&
|
|
|
2598
2607
|
}
|
|
2599
2608
|
}
|
|
2600
2609
|
Result->SetBoolField(TEXT("success"), bSuccess);
|
|
2610
|
+
|
|
2611
|
+
// A clean package had nothing to flush. Without force the save was a
|
|
2612
|
+
// no-op and says so; with force the file was rewritten anyway, which is
|
|
2613
|
+
// a write to disk even though no edit was pending, so it does not claim
|
|
2614
|
+
// to have changed nothing.
|
|
2615
|
+
if (bWasDirty)
|
|
2616
|
+
{
|
|
2617
|
+
MCPSetUpdated(Result);
|
|
2618
|
+
}
|
|
2619
|
+
else if (bForce && bSuccess)
|
|
2620
|
+
{
|
|
2621
|
+
MCPSetUpdated(Result);
|
|
2622
|
+
Result->SetStringField(TEXT("note"),
|
|
2623
|
+
TEXT("The package was not dirty. force=true rewrote the file on disk anyway; without it this call would have written nothing."));
|
|
2624
|
+
}
|
|
2625
|
+
else
|
|
2626
|
+
{
|
|
2627
|
+
Result->SetBoolField(TEXT("updated"), false);
|
|
2628
|
+
Result->SetBoolField(TEXT("unchanged"), true);
|
|
2629
|
+
if (bSuccess)
|
|
2630
|
+
{
|
|
2631
|
+
// Only when the save itself reported success. A failed save
|
|
2632
|
+
// wrote nothing either, and telling that caller the package was
|
|
2633
|
+
// simply clean would hide the failure behind a no-op.
|
|
2634
|
+
Result->SetStringField(TEXT("note"),
|
|
2635
|
+
TEXT("The package was not dirty, so nothing was written. Pass force=true to write it regardless."));
|
|
2636
|
+
}
|
|
2637
|
+
}
|
|
2638
|
+
|
|
2601
2639
|
Result->SetBoolField(TEXT("rollbackPossible"), false);
|
|
2602
2640
|
Result->SetStringField(TEXT("rollbackNote"),
|
|
2603
2641
|
TEXT("A save overwrites the file on disk with what is in memory. The previous file contents are gone and the ")
|
|
@@ -2613,10 +2651,36 @@ TSharedPtr<FJsonValue> FAssetHandlers::SaveAsset(const TSharedPtr<FJsonObject>&
|
|
|
2613
2651
|
{
|
|
2614
2652
|
return MCPError(TEXT("'force' requires an assetPath - it forces one package to disk. To flush everything, use asset(save_all_dirty), which reports exactly which packages were written."));
|
|
2615
2653
|
}
|
|
2654
|
+
// Counted before the sweep for the same reason as the single-asset
|
|
2655
|
+
// branch: SaveDirectory is dirty-only, so with nothing dirty it writes
|
|
2656
|
+
// nothing, and afterwards there is no way to tell that from a sweep
|
|
2657
|
+
// that flushed a hundred packages.
|
|
2658
|
+
TArray<UPackage*> DirtyBefore;
|
|
2659
|
+
FEditorFileUtils::GetDirtyContentPackages(DirtyBefore);
|
|
2660
|
+
FEditorFileUtils::GetDirtyWorldPackages(DirtyBefore);
|
|
2661
|
+
int32 DirtyUnderGame = 0;
|
|
2662
|
+
for (UPackage* Package : DirtyBefore)
|
|
2663
|
+
{
|
|
2664
|
+
if (Package && Package->IsDirty() && Package->GetName().StartsWith(TEXT("/Game/")))
|
|
2665
|
+
{
|
|
2666
|
+
++DirtyUnderGame;
|
|
2667
|
+
}
|
|
2668
|
+
}
|
|
2669
|
+
|
|
2616
2670
|
UEditorAssetLibrary::SaveDirectory(TEXT("/Game"));
|
|
2617
2671
|
auto Result = MCPSuccess();
|
|
2618
2672
|
Result->SetBoolField(TEXT("success"), true);
|
|
2619
2673
|
Result->SetStringField(TEXT("message"), TEXT("All modified assets under /Game saved (dirty only). Use save_all_dirty for a per-package report."));
|
|
2674
|
+
Result->SetNumberField(TEXT("dirtyPackagesBefore"), DirtyUnderGame);
|
|
2675
|
+
if (DirtyUnderGame > 0)
|
|
2676
|
+
{
|
|
2677
|
+
MCPSetUpdated(Result);
|
|
2678
|
+
}
|
|
2679
|
+
else
|
|
2680
|
+
{
|
|
2681
|
+
Result->SetBoolField(TEXT("updated"), false);
|
|
2682
|
+
Result->SetBoolField(TEXT("unchanged"), true);
|
|
2683
|
+
}
|
|
2620
2684
|
Result->SetBoolField(TEXT("rollbackPossible"), false);
|
|
2621
2685
|
Result->SetStringField(TEXT("rollbackNote"),
|
|
2622
2686
|
TEXT("A save overwrites the files on disk with what is in memory. The previous file contents are gone and the ")
|
package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Redirectors.cpp
CHANGED
|
@@ -474,5 +474,16 @@ TSharedPtr<FJsonValue> FAssetHandlers::FixupRedirectors(const TSharedPtr<FJsonOb
|
|
|
474
474
|
Result->SetNumberField(TEXT("deletedRedirectorCount"), ConfirmedDeleted);
|
|
475
475
|
Result->SetArrayField(TEXT("redirectors"), RedirectorStatuses);
|
|
476
476
|
MCPSetUpdated(Result);
|
|
477
|
+
// Two irreversible writes, neither of which the bridge can undo. The
|
|
478
|
+
// referencer packages were saved over their previous bytes, and no copy of
|
|
479
|
+
// those was kept; the redirector packages were deleted from disk once
|
|
480
|
+
// nothing pointed at them. Restoring the old state needs a call that
|
|
481
|
+
// recreates an ObjectRedirector at a vacated path and a call that rewinds a
|
|
482
|
+
// package to its pre-save contents, and neither exists.
|
|
483
|
+
MCPSetNoRollback(Result, FString::Printf(
|
|
484
|
+
TEXT("Rewrote and saved %d referencer package(s) over their previous contents and deleted %d redirector ")
|
|
485
|
+
TEXT("package(s). Undoing this needs an action that recreates an ObjectRedirector at an old path and one that ")
|
|
486
|
+
TEXT("restores a package's pre-save bytes; neither exists, and no copy of the overwritten packages was kept."),
|
|
487
|
+
SavedCount, ConfirmedDeleted));
|
|
477
488
|
return MCPResult(Result);
|
|
478
489
|
}
|
package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Sockets.cpp
CHANGED
|
@@ -318,6 +318,13 @@ TSharedPtr<FJsonValue> FAssetHandlers::RemoveSocket(const TSharedPtr<FJsonObject
|
|
|
318
318
|
{
|
|
319
319
|
if (SM->Sockets[i] && SM->Sockets[i]->SocketName == FName(*SocketName))
|
|
320
320
|
{
|
|
321
|
+
// Read before the removal. After RemoveAt the array no longer
|
|
322
|
+
// holds the socket, and a transform captured then would put
|
|
323
|
+
// back a socket at the origin rather than where this one was.
|
|
324
|
+
const FVector PrevLoc = SM->Sockets[i]->RelativeLocation;
|
|
325
|
+
const FRotator PrevRot = SM->Sockets[i]->RelativeRotation;
|
|
326
|
+
const FVector PrevScale = SM->Sockets[i]->RelativeScale;
|
|
327
|
+
|
|
321
328
|
SM->Modify();
|
|
322
329
|
SM->Sockets.RemoveAt(i);
|
|
323
330
|
SM->MarkPackageDirty();
|
|
@@ -327,6 +334,18 @@ TSharedPtr<FJsonValue> FAssetHandlers::RemoveSocket(const TSharedPtr<FJsonObject
|
|
|
327
334
|
Result->SetStringField(TEXT("meshType"), TEXT("StaticMesh"));
|
|
328
335
|
Result->SetStringField(TEXT("source"), TEXT("mesh"));
|
|
329
336
|
Result->SetBoolField(TEXT("deleted"), true);
|
|
337
|
+
|
|
338
|
+
// add_socket recreates it with the transform it had.
|
|
339
|
+
// onConflict=update so the restore lands whether or not a
|
|
340
|
+
// socket of that name exists again by the time it runs.
|
|
341
|
+
TSharedPtr<FJsonObject> Payload = MakeShared<FJsonObject>();
|
|
342
|
+
Payload->SetStringField(TEXT("assetPath"), AssetPath);
|
|
343
|
+
Payload->SetStringField(TEXT("socketName"), SocketName);
|
|
344
|
+
Payload->SetObjectField(TEXT("relativeLocation"), MCPVec3ToJsonObject(PrevLoc));
|
|
345
|
+
Payload->SetObjectField(TEXT("relativeRotation"), MCPRotatorToJsonObject(PrevRot));
|
|
346
|
+
Payload->SetObjectField(TEXT("relativeScale"), MCPVec3ToJsonObject(PrevScale));
|
|
347
|
+
Payload->SetStringField(TEXT("onConflict"), TEXT("update"));
|
|
348
|
+
MCPSetRollback(Result, TEXT("add_socket"), Payload);
|
|
330
349
|
return MCPResult(Result);
|
|
331
350
|
}
|
|
332
351
|
}
|
|
@@ -346,6 +365,14 @@ TSharedPtr<FJsonValue> FAssetHandlers::RemoveSocket(const TSharedPtr<FJsonObject
|
|
|
346
365
|
{
|
|
347
366
|
if (Sockets[i] && Sockets[i]->SocketName == FName(*SocketName))
|
|
348
367
|
{
|
|
368
|
+
// Captured before the removal, and the bone with it: a socket
|
|
369
|
+
// restored onto the wrong bone is attached to the wrong part of
|
|
370
|
+
// the skeleton however right its transform is.
|
|
371
|
+
const FVector PrevLoc = Sockets[i]->RelativeLocation;
|
|
372
|
+
const FRotator PrevRot = Sockets[i]->RelativeRotation;
|
|
373
|
+
const FVector PrevScale = Sockets[i]->RelativeScale;
|
|
374
|
+
const FString PrevBone = Sockets[i]->BoneName.ToString();
|
|
375
|
+
|
|
349
376
|
SKM->Modify();
|
|
350
377
|
Sockets[i]->Modify();
|
|
351
378
|
Sockets.RemoveAt(i);
|
|
@@ -357,6 +384,16 @@ TSharedPtr<FJsonValue> FAssetHandlers::RemoveSocket(const TSharedPtr<FJsonObject
|
|
|
357
384
|
Result->SetStringField(TEXT("meshType"), TEXT("SkeletalMesh"));
|
|
358
385
|
Result->SetStringField(TEXT("source"), TEXT("mesh"));
|
|
359
386
|
Result->SetBoolField(TEXT("deleted"), true);
|
|
387
|
+
|
|
388
|
+
TSharedPtr<FJsonObject> Payload = MakeShared<FJsonObject>();
|
|
389
|
+
Payload->SetStringField(TEXT("assetPath"), AssetPath);
|
|
390
|
+
Payload->SetStringField(TEXT("socketName"), SocketName);
|
|
391
|
+
Payload->SetStringField(TEXT("boneName"), PrevBone);
|
|
392
|
+
Payload->SetObjectField(TEXT("relativeLocation"), MCPVec3ToJsonObject(PrevLoc));
|
|
393
|
+
Payload->SetObjectField(TEXT("relativeRotation"), MCPRotatorToJsonObject(PrevRot));
|
|
394
|
+
Payload->SetObjectField(TEXT("relativeScale"), MCPVec3ToJsonObject(PrevScale));
|
|
395
|
+
Payload->SetStringField(TEXT("onConflict"), TEXT("update"));
|
|
396
|
+
MCPSetRollback(Result, TEXT("add_socket"), Payload);
|
|
360
397
|
return MCPResult(Result);
|
|
361
398
|
}
|
|
362
399
|
}
|
|
@@ -375,6 +412,11 @@ TSharedPtr<FJsonValue> FAssetHandlers::RemoveSocket(const TSharedPtr<FJsonObject
|
|
|
375
412
|
{
|
|
376
413
|
if (Skel->Sockets[i] && Skel->Sockets[i]->SocketName == FName(*SocketName))
|
|
377
414
|
{
|
|
415
|
+
const FVector PrevLoc = Skel->Sockets[i]->RelativeLocation;
|
|
416
|
+
const FRotator PrevRot = Skel->Sockets[i]->RelativeRotation;
|
|
417
|
+
const FVector PrevScale = Skel->Sockets[i]->RelativeScale;
|
|
418
|
+
const FString PrevBone = Skel->Sockets[i]->BoneName.ToString();
|
|
419
|
+
|
|
378
420
|
Skel->Modify();
|
|
379
421
|
Skel->Sockets[i]->Modify();
|
|
380
422
|
Skel->Sockets.RemoveAt(i);
|
|
@@ -385,6 +427,19 @@ TSharedPtr<FJsonValue> FAssetHandlers::RemoveSocket(const TSharedPtr<FJsonObject
|
|
|
385
427
|
Result->SetStringField(TEXT("meshType"), TEXT("Skeleton"));
|
|
386
428
|
Result->SetStringField(TEXT("source"), TEXT("skeleton"));
|
|
387
429
|
Result->SetBoolField(TEXT("deleted"), true);
|
|
430
|
+
|
|
431
|
+
// The same assetPath routes add_socket back to the Skeleton's
|
|
432
|
+
// own socket array, so the rig-level socket is restored where it
|
|
433
|
+
// lived rather than on a mesh.
|
|
434
|
+
TSharedPtr<FJsonObject> Payload = MakeShared<FJsonObject>();
|
|
435
|
+
Payload->SetStringField(TEXT("assetPath"), AssetPath);
|
|
436
|
+
Payload->SetStringField(TEXT("socketName"), SocketName);
|
|
437
|
+
Payload->SetStringField(TEXT("boneName"), PrevBone);
|
|
438
|
+
Payload->SetObjectField(TEXT("relativeLocation"), MCPVec3ToJsonObject(PrevLoc));
|
|
439
|
+
Payload->SetObjectField(TEXT("relativeRotation"), MCPRotatorToJsonObject(PrevRot));
|
|
440
|
+
Payload->SetObjectField(TEXT("relativeScale"), MCPVec3ToJsonObject(PrevScale));
|
|
441
|
+
Payload->SetStringField(TEXT("onConflict"), TEXT("update"));
|
|
442
|
+
MCPSetRollback(Result, TEXT("add_socket"), Payload);
|
|
388
443
|
return MCPResult(Result);
|
|
389
444
|
}
|
|
390
445
|
}
|
package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Subobject.cpp
CHANGED
|
@@ -268,6 +268,18 @@ TSharedPtr<FJsonValue> FAssetHandlers::CreateSubobject(const TSharedPtr<FJsonObj
|
|
|
268
268
|
OwnerAsset->PostEditChange();
|
|
269
269
|
OwnerPackage->MarkPackageDirty();
|
|
270
270
|
|
|
271
|
+
// The new object lives inside a package that existed before this call, and
|
|
272
|
+
// nothing in this surface takes one back out: delete_asset would destroy
|
|
273
|
+
// the owning asset along with everything else in it, which is a larger loss
|
|
274
|
+
// than the thing being undone. Undoing this needs a remove_subobject that
|
|
275
|
+
// does not exist, so the property values overwritten on a reused subobject
|
|
276
|
+
// are not recoverable through the bridge either.
|
|
277
|
+
MCPSetNoRollback(Result, FString::Printf(
|
|
278
|
+
TEXT("Created or reconfigured the subobject '%s' inside the existing package '%s'. No action removes a named ")
|
|
279
|
+
TEXT("subobject from a package or restores its previous property values; delete_asset would destroy the whole ")
|
|
280
|
+
TEXT("owning asset rather than undo this."),
|
|
281
|
+
*Name, *OwnerPackage->GetName()));
|
|
282
|
+
|
|
271
283
|
// Saving in the same call is what closes the garbage-collection window the
|
|
272
284
|
// issue is about: after this the subobject is an export on disk, so a later
|
|
273
285
|
// call resolves it by path even if the in-memory copy is collected.
|
|
@@ -2743,6 +2743,10 @@ TSharedPtr<FJsonValue> FAssetHandlers::ExportUvLayout(const TSharedPtr<FJsonObje
|
|
|
2743
2743
|
TEXT("The %dx%d UV layout for '%s' could not be PNG-encoded."), Size, Size, *Target.AssetPath));
|
|
2744
2744
|
}
|
|
2745
2745
|
const TArray64<uint8> PngData = PngWrapper->GetCompressed(100);
|
|
2746
|
+
// Asked before the write, because afterwards every export looks like a
|
|
2747
|
+
// first one. A caller rerunning this over a directory it is collecting
|
|
2748
|
+
// pictures in wants to know which of them it just replaced.
|
|
2749
|
+
const bool bOverwroteExistingFile = FPaths::FileExists(OutputPath);
|
|
2746
2750
|
if (!FFileHelper::SaveArrayToFile(PngData, *OutputPath))
|
|
2747
2751
|
{
|
|
2748
2752
|
return MCPError(FString::Printf(
|
|
@@ -2764,6 +2768,33 @@ TSharedPtr<FJsonValue> FAssetHandlers::ExportUvLayout(const TSharedPtr<FJsonObje
|
|
|
2764
2768
|
TEXT("White wire = UV triangle edges. Yellow border = the unit square. Grey grid = quarters. Coloured fill ")
|
|
2765
2769
|
TEXT("= one hue per UV island. Red fill = two or more triangles on the same texel, which is what breaks ")
|
|
2766
2770
|
TEXT("a lightmap bake."));
|
|
2771
|
+
|
|
2772
|
+
// The render always runs and the file is always written, so the honest
|
|
2773
|
+
// answer to "did this change anything" is whether a picture was already
|
|
2774
|
+
// sitting at that path.
|
|
2775
|
+
if (bOverwroteExistingFile)
|
|
2776
|
+
{
|
|
2777
|
+
MCPSetExisted(Result);
|
|
2778
|
+
MCPSetUpdated(Result);
|
|
2779
|
+
}
|
|
2780
|
+
else
|
|
2781
|
+
{
|
|
2782
|
+
MCPSetCreated(Result);
|
|
2783
|
+
}
|
|
2784
|
+
|
|
2785
|
+
// The mesh is untouched: this writes a preview PNG under Saved/ and nothing
|
|
2786
|
+
// else. An export produces an output artifact rather than project state,
|
|
2787
|
+
// and deleting a picture that regenerates on demand from the same call is
|
|
2788
|
+
// not a meaningful undo, so no inverse is named. The six export_* actions
|
|
2789
|
+
// that predate this one emit no rollback for the same reason.
|
|
2790
|
+
const FString OverwriteNote = bOverwroteExistingFile
|
|
2791
|
+
? FString(TEXT(" The picture that was already at that path is gone and no copy was kept."))
|
|
2792
|
+
: FString();
|
|
2793
|
+
MCPSetNoRollback(Result, FString::Printf(
|
|
2794
|
+
TEXT("Wrote the preview PNG '%s' and changed no project state. An export produces an output artifact, and ")
|
|
2795
|
+
TEXT("deleting a file that this same call regenerates on demand is not a meaningful undo, so no inverse is ")
|
|
2796
|
+
TEXT("named.%s"),
|
|
2797
|
+
*OutputPath, *OverwriteNote));
|
|
2767
2798
|
return MCPResult(Result);
|
|
2768
2799
|
}
|
|
2769
2800
|
|
|
@@ -65,10 +65,14 @@
|
|
|
65
65
|
#include "EdGraph/EdGraphNode.h"
|
|
66
66
|
|
|
67
67
|
#include "MetasoundBuilderBase.h"
|
|
68
|
+
// MetasoundDocumentBuilderRegistry.h, and never MetasoundFrontendDocumentBuilderRegistry.h:
|
|
69
|
+
// the frontend header ships on 5.8 only. This MetasoundEngine header reaches
|
|
70
|
+
// Metasound::Frontend::IDocumentBuilderRegistry on every supported engine, by
|
|
71
|
+
// including the frontend header on 5.8 and MetasoundDocumentInterface.h, where
|
|
72
|
+
// 5.7 and earlier declare the class, on all of them.
|
|
68
73
|
#include "MetasoundDocumentBuilderRegistry.h"
|
|
69
74
|
#include "MetasoundDocumentInterface.h"
|
|
70
75
|
#include "MetasoundFrontendDocument.h"
|
|
71
|
-
#include "MetasoundFrontendDocumentBuilderRegistry.h"
|
|
72
76
|
#include "MetasoundFrontendLiteral.h"
|
|
73
77
|
#include "MetasoundSource.h"
|
|
74
78
|
|
|
@@ -240,9 +244,18 @@ namespace
|
|
|
240
244
|
const FMetasoundFrontendDocument* MSEditDocument(const FMSEditTarget& T)
|
|
241
245
|
{
|
|
242
246
|
if (!T.Builder) return nullptr;
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
247
|
+
// Through the builder's own document rather than through the MetaSound
|
|
248
|
+
// object it is editing. UMetaSoundBuilderBase::GetMetaSound arrived in
|
|
249
|
+
// 5.8, and the two accessors that would stand in for it on 5.7 are
|
|
250
|
+
// private in both engines, but GetConstDocumentChecked has been public
|
|
251
|
+
// on FMetaSoundFrontendDocumentBuilder throughout and is what the
|
|
252
|
+
// GetMetaSound round trip was reaching for anyway.
|
|
253
|
+
//
|
|
254
|
+
// IsValid first, because the Checked form asserts on a builder with no
|
|
255
|
+
// document while the round trip it replaces returned null for it.
|
|
256
|
+
const FMetaSoundFrontendDocumentBuilder& Builder = T.Builder->GetConstBuilder();
|
|
257
|
+
if (!Builder.IsValid()) return nullptr;
|
|
258
|
+
return &Builder.GetConstDocumentChecked();
|
|
246
259
|
}
|
|
247
260
|
|
|
248
261
|
/**
|
package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AudioHandlers_MetaSound.cpp
CHANGED
|
@@ -45,9 +45,13 @@
|
|
|
45
45
|
|
|
46
46
|
#include "MetasoundBuilderSubsystem.h"
|
|
47
47
|
#include "MetasoundBuilderBase.h"
|
|
48
|
+
// MetasoundDocumentBuilderRegistry.h, and never MetasoundFrontendDocumentBuilderRegistry.h:
|
|
49
|
+
// the frontend header ships on 5.8 only. This MetasoundEngine header reaches
|
|
50
|
+
// Metasound::Frontend::IDocumentBuilderRegistry on every supported engine, by
|
|
51
|
+
// including the frontend header on 5.8 and MetasoundDocumentInterface.h, where
|
|
52
|
+
// 5.7 and earlier declare the class, on all of them.
|
|
48
53
|
#include "MetasoundDocumentBuilderRegistry.h"
|
|
49
54
|
#include "MetasoundDocumentInterface.h"
|
|
50
|
-
#include "MetasoundFrontendDocumentBuilderRegistry.h"
|
|
51
55
|
#include "MetasoundSource.h"
|
|
52
56
|
#include "MetasoundFrontendLiteral.h"
|
|
53
57
|
#include "MetasoundFrontendDocument.h"
|
package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AudioHandlers_MetaSoundRead.cpp
CHANGED
|
@@ -39,9 +39,14 @@
|
|
|
39
39
|
|
|
40
40
|
#include "MetasoundBuilderSubsystem.h"
|
|
41
41
|
#include "MetasoundBuilderBase.h"
|
|
42
|
+
// MetasoundDocumentBuilderRegistry.h, and never MetasoundFrontendDocumentBuilderRegistry.h:
|
|
43
|
+
// the frontend header ships on 5.8 only. This MetasoundEngine header reaches
|
|
44
|
+
// Metasound::Frontend::IDocumentBuilderRegistry on every supported engine, by
|
|
45
|
+
// including the frontend header on 5.8 and MetasoundDocumentInterface.h, where
|
|
46
|
+
// 5.7 and earlier declare the class, on all of them.
|
|
47
|
+
#include "MetasoundDocumentBuilderRegistry.h"
|
|
42
48
|
#include "MetasoundDocumentInterface.h"
|
|
43
49
|
#include "MetasoundFrontendDocument.h"
|
|
44
|
-
#include "MetasoundFrontendDocumentBuilderRegistry.h"
|
|
45
50
|
#include "MetasoundFrontendLiteral.h"
|
|
46
51
|
#include "MetasoundSource.h"
|
|
47
52
|
|