More work on handlers

This commit is contained in:
2026-03-12 01:31:57 -04:00
parent d69fc4cd1e
commit cf9ffc619c
34 changed files with 88 additions and 116 deletions

View File

@@ -80,6 +80,7 @@ public:
FName VarFName = VarDesc->VarName; FName VarFName = VarDesc->VarName;
int32 ChangeCount = 0; int32 ChangeCount = 0;
F.PreEdit();
// Category // Category
if (Json->HasField(TEXT("category"))) if (Json->HasField(TEXT("category")))
@@ -179,9 +180,7 @@ public:
return; return;
} }
BP->PreEditChange(nullptr); F.PostEdit();
BP->PostEditChange();
FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(BP);
bool bSaved = MCPUtils::SaveBlueprintPackage(BP); bool bSaved = MCPUtils::SaveBlueprintPackage(BP);
Result.Appendf(TEXT("Updated %d field(s) on %s in %s.%s\n"), Result.Appendf(TEXT("Updated %d field(s) on %s in %s.%s\n"),

View File

@@ -73,7 +73,7 @@ public:
UBlendSpace* BS = Assets.Object(); UBlendSpace* BS = Assets.Object();
// Set axis parameters // Set axis parameters
BS->PreEditChange(nullptr); MCPUtils::PreEdit({BS});
const FBlendParameter& ParamX = BS->GetBlendParameter(0); const FBlendParameter& ParamX = BS->GetBlendParameter(0);
const FBlendParameter& ParamY = BS->GetBlendParameter(1); const FBlendParameter& ParamY = BS->GetBlendParameter(1);
@@ -126,10 +126,9 @@ public:
} }
BS->ValidateSampleData(); BS->ValidateSampleData();
BS->PostEditChange(); MCPUtils::PostEdit({BS});
// Save // Save
BS->MarkPackageDirty();
bool bSaved = MCPUtils::SaveGenericPackage(BS); bool bSaved = MCPUtils::SaveGenericPackage(BS);
Result.Appendf(TEXT("Set %d samples on %s\n"), SamplesSet, *MCPUtils::FormatName(BS)); Result.Appendf(TEXT("Set %d samples on %s\n"), SamplesSet, *MCPUtils::FormatName(BS));

View File

@@ -70,7 +70,6 @@ public:
// Set skeleton. // Set skeleton.
NewBS->SetSkeleton(SkeletonObj); NewBS->SetSkeleton(SkeletonObj);
// Mark dirty and save.
NewBS->MarkPackageDirty(); NewBS->MarkPackageDirty();
bool bSaved = MCPUtils::SaveGenericPackage(NewBS); bool bSaved = MCPUtils::SaveGenericPackage(NewBS);

View File

@@ -69,6 +69,8 @@ public:
} }
} }
F.PreEdit();
if (GraphType == TEXT("function")) if (GraphType == TEXT("function"))
{ {
UEdGraph* NewGraph = FBlueprintEditorUtils::CreateNewGraph(BP, FName(*Graph), UEdGraph* NewGraph = FBlueprintEditorUtils::CreateNewGraph(BP, FName(*Graph),
@@ -114,7 +116,7 @@ public:
Result.Appendf(TEXT("Created custom event: %s\n"), *MCPUtils::FormatName(NewEvent)); Result.Appendf(TEXT("Created custom event: %s\n"), *MCPUtils::FormatName(NewEvent));
} }
FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(BP); F.PostEdit();
MCPUtils::SaveBlueprintPackage(BP); MCPUtils::SaveBlueprintPackage(BP);
} }
}; };

View File

@@ -85,8 +85,9 @@ public:
// Remove the graph // Remove the graph
FString GraphName = MCPUtils::FormatName(TargetGraph); FString GraphName = MCPUtils::FormatName(TargetGraph);
F.PreEdit();
FBlueprintEditorUtils::RemoveGraph(BP, TargetGraph, EGraphRemoveFlags::Default); FBlueprintEditorUtils::RemoveGraph(BP, TargetGraph, EGraphRemoveFlags::Default);
FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(BP); F.PostEdit();
bool bSaved = MCPUtils::SaveBlueprintPackage(BP); bool bSaved = MCPUtils::SaveBlueprintPackage(BP);
Result.Appendf(TEXT("Deleted %s graph %s\n"), *GraphType, *GraphName); Result.Appendf(TEXT("Deleted %s graph %s\n"), *GraphType, *GraphName);

View File

@@ -73,8 +73,9 @@ public:
} }
} }
F.PreEdit();
FBlueprintEditorUtils::RenameGraph(TargetGraph, NewName); FBlueprintEditorUtils::RenameGraph(TargetGraph, NewName);
FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(BP); F.PostEdit();
MCPUtils::SaveBlueprintPackage(BP); MCPUtils::SaveBlueprintPackage(BP);
Result.Appendf(TEXT("Renamed to %s %s\n"), Result.Appendf(TEXT("Renamed to %s %s\n"),

View File

@@ -8,7 +8,6 @@
#include "Engine/SimpleConstructionScript.h" #include "Engine/SimpleConstructionScript.h"
#include "Engine/SCS_Node.h" #include "Engine/SCS_Node.h"
#include "Components/ActorComponent.h" #include "Components/ActorComponent.h"
#include "Kismet2/BlueprintEditorUtils.h"
#include "Blueprint_AddComponent.generated.h" #include "Blueprint_AddComponent.generated.h"
@@ -107,6 +106,7 @@ public:
} }
// Create the SCS node // Create the SCS node
MCPUtils::PreEdit({BP});
USCS_Node* NewNode = SCS->CreateNode(ComponentClassObj, FName(*Component)); USCS_Node* NewNode = SCS->CreateNode(ComponentClassObj, FName(*Component));
if (!NewNode) if (!NewNode)
{ {
@@ -126,7 +126,7 @@ public:
SCS->AddNode(NewNode); SCS->AddNode(NewNode);
} }
FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(BP); MCPUtils::PostEdit({BP});
bool bSaved = MCPUtils::SaveBlueprintPackage(BP); bool bSaved = MCPUtils::SaveBlueprintPackage(BP);
Result.Appendf(TEXT("Added component %s (%s)"), Result.Appendf(TEXT("Added component %s (%s)"),

View File

@@ -75,6 +75,7 @@ public:
} }
// Add a member variable with PC_MCDelegate pin type // Add a member variable with PC_MCDelegate pin type
F.PreEdit();
FEdGraphPinType DelegateType; FEdGraphPinType DelegateType;
DelegateType.PinCategory = UEdGraphSchema_K2::PC_MCDelegate; DelegateType.PinCategory = UEdGraphSchema_K2::PC_MCDelegate;
if (!FBlueprintEditorUtils::AddMemberVariable(BP, DispatcherFName, DelegateType)) if (!FBlueprintEditorUtils::AddMemberVariable(BP, DispatcherFName, DelegateType))
@@ -115,7 +116,7 @@ public:
if (!EntryNode) if (!EntryNode)
{ {
FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(BP); F.PostEdit();
MCPUtils::SaveBlueprintPackage(BP); MCPUtils::SaveBlueprintPackage(BP);
Result.Append(TEXT("Error: Event dispatcher created but entry node not found — parameters could not be added.\n")); Result.Append(TEXT("Error: Event dispatcher created but entry node not found — parameters could not be added.\n"));
return; return;
@@ -136,7 +137,7 @@ public:
} }
} }
FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(BP); F.PostEdit();
MCPUtils::SaveBlueprintPackage(BP); MCPUtils::SaveBlueprintPackage(BP);
Result.Appendf(TEXT("Created event dispatcher '%s'"), *DispatcherName); Result.Appendf(TEXT("Created event dispatcher '%s'"), *DispatcherName);

View File

@@ -133,9 +133,9 @@ public:
} }
// Add the parameter pin (EGPD_Output on entry = input to callers) // Add the parameter pin (EGPD_Output on entry = input to callers)
MCPUtils::PreEdit({BP});
EntryNode->CreateUserDefinedPin(FName(*ParamName), PinType, EGPD_Output); EntryNode->CreateUserDefinedPin(FName(*ParamName), PinType, EGPD_Output);
MCPUtils::PostEdit({BP});
FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(BP);
bool bSaved = MCPUtils::SaveBlueprintPackage(BP); bool bSaved = MCPUtils::SaveBlueprintPackage(BP);
Result.Appendf(TEXT("Added %s parameter '%s' to %s '%s'%s\n"), Result.Appendf(TEXT("Added %s parameter '%s' to %s '%s'%s\n"),

View File

@@ -55,6 +55,7 @@ public:
} }
FTopLevelAssetPath InterfacePath = InterfaceClass->GetClassPathName(); FTopLevelAssetPath InterfacePath = InterfaceClass->GetClassPathName();
MCPUtils::PreEdit({BP});
bool bAdded = FBlueprintEditorUtils::ImplementNewInterface(BP, InterfacePath); bool bAdded = FBlueprintEditorUtils::ImplementNewInterface(BP, InterfacePath);
if (!bAdded) if (!bAdded)
{ {
@@ -65,7 +66,7 @@ public:
} }
// Collect stub function graph names from the newly added interface entry // Collect stub function graph names from the newly added interface entry
FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(BP); MCPUtils::PostEdit({BP});
Result.Appendf(TEXT("Added interface %s\n"), *MCPUtils::FormatName(InterfaceClass)); Result.Appendf(TEXT("Added interface %s\n"), *MCPUtils::FormatName(InterfaceClass));
Result.Appendf(TEXT("Function stubs:\n")); Result.Appendf(TEXT("Function stubs:\n"));

View File

@@ -69,6 +69,7 @@ public:
PinType.ContainerType = EPinContainerType::Array; PinType.ContainerType = EPinContainerType::Array;
// Add the variable // Add the variable
MCPUtils::PreEdit({BP});
if (!FBlueprintEditorUtils::AddMemberVariable(BP, VarFName, PinType, DefaultValue)) if (!FBlueprintEditorUtils::AddMemberVariable(BP, VarFName, PinType, DefaultValue))
{ {
MCPErrorCallback(Result).SetError(FString::Printf( MCPErrorCallback(Result).SetError(FString::Printf(
@@ -79,7 +80,7 @@ public:
if (!Category.IsEmpty()) if (!Category.IsEmpty())
FBlueprintEditorUtils::SetBlueprintVariableCategory(BP, VarFName, nullptr, FText::FromString(Category)); FBlueprintEditorUtils::SetBlueprintVariableCategory(BP, VarFName, nullptr, FText::FromString(Category));
FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(BP); MCPUtils::PostEdit({BP});
bool bSaved = MCPUtils::SaveBlueprintPackage(BP); bool bSaved = MCPUtils::SaveBlueprintPackage(BP);
Result.Appendf(TEXT("Added %s %s to %s\n"), Result.Appendf(TEXT("Added %s %s to %s\n"),

View File

@@ -135,7 +135,8 @@ public:
return; return;
} }
// Apply the type change // Apply the type change (PreEdit/PostEdit on the node itself, not the BP —
// MCPUtils::PreEdit/PostEdit operates at BP level, not node level)
EntryNode->PreEditChange(nullptr); EntryNode->PreEditChange(nullptr);
(*FoundPinInfo)->PinType = NewPinType; (*FoundPinInfo)->PinType = NewPinType;
EntryNode->PostEditChange(); EntryNode->PostEditChange();

View File

@@ -9,7 +9,6 @@
#include "EdGraph/EdGraphPin.h" #include "EdGraph/EdGraphPin.h"
#include "K2Node_VariableGet.h" #include "K2Node_VariableGet.h"
#include "K2Node_VariableSet.h" #include "K2Node_VariableSet.h"
#include "Kismet2/BlueprintEditorUtils.h"
#include "Blueprint_ChangeVariableType.generated.h" #include "Blueprint_ChangeVariableType.generated.h"
@@ -129,9 +128,9 @@ public:
} }
// Apply the type change // Apply the type change
BP->PreEditChange(nullptr); F.PreEdit();
Found->VarType = NewPinType; Found->VarType = NewPinType;
BP->PostEditChange(); F.PostEdit();
bool bSaved = MCPUtils::SaveBlueprintPackage(BP); bool bSaved = MCPUtils::SaveBlueprintPackage(BP);
Result.Appendf(TEXT("Changed %s to %s.%s\n"), Result.Appendf(TEXT("Changed %s to %s.%s\n"),

View File

@@ -42,6 +42,7 @@ public:
int32 NodeCount = MCPUtils::AllNodes(BP).Num(); int32 NodeCount = MCPUtils::AllNodes(BP).Num();
// Refresh all nodes // Refresh all nodes
MCPUtils::PreEdit({BP});
FBlueprintEditorUtils::RefreshAllNodes(BP); FBlueprintEditorUtils::RefreshAllNodes(BP);
// Remove orphaned pins from all nodes // Remove orphaned pins from all nodes
@@ -61,7 +62,7 @@ public:
} }
// Mark as modified and recompile after orphan removal // Mark as modified and recompile after orphan removal
FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(BP); MCPUtils::PostEdit({BP});
// Summary // Summary
Result.Appendf(TEXT("Refreshed %s: %d graphs, %d nodes"), *MCPUtils::FormatName(BP), GraphCount, NodeCount); Result.Appendf(TEXT("Refreshed %s: %d graphs, %d nodes"), *MCPUtils::FormatName(BP), GraphCount, NodeCount);

View File

@@ -7,7 +7,6 @@
#include "Engine/Blueprint.h" #include "Engine/Blueprint.h"
#include "Engine/SimpleConstructionScript.h" #include "Engine/SimpleConstructionScript.h"
#include "Engine/SCS_Node.h" #include "Engine/SCS_Node.h"
#include "Kismet2/BlueprintEditorUtils.h"
#include "Blueprint_RemoveComponent.generated.h" #include "Blueprint_RemoveComponent.generated.h"
@@ -84,9 +83,10 @@ public:
FString RemovedName = MCPUtils::FormatName(NodeToRemove->ComponentTemplate); FString RemovedName = MCPUtils::FormatName(NodeToRemove->ComponentTemplate);
// Remove the node (promotes children to parent if it has any — but we've guarded root above) // Remove the node (promotes children to parent if it has any — but we've guarded root above)
F.PreEdit();
SCS->RemoveNodeAndPromoteChildren(NodeToRemove); SCS->RemoveNodeAndPromoteChildren(NodeToRemove);
F.PostEdit();
FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(BP);
bool bSaved = MCPUtils::SaveBlueprintPackage(BP); bool bSaved = MCPUtils::SaveBlueprintPackage(BP);
Result.Appendf(TEXT("Removed component %s.%s\n"), Result.Appendf(TEXT("Removed component %s.%s\n"),

View File

@@ -65,8 +65,9 @@ public:
} }
FTopLevelAssetPath InterfacePath = FoundInterface->GetClassPathName(); FTopLevelAssetPath InterfacePath = FoundInterface->GetClassPathName();
MCPUtils::PreEdit({BP});
FBlueprintEditorUtils::RemoveInterface(BP, InterfacePath, PreserveFunctions); FBlueprintEditorUtils::RemoveInterface(BP, InterfacePath, PreserveFunctions);
FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(BP); MCPUtils::PostEdit({BP});
Result.Appendf(TEXT("Removed interface %s\n"), *MCPUtils::FormatName(FoundInterface)); Result.Appendf(TEXT("Removed interface %s\n"), *MCPUtils::FormatName(FoundInterface));
if (PreserveFunctions) if (PreserveFunctions)

View File

@@ -62,8 +62,9 @@ public:
FName VarFName = Found->VarName; FName VarFName = Found->VarName;
// RemoveMemberVariable also cleans up Get/Set nodes // RemoveMemberVariable also cleans up Get/Set nodes
F.PreEdit();
FBlueprintEditorUtils::RemoveMemberVariable(BP, VarFName); FBlueprintEditorUtils::RemoveMemberVariable(BP, VarFName);
FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(BP); F.PostEdit();
bool bSaved = MCPUtils::SaveBlueprintPackage(BP); bool bSaved = MCPUtils::SaveBlueprintPackage(BP);
Result.Appendf(TEXT("Removed variable %s from %s.%s\n"), Result.Appendf(TEXT("Removed variable %s from %s.%s\n"),

View File

@@ -61,9 +61,9 @@ public:
} }
// Perform reparent // Perform reparent
BP->PreEditChange(nullptr); MCPUtils::PreEdit({BP});
BP->ParentClass = NewParentClassObj; BP->ParentClass = NewParentClassObj;
BP->PostEditChange(); MCPUtils::PostEdit({BP});
FBlueprintEditorUtils::RefreshAllNodes(BP); FBlueprintEditorUtils::RefreshAllNodes(BP);
FKismetEditorUtilities::CompileBlueprint(BP); FKismetEditorUtilities::CompileBlueprint(BP);
bool bSaved = MCPUtils::SaveBlueprintPackage(BP); bool bSaved = MCPUtils::SaveBlueprintPackage(BP);

View File

@@ -4,11 +4,9 @@
#include "MCPHandler.h" #include "MCPHandler.h"
#include "MCPFetcher.h" #include "MCPFetcher.h"
#include "MCPUtils.h" #include "MCPUtils.h"
#include "Engine/Blueprint.h"
#include "EdGraph/EdGraph.h" #include "EdGraph/EdGraph.h"
#include "EdGraph/EdGraphNode.h" #include "EdGraph/EdGraphNode.h"
#include "EdGraph/EdGraphSchema.h" #include "EdGraph/EdGraphSchema.h"
#include "Kismet2/BlueprintEditorUtils.h"
#include "GraphNode_Create.generated.h" #include "GraphNode_Create.generated.h"
@@ -57,6 +55,7 @@ public:
UEdGraph* TargetGraph = F.Walk(Graph).Cast<UEdGraph>(); UEdGraph* TargetGraph = F.Walk(Graph).Cast<UEdGraph>();
if (!TargetGraph) return; if (!TargetGraph) return;
F.PreEdit();
int32 SuccessCount = 0; int32 SuccessCount = 0;
int32 TotalCount = Nodes.Array.Num(); int32 TotalCount = Nodes.Array.Num();
@@ -98,16 +97,7 @@ public:
SuccessCount++; SuccessCount++;
} }
// Mark the owning asset as modified F.PostEdit();
UBlueprint* BP = Cast<UBlueprint>(TargetGraph->GetOuter());
if (BP)
FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(BP);
TargetGraph->NotifyGraphChanged();
UObject* Outer = TargetGraph->GetOuter();
if (Outer)
Outer->MarkPackageDirty();
Result.Appendf(TEXT("Spawned %d/%d nodes.\n"), SuccessCount, TotalCount); Result.Appendf(TEXT("Spawned %d/%d nodes.\n"), SuccessCount, TotalCount);
} }

View File

@@ -5,10 +5,6 @@
#include "MCPFetcher.h" #include "MCPFetcher.h"
#include "MCPUtils.h" #include "MCPUtils.h"
#include "EdGraph/EdGraphNode.h" #include "EdGraph/EdGraphNode.h"
#include "K2Node_Event.h"
#include "K2Node_CustomEvent.h"
#include "K2Node_FunctionEntry.h"
#include "Kismet2/BlueprintEditorUtils.h"
#include "GraphNode_Delete.generated.h" #include "GraphNode_Delete.generated.h"
@@ -27,8 +23,8 @@ public:
virtual FString GetDescription() const override virtual FString GetDescription() const override
{ {
return TEXT("Delete a node from a Blueprint graph. " return TEXT("Delete a node from a graph. "
"Cannot delete entry nodes (FunctionEntry, Event, CustomEvent)."); "Cannot delete undeletable nodes (entry points, root nodes, etc).");
} }
virtual void Handle(const FJsonObject* Json, FStringBuilderBase& Result) override virtual void Handle(const FJsonObject* Json, FStringBuilderBase& Result) override
@@ -38,42 +34,21 @@ public:
if (!FoundNode) return; if (!FoundNode) return;
UEdGraph* Graph = FoundNode->GetGraph(); UEdGraph* Graph = FoundNode->GetGraph();
UBlueprint* BP = FBlueprintEditorUtils::FindBlueprintForNodeChecked(FoundNode);
// Protect root/entry nodes — deleting these leaves the graph in an invalid
// state with no root node, causing compiler errors that can't be fixed
// without recreating the entire function/event.
MCPErrorCallback Error(Result);
FString NodeTitle = MCPUtils::FormatName(FoundNode); FString NodeTitle = MCPUtils::FormatName(FoundNode);
FString GraphName = MCPUtils::FormatName(Graph); FString GraphName = MCPUtils::FormatName(Graph);
if (Cast<UK2Node_FunctionEntry>(FoundNode)) if (!FoundNode->CanUserDeleteNode())
{ {
MCPErrorCallback Error(Result);
return Error.SetError(FString::Printf( return Error.SetError(FString::Printf(
TEXT("Cannot delete FunctionEntry node '%s' in graph '%s'. ") TEXT("Cannot delete node '%s' in graph '%s' — it is not deletable."),
TEXT("This is the root node of the function — removing it would leave an empty, uncompilable graph. ")
TEXT("To remove the entire function, delete it from the Blueprint editor."),
*NodeTitle, *GraphName));
}
if (Cast<UK2Node_Event>(FoundNode))
{
return Error.SetError(FString::Printf(
TEXT("Cannot delete event entry node '%s' in graph '%s'. ")
TEXT("This is the root node of the event handler — removing it would leave an empty, uncompilable graph."),
*NodeTitle, *GraphName));
}
if (Cast<UK2Node_CustomEvent>(FoundNode))
{
return Error.SetError(FString::Printf(
TEXT("Cannot delete CustomEvent entry node '%s' in graph '%s'. ")
TEXT("This is the root node of the custom event — removing it would leave an empty, uncompilable graph."),
*NodeTitle, *GraphName)); *NodeTitle, *GraphName));
} }
F.PreEdit();
FoundNode->BreakAllNodeLinks(); FoundNode->BreakAllNodeLinks();
Graph->RemoveNode(FoundNode); Graph->RemoveNode(FoundNode);
F.PostEdit();
FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(BP);
Result.Appendf(TEXT("Deleted node '%s' from graph '%s'.\n"), *NodeTitle, *GraphName); Result.Appendf(TEXT("Deleted node '%s' from graph '%s'.\n"), *NodeTitle, *GraphName);
} }

View File

@@ -4,11 +4,9 @@
#include "MCPHandler.h" #include "MCPHandler.h"
#include "MCPFetcher.h" #include "MCPFetcher.h"
#include "MCPUtils.h" #include "MCPUtils.h"
#include "Engine/Blueprint.h"
#include "EdGraph/EdGraph.h" #include "EdGraph/EdGraph.h"
#include "EdGraph/EdGraphNode.h" #include "EdGraph/EdGraphNode.h"
#include "EdGraph/EdGraphPin.h" #include "EdGraph/EdGraphPin.h"
#include "Kismet2/BlueprintEditorUtils.h"
#include "GraphNode_Duplicate.generated.h" #include "GraphNode_Duplicate.generated.h"
@@ -77,6 +75,7 @@ public:
if (SourceNodes.Num() == 0) return; if (SourceNodes.Num() == 0) return;
F.PreEdit();
// Duplicate each node // Duplicate each node
for (UEdGraphNode* SourceNode : SourceNodes) for (UEdGraphNode* SourceNode : SourceNodes)
{ {
@@ -101,8 +100,6 @@ public:
Result.Appendf(TEXT("Duplicated: %s -> %s\n"), *MCPUtils::FormatName(SourceNode), *MCPUtils::FormatName(NewNode)); Result.Appendf(TEXT("Duplicated: %s -> %s\n"), *MCPUtils::FormatName(SourceNode), *MCPUtils::FormatName(NewNode));
} }
UBlueprint* BP = Cast<UBlueprint>(TargetGraph->GetOuter()); F.PostEdit();
if (BP)
FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(BP);
} }
}; };

View File

@@ -5,7 +5,6 @@
#include "MCPFetcher.h" #include "MCPFetcher.h"
#include "MCPUtils.h" #include "MCPUtils.h"
#include "EdGraph/EdGraphNode.h" #include "EdGraph/EdGraphNode.h"
#include "Kismet2/BlueprintEditorUtils.h"
#include "GraphNode_SetComment.generated.h" #include "GraphNode_SetComment.generated.h"
@@ -36,6 +35,8 @@ public:
UEdGraphNode* FoundNode = F.Walk(Node).Cast<UEdGraphNode>(); UEdGraphNode* FoundNode = F.Walk(Node).Cast<UEdGraphNode>();
if (!FoundNode) return; if (!FoundNode) return;
F.PreEdit();
FoundNode->NodeComment = Comment; FoundNode->NodeComment = Comment;
// Make the comment bubble visible if setting a non-empty comment // Make the comment bubble visible if setting a non-empty comment
@@ -45,8 +46,7 @@ public:
FoundNode->bCommentBubblePinned = true; FoundNode->bCommentBubblePinned = true;
} }
UBlueprint* BP = FBlueprintEditorUtils::FindBlueprintForNodeChecked(FoundNode); F.PostEdit();
FBlueprintEditorUtils::MarkBlueprintAsModified(BP);
Result.Appendf(TEXT("Comment set on %s\n"), *MCPUtils::FormatName(FoundNode)); Result.Appendf(TEXT("Comment set on %s\n"), *MCPUtils::FormatName(FoundNode));
} }

View File

@@ -6,7 +6,6 @@
#include "MCPUtils.h" #include "MCPUtils.h"
#include "Engine/Blueprint.h" #include "Engine/Blueprint.h"
#include "EdGraph/EdGraphNode.h" #include "EdGraph/EdGraphNode.h"
#include "Kismet2/BlueprintEditorUtils.h"
#include "GraphNode_SetPositions.generated.h" #include "GraphNode_SetPositions.generated.h"
@@ -53,6 +52,8 @@ public:
UBlueprint* BP = F.Walk(Blueprint).Cast<UBlueprint>(); UBlueprint* BP = F.Walk(Blueprint).Cast<UBlueprint>();
if (!BP) return; if (!BP) return;
F.PreEdit();
int32 SuccessCount = 0; int32 SuccessCount = 0;
for (const TSharedPtr<FJsonValue>& NodeVal : Nodes.Array) for (const TSharedPtr<FJsonValue>& NodeVal : Nodes.Array)
@@ -70,7 +71,7 @@ public:
SuccessCount++; SuccessCount++;
} }
FBlueprintEditorUtils::MarkBlueprintAsModified(BP); F.PostEdit();
Result.Appendf(TEXT("Moved %d/%d nodes.\n"), SuccessCount, Nodes.Array.Num()); Result.Appendf(TEXT("Moved %d/%d nodes.\n"), SuccessCount, Nodes.Array.Num());
} }
}; };

View File

@@ -5,7 +5,6 @@
#include "MCPFetcher.h" #include "MCPFetcher.h"
#include "MCPUtils.h" #include "MCPUtils.h"
#include "EdGraph/EdGraphPin.h" #include "EdGraph/EdGraphPin.h"
#include "Kismet2/BlueprintEditorUtils.h"
#include "GraphPin_Connect.generated.h" #include "GraphPin_Connect.generated.h"
@@ -49,6 +48,8 @@ public:
UBlueprint* BP = F.Walk(Blueprint).Cast<UBlueprint>(); UBlueprint* BP = F.Walk(Blueprint).Cast<UBlueprint>();
if (!BP) return; if (!BP) return;
F.PreEdit();
int32 SuccessCount = 0; int32 SuccessCount = 0;
int32 TotalCount = Connections.Array.Num(); int32 TotalCount = Connections.Array.Num();
@@ -81,10 +82,7 @@ public:
SuccessCount++; SuccessCount++;
} }
if (SuccessCount > 0) F.PostEdit();
{
FBlueprintEditorUtils::MarkBlueprintAsModified(BP);
}
Result.Appendf(TEXT("Connected %d/%d pins.\n"), SuccessCount, TotalCount); Result.Appendf(TEXT("Connected %d/%d pins.\n"), SuccessCount, TotalCount);
} }

View File

@@ -5,7 +5,6 @@
#include "MCPFetcher.h" #include "MCPFetcher.h"
#include "MCPUtils.h" #include "MCPUtils.h"
#include "EdGraph/EdGraphPin.h" #include "EdGraph/EdGraphPin.h"
#include "Kismet2/BlueprintEditorUtils.h"
#include "GraphPin_Disconnect.generated.h" #include "GraphPin_Disconnect.generated.h"
@@ -50,6 +49,8 @@ public:
UBlueprint* BP = F.Walk(Blueprint).Cast<UBlueprint>(); UBlueprint* BP = F.Walk(Blueprint).Cast<UBlueprint>();
if (!BP) return; if (!BP) return;
F.PreEdit();
int32 SuccessCount = 0; int32 SuccessCount = 0;
int32 TotalDisconnected = 0; int32 TotalDisconnected = 0;
@@ -97,10 +98,7 @@ public:
TotalDisconnected += DisconnectedCount; TotalDisconnected += DisconnectedCount;
} }
if (TotalDisconnected > 0) F.PostEdit();
{
FBlueprintEditorUtils::MarkBlueprintAsModified(BP);
}
Result.Appendf(TEXT("Done: %d/%d succeeded, %d links broken.\n"), Result.Appendf(TEXT("Done: %d/%d succeeded, %d links broken.\n"),
SuccessCount, Disconnections.Array.Num(), TotalDisconnected); SuccessCount, Disconnections.Array.Num(), TotalDisconnected);

View File

@@ -5,7 +5,6 @@
#include "MCPFetcher.h" #include "MCPFetcher.h"
#include "MCPUtils.h" #include "MCPUtils.h"
#include "EdGraph/EdGraphPin.h" #include "EdGraph/EdGraphPin.h"
#include "Kismet2/BlueprintEditorUtils.h"
#include "GraphPin_SetDefault.generated.h" #include "GraphPin_SetDefault.generated.h"

View File

@@ -91,9 +91,10 @@ public:
} }
// Set parent. // Set parent.
MI->PreEditChange(nullptr); TArray<UObject*> Chain = { MI };
MCPUtils::PreEdit(Chain);
MI->Parent = ParentMaterialObj; MI->Parent = ParentMaterialObj;
MI->PostEditChange(); MCPUtils::PostEdit(Chain);
// Save. // Save.
bool bSaved = MCPUtils::SaveGenericPackage(MI); bool bSaved = MCPUtils::SaveGenericPackage(MI);

View File

@@ -34,9 +34,10 @@ public:
if (!Assets.Exact(Material).Errors(Result).ENone().ETwo().Load()) return; if (!Assets.Exact(Material).Errors(Result).ENone().ETwo().Load()) return;
UMaterial* MaterialObj = Assets.Object(); UMaterial* MaterialObj = Assets.Object();
// Force recompile by triggering PreEditChange/PostEditChange // Force recompile by triggering PreEdit/PostEdit
MaterialObj->PreEditChange(nullptr); TArray<UObject*> Chain = { MaterialObj };
MaterialObj->PostEditChange(); MCPUtils::PreEdit(Chain);
MCPUtils::PostEdit(Chain);
// Check for compilation errors via FMaterialResource on current platform // Check for compilation errors via FMaterialResource on current platform
TArray<FString> Errors; TArray<FString> Errors;

View File

@@ -84,7 +84,8 @@ public:
// Apply optional properties. // Apply optional properties.
bool bHasTwoSided = Json->HasField(TEXT("twoSided")); bool bHasTwoSided = Json->HasField(TEXT("twoSided"));
MaterialObj->PreEditChange(nullptr); TArray<UObject*> Chain = { MaterialObj };
MCPUtils::PreEdit(Chain);
if (!Domain.IsEmpty()) if (!Domain.IsEmpty())
MaterialObj->MaterialDomain = ParsedDomain; MaterialObj->MaterialDomain = ParsedDomain;
@@ -95,7 +96,7 @@ public:
if (bHasTwoSided) if (bHasTwoSided)
MaterialObj->TwoSided = TwoSided; MaterialObj->TwoSided = TwoSided;
MaterialObj->PostEditChange(); MCPUtils::PostEdit(Chain);
bool bSaved = MCPUtils::SaveMaterialPackage(MaterialObj); bool bSaved = MCPUtils::SaveMaterialPackage(MaterialObj);

View File

@@ -74,9 +74,9 @@ public:
return; return;
} }
MI->PreEditChange(nullptr); MCPUtils::PreEdit({MI});
MI->Parent = NewParentObj; MI->Parent = NewParentObj;
MI->PostEditChange(); MCPUtils::PostEdit({MI});
MCPUtils::SaveGenericPackage(MI); MCPUtils::SaveGenericPackage(MI);
Result.Appendf(TEXT("Reparented %s: %s -> %s\n"), Result.Appendf(TEXT("Reparented %s: %s -> %s\n"),

View File

@@ -159,9 +159,8 @@ public:
if (!DryRun) if (!DryRun)
{ {
MI->PreEditChange(nullptr); MCPUtils::PreEdit({MI});
MI->PostEditChange(); MCPUtils::PostEdit({MI});
MI->MarkPackageDirty();
MCPUtils::SaveGenericPackage(MI); MCPUtils::SaveGenericPackage(MI);
} }

View File

@@ -55,7 +55,7 @@ public:
bool bValue = Json->GetBoolField(TEXT("value")); bool bValue = Json->GetBoolField(TEXT("value"));
OldValue = Getter() ? TEXT("true") : TEXT("false"); OldValue = Getter() ? TEXT("true") : TEXT("false");
NewValue = bValue ? TEXT("true") : TEXT("false"); NewValue = bValue ? TEXT("true") : TEXT("false");
if (!DryRun) { Mat->PreEditChange(nullptr); Setter(bValue); Mat->PostEditChange(); } if (!DryRun) Setter(bValue);
}; };
if (Property == TEXT("domain")) if (Property == TEXT("domain"))
@@ -65,7 +65,7 @@ public:
EMaterialDomain NewDomain; EMaterialDomain NewDomain;
if (!MCPUtils::StringToEnum(ValueStr, NewDomain, Result, TEXT("MD_"))) return; if (!MCPUtils::StringToEnum(ValueStr, NewDomain, Result, TEXT("MD_"))) return;
NewValue = MCPUtils::EnumToString(NewDomain, TEXT("MD_")); NewValue = MCPUtils::EnumToString(NewDomain, TEXT("MD_"));
if (!DryRun) { Mat->PreEditChange(nullptr); Mat->MaterialDomain = NewDomain; Mat->PostEditChange(); } if (!DryRun) Mat->MaterialDomain = NewDomain;
} }
else if (Property == TEXT("blendMode")) else if (Property == TEXT("blendMode"))
{ {
@@ -74,7 +74,7 @@ public:
EBlendMode NewBlend; EBlendMode NewBlend;
if (!MCPUtils::StringToEnum(ValueStr, NewBlend, Result, TEXT("BLEND_"))) return; if (!MCPUtils::StringToEnum(ValueStr, NewBlend, Result, TEXT("BLEND_"))) return;
NewValue = MCPUtils::EnumToString(NewBlend, TEXT("BLEND_")); NewValue = MCPUtils::EnumToString(NewBlend, TEXT("BLEND_"));
if (!DryRun) { Mat->PreEditChange(nullptr); Mat->BlendMode = NewBlend; Mat->PostEditChange(); } if (!DryRun) Mat->BlendMode = NewBlend;
} }
else if (Property == TEXT("shadingModel")) else if (Property == TEXT("shadingModel"))
{ {
@@ -83,14 +83,14 @@ public:
EMaterialShadingModel NewModel; EMaterialShadingModel NewModel;
if (!MCPUtils::StringToEnum(ValueStr, NewModel, Result, TEXT("MSM_"))) return; if (!MCPUtils::StringToEnum(ValueStr, NewModel, Result, TEXT("MSM_"))) return;
NewValue = MCPUtils::EnumToString(NewModel, TEXT("MSM_")); NewValue = MCPUtils::EnumToString(NewModel, TEXT("MSM_"));
if (!DryRun) { Mat->PreEditChange(nullptr); Mat->SetShadingModel(NewModel); Mat->PostEditChange(); } if (!DryRun) Mat->SetShadingModel(NewModel);
} }
else if (Property == TEXT("opacity") || Property == TEXT("opacityMaskClipValue")) else if (Property == TEXT("opacity") || Property == TEXT("opacityMaskClipValue"))
{ {
double OpacityValue = Json->GetNumberField(TEXT("value")); double OpacityValue = Json->GetNumberField(TEXT("value"));
OldValue = FString::Printf(TEXT("%g"), Mat->OpacityMaskClipValue); OldValue = FString::Printf(TEXT("%g"), Mat->OpacityMaskClipValue);
NewValue = FString::Printf(TEXT("%g"), OpacityValue); NewValue = FString::Printf(TEXT("%g"), OpacityValue);
if (!DryRun) { Mat->PreEditChange(nullptr); Mat->OpacityMaskClipValue = (float)OpacityValue; Mat->PostEditChange(); } if (!DryRun) Mat->OpacityMaskClipValue = (float)OpacityValue;
} }
else if (Property == TEXT("twoSided")) else if (Property == TEXT("twoSided"))
{ {
@@ -124,9 +124,12 @@ public:
return; return;
} }
// Save if not dry run // Notify and save if not dry run
if (!DryRun) if (!DryRun)
{ {
TArray<UObject*> Chain = { Mat };
MCPUtils::PreEdit(Chain);
MCPUtils::PostEdit(Chain);
if (!MCPUtils::SaveMaterialPackage(Mat)) if (!MCPUtils::SaveMaterialPackage(Mat))
Result.Append(TEXT("WARNING: Package save failed\n")); Result.Append(TEXT("WARNING: Package save failed\n"));
} }

View File

@@ -74,9 +74,8 @@ public:
return; return;
} }
// Update properties // Count and apply property changes
int32 ChangedCount = 0; int32 ChangedCount = 0;
TransNode->PreEditChange(nullptr);
if (Json->HasField(TEXT("crossfadeDuration"))) if (Json->HasField(TEXT("crossfadeDuration")))
{ {
@@ -109,7 +108,10 @@ public:
Result.Append(TEXT("ERROR: No properties to update. Provide at least one of: crossfadeDuration, blendMode, priorityOrder, logicType, bBidirectional\n")); Result.Append(TEXT("ERROR: No properties to update. Provide at least one of: crossfadeDuration, blendMode, priorityOrder, logicType, bBidirectional\n"));
return; return;
} }
TransNode->PostEditChange();
TArray<UObject*> Chain = { TransNode };
MCPUtils::PreEdit(Chain);
MCPUtils::PostEdit(Chain);
// Compile and save // Compile and save
FKismetEditorUtilities::CompileBlueprint(AnimBP); FKismetEditorUtilities::CompileBlueprint(AnimBP);

View File

@@ -1132,7 +1132,7 @@ void MCPUtils::PostEdit(const TArray<UObject*>& Objects)
Obj->MarkPackageDirty(); Obj->MarkPackageDirty();
if (UBlueprint* BP = Cast<UBlueprint>(Obj)) if (UBlueprint* BP = Cast<UBlueprint>(Obj))
FBlueprintEditorUtils::MarkBlueprintAsModified(BP); FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(BP);
} }
} }