More work on handlers
This commit is contained in:
@@ -73,7 +73,7 @@ public:
|
||||
UBlendSpace* BS = Assets.Object();
|
||||
|
||||
// Set axis parameters
|
||||
BS->PreEditChange(nullptr);
|
||||
MCPUtils::PreEdit({BS});
|
||||
|
||||
const FBlendParameter& ParamX = BS->GetBlendParameter(0);
|
||||
const FBlendParameter& ParamY = BS->GetBlendParameter(1);
|
||||
@@ -126,10 +126,9 @@ public:
|
||||
}
|
||||
|
||||
BS->ValidateSampleData();
|
||||
BS->PostEditChange();
|
||||
MCPUtils::PostEdit({BS});
|
||||
|
||||
// Save
|
||||
BS->MarkPackageDirty();
|
||||
bool bSaved = MCPUtils::SaveGenericPackage(BS);
|
||||
|
||||
Result.Appendf(TEXT("Set %d samples on %s\n"), SamplesSet, *MCPUtils::FormatName(BS));
|
||||
|
||||
@@ -70,7 +70,6 @@ public:
|
||||
// Set skeleton.
|
||||
NewBS->SetSkeleton(SkeletonObj);
|
||||
|
||||
// Mark dirty and save.
|
||||
NewBS->MarkPackageDirty();
|
||||
bool bSaved = MCPUtils::SaveGenericPackage(NewBS);
|
||||
|
||||
|
||||
@@ -69,6 +69,8 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
F.PreEdit();
|
||||
|
||||
if (GraphType == TEXT("function"))
|
||||
{
|
||||
UEdGraph* NewGraph = FBlueprintEditorUtils::CreateNewGraph(BP, FName(*Graph),
|
||||
@@ -114,7 +116,7 @@ public:
|
||||
Result.Appendf(TEXT("Created custom event: %s\n"), *MCPUtils::FormatName(NewEvent));
|
||||
}
|
||||
|
||||
FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(BP);
|
||||
F.PostEdit();
|
||||
MCPUtils::SaveBlueprintPackage(BP);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -85,8 +85,9 @@ public:
|
||||
|
||||
// Remove the graph
|
||||
FString GraphName = MCPUtils::FormatName(TargetGraph);
|
||||
F.PreEdit();
|
||||
FBlueprintEditorUtils::RemoveGraph(BP, TargetGraph, EGraphRemoveFlags::Default);
|
||||
FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(BP);
|
||||
F.PostEdit();
|
||||
bool bSaved = MCPUtils::SaveBlueprintPackage(BP);
|
||||
|
||||
Result.Appendf(TEXT("Deleted %s graph %s\n"), *GraphType, *GraphName);
|
||||
|
||||
@@ -73,8 +73,9 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
F.PreEdit();
|
||||
FBlueprintEditorUtils::RenameGraph(TargetGraph, NewName);
|
||||
FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(BP);
|
||||
F.PostEdit();
|
||||
MCPUtils::SaveBlueprintPackage(BP);
|
||||
|
||||
Result.Appendf(TEXT("Renamed to %s %s\n"),
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
#include "Engine/SimpleConstructionScript.h"
|
||||
#include "Engine/SCS_Node.h"
|
||||
#include "Components/ActorComponent.h"
|
||||
#include "Kismet2/BlueprintEditorUtils.h"
|
||||
#include "Blueprint_AddComponent.generated.h"
|
||||
|
||||
|
||||
@@ -107,6 +106,7 @@ public:
|
||||
}
|
||||
|
||||
// Create the SCS node
|
||||
MCPUtils::PreEdit({BP});
|
||||
USCS_Node* NewNode = SCS->CreateNode(ComponentClassObj, FName(*Component));
|
||||
if (!NewNode)
|
||||
{
|
||||
@@ -126,7 +126,7 @@ public:
|
||||
SCS->AddNode(NewNode);
|
||||
}
|
||||
|
||||
FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(BP);
|
||||
MCPUtils::PostEdit({BP});
|
||||
bool bSaved = MCPUtils::SaveBlueprintPackage(BP);
|
||||
|
||||
Result.Appendf(TEXT("Added component %s (%s)"),
|
||||
|
||||
@@ -75,6 +75,7 @@ public:
|
||||
}
|
||||
|
||||
// Add a member variable with PC_MCDelegate pin type
|
||||
F.PreEdit();
|
||||
FEdGraphPinType DelegateType;
|
||||
DelegateType.PinCategory = UEdGraphSchema_K2::PC_MCDelegate;
|
||||
if (!FBlueprintEditorUtils::AddMemberVariable(BP, DispatcherFName, DelegateType))
|
||||
@@ -115,7 +116,7 @@ public:
|
||||
|
||||
if (!EntryNode)
|
||||
{
|
||||
FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(BP);
|
||||
F.PostEdit();
|
||||
MCPUtils::SaveBlueprintPackage(BP);
|
||||
Result.Append(TEXT("Error: Event dispatcher created but entry node not found — parameters could not be added.\n"));
|
||||
return;
|
||||
@@ -136,7 +137,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(BP);
|
||||
F.PostEdit();
|
||||
MCPUtils::SaveBlueprintPackage(BP);
|
||||
|
||||
Result.Appendf(TEXT("Created event dispatcher '%s'"), *DispatcherName);
|
||||
|
||||
@@ -133,9 +133,9 @@ public:
|
||||
}
|
||||
|
||||
// Add the parameter pin (EGPD_Output on entry = input to callers)
|
||||
MCPUtils::PreEdit({BP});
|
||||
EntryNode->CreateUserDefinedPin(FName(*ParamName), PinType, EGPD_Output);
|
||||
|
||||
FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(BP);
|
||||
MCPUtils::PostEdit({BP});
|
||||
bool bSaved = MCPUtils::SaveBlueprintPackage(BP);
|
||||
|
||||
Result.Appendf(TEXT("Added %s parameter '%s' to %s '%s'%s\n"),
|
||||
|
||||
@@ -55,6 +55,7 @@ public:
|
||||
}
|
||||
|
||||
FTopLevelAssetPath InterfacePath = InterfaceClass->GetClassPathName();
|
||||
MCPUtils::PreEdit({BP});
|
||||
bool bAdded = FBlueprintEditorUtils::ImplementNewInterface(BP, InterfacePath);
|
||||
if (!bAdded)
|
||||
{
|
||||
@@ -65,7 +66,7 @@ public:
|
||||
}
|
||||
|
||||
// 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("Function stubs:\n"));
|
||||
|
||||
@@ -69,6 +69,7 @@ public:
|
||||
PinType.ContainerType = EPinContainerType::Array;
|
||||
|
||||
// Add the variable
|
||||
MCPUtils::PreEdit({BP});
|
||||
if (!FBlueprintEditorUtils::AddMemberVariable(BP, VarFName, PinType, DefaultValue))
|
||||
{
|
||||
MCPErrorCallback(Result).SetError(FString::Printf(
|
||||
@@ -79,7 +80,7 @@ public:
|
||||
if (!Category.IsEmpty())
|
||||
FBlueprintEditorUtils::SetBlueprintVariableCategory(BP, VarFName, nullptr, FText::FromString(Category));
|
||||
|
||||
FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(BP);
|
||||
MCPUtils::PostEdit({BP});
|
||||
bool bSaved = MCPUtils::SaveBlueprintPackage(BP);
|
||||
|
||||
Result.Appendf(TEXT("Added %s %s to %s\n"),
|
||||
|
||||
@@ -135,7 +135,8 @@ public:
|
||||
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);
|
||||
(*FoundPinInfo)->PinType = NewPinType;
|
||||
EntryNode->PostEditChange();
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#include "EdGraph/EdGraphPin.h"
|
||||
#include "K2Node_VariableGet.h"
|
||||
#include "K2Node_VariableSet.h"
|
||||
#include "Kismet2/BlueprintEditorUtils.h"
|
||||
#include "Blueprint_ChangeVariableType.generated.h"
|
||||
|
||||
|
||||
@@ -129,9 +128,9 @@ public:
|
||||
}
|
||||
|
||||
// Apply the type change
|
||||
BP->PreEditChange(nullptr);
|
||||
F.PreEdit();
|
||||
Found->VarType = NewPinType;
|
||||
BP->PostEditChange();
|
||||
F.PostEdit();
|
||||
|
||||
bool bSaved = MCPUtils::SaveBlueprintPackage(BP);
|
||||
Result.Appendf(TEXT("Changed %s to %s.%s\n"),
|
||||
|
||||
@@ -42,6 +42,7 @@ public:
|
||||
int32 NodeCount = MCPUtils::AllNodes(BP).Num();
|
||||
|
||||
// Refresh all nodes
|
||||
MCPUtils::PreEdit({BP});
|
||||
FBlueprintEditorUtils::RefreshAllNodes(BP);
|
||||
|
||||
// Remove orphaned pins from all nodes
|
||||
@@ -61,7 +62,7 @@ public:
|
||||
}
|
||||
|
||||
// Mark as modified and recompile after orphan removal
|
||||
FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(BP);
|
||||
MCPUtils::PostEdit({BP});
|
||||
|
||||
// Summary
|
||||
Result.Appendf(TEXT("Refreshed %s: %d graphs, %d nodes"), *MCPUtils::FormatName(BP), GraphCount, NodeCount);
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
#include "Engine/Blueprint.h"
|
||||
#include "Engine/SimpleConstructionScript.h"
|
||||
#include "Engine/SCS_Node.h"
|
||||
#include "Kismet2/BlueprintEditorUtils.h"
|
||||
#include "Blueprint_RemoveComponent.generated.h"
|
||||
|
||||
|
||||
@@ -84,9 +83,10 @@ public:
|
||||
FString RemovedName = MCPUtils::FormatName(NodeToRemove->ComponentTemplate);
|
||||
|
||||
// Remove the node (promotes children to parent if it has any — but we've guarded root above)
|
||||
F.PreEdit();
|
||||
SCS->RemoveNodeAndPromoteChildren(NodeToRemove);
|
||||
F.PostEdit();
|
||||
|
||||
FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(BP);
|
||||
bool bSaved = MCPUtils::SaveBlueprintPackage(BP);
|
||||
|
||||
Result.Appendf(TEXT("Removed component %s.%s\n"),
|
||||
|
||||
@@ -65,8 +65,9 @@ public:
|
||||
}
|
||||
|
||||
FTopLevelAssetPath InterfacePath = FoundInterface->GetClassPathName();
|
||||
MCPUtils::PreEdit({BP});
|
||||
FBlueprintEditorUtils::RemoveInterface(BP, InterfacePath, PreserveFunctions);
|
||||
FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(BP);
|
||||
MCPUtils::PostEdit({BP});
|
||||
|
||||
Result.Appendf(TEXT("Removed interface %s\n"), *MCPUtils::FormatName(FoundInterface));
|
||||
if (PreserveFunctions)
|
||||
|
||||
@@ -62,8 +62,9 @@ public:
|
||||
FName VarFName = Found->VarName;
|
||||
|
||||
// RemoveMemberVariable also cleans up Get/Set nodes
|
||||
F.PreEdit();
|
||||
FBlueprintEditorUtils::RemoveMemberVariable(BP, VarFName);
|
||||
FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(BP);
|
||||
F.PostEdit();
|
||||
|
||||
bool bSaved = MCPUtils::SaveBlueprintPackage(BP);
|
||||
Result.Appendf(TEXT("Removed variable %s from %s.%s\n"),
|
||||
|
||||
@@ -61,9 +61,9 @@ public:
|
||||
}
|
||||
|
||||
// Perform reparent
|
||||
BP->PreEditChange(nullptr);
|
||||
MCPUtils::PreEdit({BP});
|
||||
BP->ParentClass = NewParentClassObj;
|
||||
BP->PostEditChange();
|
||||
MCPUtils::PostEdit({BP});
|
||||
FBlueprintEditorUtils::RefreshAllNodes(BP);
|
||||
FKismetEditorUtilities::CompileBlueprint(BP);
|
||||
bool bSaved = MCPUtils::SaveBlueprintPackage(BP);
|
||||
|
||||
@@ -1,191 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "MCPHandler.h"
|
||||
#include "MCPFetcher.h"
|
||||
#include "MCPUtils.h"
|
||||
#include "Engine/Blueprint.h"
|
||||
#include "Kismet2/BlueprintEditorUtils.h"
|
||||
#include "Blueprint_SetVariableMetadata.generated.h"
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// ---------------------------------------------------------------------------
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
UCLASS()
|
||||
class UMCP_Blueprint_SetVariableMetadata : public UObject, public IMCPHandler
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
UPROPERTY(meta=(Description="Blueprint name or package path"))
|
||||
FString Blueprint;
|
||||
|
||||
UPROPERTY(meta=(Description="Name of the variable to modify"))
|
||||
FString Variable;
|
||||
|
||||
UPROPERTY(meta=(Optional, Description="Category to assign the variable to"))
|
||||
FString Category;
|
||||
|
||||
UPROPERTY(meta=(Optional, Description="Tooltip text for the variable"))
|
||||
FString Tooltip;
|
||||
|
||||
UPROPERTY(meta=(Optional, Description="Replication mode: none, replicated, or repNotify"))
|
||||
FString Replication;
|
||||
|
||||
UPROPERTY(meta=(Optional, Description="If true, expose this variable on spawn"))
|
||||
bool ExposeOnSpawn = false;
|
||||
|
||||
UPROPERTY(meta=(Optional, Description="If true, mark the variable as private"))
|
||||
bool IsPrivate = false;
|
||||
|
||||
UPROPERTY(meta=(Optional, Description="Editability mode: editAnywhere, editDefaultsOnly, editInstanceOnly, or none"))
|
||||
FString Editability;
|
||||
|
||||
virtual FString GetDescription() const override
|
||||
{
|
||||
return TEXT("Set variable metadata properties such as category, tooltip, "
|
||||
"replication, editability, and visibility flags.");
|
||||
}
|
||||
|
||||
virtual void Handle(const FJsonObject* Json, FStringBuilderBase& Result) override
|
||||
{
|
||||
MCPFetcher F(Result);
|
||||
UBlueprint* BP = F.Walk(Blueprint).Cast<UBlueprint>();
|
||||
if (!BP) return;
|
||||
|
||||
// Find the variable using Identifies for consistent name matching
|
||||
FBPVariableDescription* VarDesc = nullptr;
|
||||
for (FBPVariableDescription& Var : BP->NewVariables)
|
||||
{
|
||||
if (MCPUtils::FormatName(Var) == Variable ||
|
||||
Var.VarName.ToString().Equals(Variable, ESearchCase::IgnoreCase))
|
||||
{
|
||||
VarDesc = &Var;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!VarDesc)
|
||||
{
|
||||
Result.Appendf(TEXT("ERROR: Variable '%s' not found in %s.\nAvailable variables:\n"),
|
||||
*Variable, *MCPUtils::FormatName(BP));
|
||||
for (const FBPVariableDescription& Var : BP->NewVariables)
|
||||
{
|
||||
Result.Appendf(TEXT(" %s\n"), *MCPUtils::FormatName(Var));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
FName VarFName = VarDesc->VarName;
|
||||
int32 ChangeCount = 0;
|
||||
|
||||
// Category
|
||||
if (Json->HasField(TEXT("category")))
|
||||
{
|
||||
VarDesc->Category = FText::FromString(Category);
|
||||
FBlueprintEditorUtils::SetBlueprintVariableCategory(BP, VarFName, nullptr, FText::FromString(Category));
|
||||
Result.Appendf(TEXT("Set category to '%s'.\n"), *Category);
|
||||
ChangeCount++;
|
||||
}
|
||||
|
||||
// Tooltip
|
||||
if (Json->HasField(TEXT("tooltip")))
|
||||
{
|
||||
FBlueprintEditorUtils::SetBlueprintVariableMetaData(BP, VarFName, nullptr, TEXT("tooltip"), Tooltip);
|
||||
Result.Appendf(TEXT("Set tooltip to '%s'.\n"), *Tooltip);
|
||||
ChangeCount++;
|
||||
}
|
||||
|
||||
// Replication
|
||||
if (Json->HasField(TEXT("replication")))
|
||||
{
|
||||
if (Replication == TEXT("none"))
|
||||
{
|
||||
VarDesc->PropertyFlags &= ~CPF_Net;
|
||||
VarDesc->PropertyFlags &= ~CPF_RepNotify;
|
||||
VarDesc->RepNotifyFunc = NAME_None;
|
||||
}
|
||||
else if (Replication == TEXT("replicated"))
|
||||
{
|
||||
VarDesc->PropertyFlags |= CPF_Net;
|
||||
VarDesc->PropertyFlags &= ~CPF_RepNotify;
|
||||
VarDesc->RepNotifyFunc = NAME_None;
|
||||
}
|
||||
else if (Replication == TEXT("repNotify"))
|
||||
{
|
||||
VarDesc->PropertyFlags |= CPF_Net | CPF_RepNotify;
|
||||
VarDesc->RepNotifyFunc = FName(*FString::Printf(TEXT("OnRep_%s"), *Variable));
|
||||
}
|
||||
else
|
||||
{
|
||||
Result.Appendf(TEXT("ERROR: Invalid replication value '%s'. Valid: none, replicated, repNotify\n"), *Replication);
|
||||
return;
|
||||
}
|
||||
Result.Appendf(TEXT("Set replication to '%s'.\n"), *Replication);
|
||||
ChangeCount++;
|
||||
}
|
||||
|
||||
// ExposeOnSpawn
|
||||
if (Json->HasField(TEXT("exposeOnSpawn")))
|
||||
{
|
||||
if (ExposeOnSpawn)
|
||||
VarDesc->PropertyFlags |= CPF_ExposeOnSpawn;
|
||||
else
|
||||
VarDesc->PropertyFlags &= ~CPF_ExposeOnSpawn;
|
||||
Result.Appendf(TEXT("Set exposeOnSpawn to %s.\n"), ExposeOnSpawn ? TEXT("true") : TEXT("false"));
|
||||
ChangeCount++;
|
||||
}
|
||||
|
||||
// isPrivate
|
||||
if (Json->HasField(TEXT("isPrivate")))
|
||||
{
|
||||
FBlueprintEditorUtils::SetBlueprintVariableMetaData(BP, VarFName, nullptr,
|
||||
TEXT("BlueprintPrivate"), IsPrivate ? TEXT("true") : TEXT("false"));
|
||||
Result.Appendf(TEXT("Set isPrivate to %s.\n"), IsPrivate ? TEXT("true") : TEXT("false"));
|
||||
ChangeCount++;
|
||||
}
|
||||
|
||||
// Editability
|
||||
if (Json->HasField(TEXT("editability")))
|
||||
{
|
||||
VarDesc->PropertyFlags &= ~(CPF_Edit | CPF_DisableEditOnInstance | CPF_DisableEditOnTemplate);
|
||||
|
||||
if (Editability == TEXT("editAnywhere"))
|
||||
{
|
||||
VarDesc->PropertyFlags |= CPF_Edit;
|
||||
}
|
||||
else if (Editability == TEXT("editDefaultsOnly"))
|
||||
{
|
||||
VarDesc->PropertyFlags |= CPF_Edit | CPF_DisableEditOnInstance;
|
||||
}
|
||||
else if (Editability == TEXT("editInstanceOnly"))
|
||||
{
|
||||
VarDesc->PropertyFlags |= CPF_Edit | CPF_DisableEditOnTemplate;
|
||||
}
|
||||
else if (Editability != TEXT("none"))
|
||||
{
|
||||
Result.Appendf(TEXT("ERROR: Invalid editability value '%s'. Valid: editAnywhere, editDefaultsOnly, editInstanceOnly, none\n"), *Editability);
|
||||
return;
|
||||
}
|
||||
Result.Appendf(TEXT("Set editability to '%s'.\n"), *Editability);
|
||||
ChangeCount++;
|
||||
}
|
||||
|
||||
if (ChangeCount == 0)
|
||||
{
|
||||
Result.Append(TEXT("ERROR: No metadata fields specified. Provide at least one of: category, tooltip, replication, exposeOnSpawn, isPrivate, editability\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
BP->PreEditChange(nullptr);
|
||||
BP->PostEditChange();
|
||||
FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(BP);
|
||||
bool bSaved = MCPUtils::SaveBlueprintPackage(BP);
|
||||
|
||||
Result.Appendf(TEXT("Updated %d field(s) on %s in %s.%s\n"),
|
||||
ChangeCount, *VarFName.ToString(), *MCPUtils::FormatName(BP),
|
||||
bSaved ? TEXT("") : TEXT(" WARNING: save failed."));
|
||||
}
|
||||
};
|
||||
@@ -4,11 +4,9 @@
|
||||
#include "MCPHandler.h"
|
||||
#include "MCPFetcher.h"
|
||||
#include "MCPUtils.h"
|
||||
#include "Engine/Blueprint.h"
|
||||
#include "EdGraph/EdGraph.h"
|
||||
#include "EdGraph/EdGraphNode.h"
|
||||
#include "EdGraph/EdGraphSchema.h"
|
||||
#include "Kismet2/BlueprintEditorUtils.h"
|
||||
#include "GraphNode_Create.generated.h"
|
||||
|
||||
|
||||
@@ -57,6 +55,7 @@ public:
|
||||
UEdGraph* TargetGraph = F.Walk(Graph).Cast<UEdGraph>();
|
||||
if (!TargetGraph) return;
|
||||
|
||||
F.PreEdit();
|
||||
int32 SuccessCount = 0;
|
||||
int32 TotalCount = Nodes.Array.Num();
|
||||
|
||||
@@ -98,16 +97,7 @@ public:
|
||||
SuccessCount++;
|
||||
}
|
||||
|
||||
// Mark the owning asset as modified
|
||||
UBlueprint* BP = Cast<UBlueprint>(TargetGraph->GetOuter());
|
||||
if (BP)
|
||||
FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(BP);
|
||||
|
||||
TargetGraph->NotifyGraphChanged();
|
||||
|
||||
UObject* Outer = TargetGraph->GetOuter();
|
||||
if (Outer)
|
||||
Outer->MarkPackageDirty();
|
||||
F.PostEdit();
|
||||
|
||||
Result.Appendf(TEXT("Spawned %d/%d nodes.\n"), SuccessCount, TotalCount);
|
||||
}
|
||||
|
||||
@@ -5,10 +5,6 @@
|
||||
#include "MCPFetcher.h"
|
||||
#include "MCPUtils.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"
|
||||
|
||||
|
||||
@@ -27,8 +23,8 @@ public:
|
||||
|
||||
virtual FString GetDescription() const override
|
||||
{
|
||||
return TEXT("Delete a node from a Blueprint graph. "
|
||||
"Cannot delete entry nodes (FunctionEntry, Event, CustomEvent).");
|
||||
return TEXT("Delete a node from a graph. "
|
||||
"Cannot delete undeletable nodes (entry points, root nodes, etc).");
|
||||
}
|
||||
|
||||
virtual void Handle(const FJsonObject* Json, FStringBuilderBase& Result) override
|
||||
@@ -38,42 +34,21 @@ public:
|
||||
if (!FoundNode) return;
|
||||
|
||||
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 GraphName = MCPUtils::FormatName(Graph);
|
||||
|
||||
if (Cast<UK2Node_FunctionEntry>(FoundNode))
|
||||
if (!FoundNode->CanUserDeleteNode())
|
||||
{
|
||||
MCPErrorCallback Error(Result);
|
||||
return Error.SetError(FString::Printf(
|
||||
TEXT("Cannot delete FunctionEntry node '%s' in graph '%s'. ")
|
||||
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."),
|
||||
TEXT("Cannot delete node '%s' in graph '%s' — it is not deletable."),
|
||||
*NodeTitle, *GraphName));
|
||||
}
|
||||
|
||||
F.PreEdit();
|
||||
FoundNode->BreakAllNodeLinks();
|
||||
Graph->RemoveNode(FoundNode);
|
||||
|
||||
FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(BP);
|
||||
F.PostEdit();
|
||||
|
||||
Result.Appendf(TEXT("Deleted node '%s' from graph '%s'.\n"), *NodeTitle, *GraphName);
|
||||
}
|
||||
|
||||
@@ -4,11 +4,9 @@
|
||||
#include "MCPHandler.h"
|
||||
#include "MCPFetcher.h"
|
||||
#include "MCPUtils.h"
|
||||
#include "Engine/Blueprint.h"
|
||||
#include "EdGraph/EdGraph.h"
|
||||
#include "EdGraph/EdGraphNode.h"
|
||||
#include "EdGraph/EdGraphPin.h"
|
||||
#include "Kismet2/BlueprintEditorUtils.h"
|
||||
#include "GraphNode_Duplicate.generated.h"
|
||||
|
||||
|
||||
@@ -77,6 +75,7 @@ public:
|
||||
|
||||
if (SourceNodes.Num() == 0) return;
|
||||
|
||||
F.PreEdit();
|
||||
// Duplicate each node
|
||||
for (UEdGraphNode* SourceNode : SourceNodes)
|
||||
{
|
||||
@@ -101,8 +100,6 @@ public:
|
||||
Result.Appendf(TEXT("Duplicated: %s -> %s\n"), *MCPUtils::FormatName(SourceNode), *MCPUtils::FormatName(NewNode));
|
||||
}
|
||||
|
||||
UBlueprint* BP = Cast<UBlueprint>(TargetGraph->GetOuter());
|
||||
if (BP)
|
||||
FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(BP);
|
||||
F.PostEdit();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#include "MCPFetcher.h"
|
||||
#include "MCPUtils.h"
|
||||
#include "EdGraph/EdGraphNode.h"
|
||||
#include "Kismet2/BlueprintEditorUtils.h"
|
||||
#include "GraphNode_SetComment.generated.h"
|
||||
|
||||
|
||||
@@ -36,6 +35,8 @@ public:
|
||||
UEdGraphNode* FoundNode = F.Walk(Node).Cast<UEdGraphNode>();
|
||||
if (!FoundNode) return;
|
||||
|
||||
F.PreEdit();
|
||||
|
||||
FoundNode->NodeComment = Comment;
|
||||
|
||||
// Make the comment bubble visible if setting a non-empty comment
|
||||
@@ -45,8 +46,7 @@ public:
|
||||
FoundNode->bCommentBubblePinned = true;
|
||||
}
|
||||
|
||||
UBlueprint* BP = FBlueprintEditorUtils::FindBlueprintForNodeChecked(FoundNode);
|
||||
FBlueprintEditorUtils::MarkBlueprintAsModified(BP);
|
||||
F.PostEdit();
|
||||
|
||||
Result.Appendf(TEXT("Comment set on %s\n"), *MCPUtils::FormatName(FoundNode));
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
#include "MCPUtils.h"
|
||||
#include "Engine/Blueprint.h"
|
||||
#include "EdGraph/EdGraphNode.h"
|
||||
#include "Kismet2/BlueprintEditorUtils.h"
|
||||
#include "GraphNode_SetPositions.generated.h"
|
||||
|
||||
|
||||
@@ -53,6 +52,8 @@ public:
|
||||
UBlueprint* BP = F.Walk(Blueprint).Cast<UBlueprint>();
|
||||
if (!BP) return;
|
||||
|
||||
F.PreEdit();
|
||||
|
||||
int32 SuccessCount = 0;
|
||||
|
||||
for (const TSharedPtr<FJsonValue>& NodeVal : Nodes.Array)
|
||||
@@ -70,7 +71,7 @@ public:
|
||||
SuccessCount++;
|
||||
}
|
||||
|
||||
FBlueprintEditorUtils::MarkBlueprintAsModified(BP);
|
||||
F.PostEdit();
|
||||
Result.Appendf(TEXT("Moved %d/%d nodes.\n"), SuccessCount, Nodes.Array.Num());
|
||||
}
|
||||
};
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#include "MCPFetcher.h"
|
||||
#include "MCPUtils.h"
|
||||
#include "EdGraph/EdGraphPin.h"
|
||||
#include "Kismet2/BlueprintEditorUtils.h"
|
||||
#include "GraphPin_Connect.generated.h"
|
||||
|
||||
|
||||
@@ -49,6 +48,8 @@ public:
|
||||
UBlueprint* BP = F.Walk(Blueprint).Cast<UBlueprint>();
|
||||
if (!BP) return;
|
||||
|
||||
F.PreEdit();
|
||||
|
||||
int32 SuccessCount = 0;
|
||||
int32 TotalCount = Connections.Array.Num();
|
||||
|
||||
@@ -81,10 +82,7 @@ public:
|
||||
SuccessCount++;
|
||||
}
|
||||
|
||||
if (SuccessCount > 0)
|
||||
{
|
||||
FBlueprintEditorUtils::MarkBlueprintAsModified(BP);
|
||||
}
|
||||
F.PostEdit();
|
||||
|
||||
Result.Appendf(TEXT("Connected %d/%d pins.\n"), SuccessCount, TotalCount);
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#include "MCPFetcher.h"
|
||||
#include "MCPUtils.h"
|
||||
#include "EdGraph/EdGraphPin.h"
|
||||
#include "Kismet2/BlueprintEditorUtils.h"
|
||||
#include "GraphPin_Disconnect.generated.h"
|
||||
|
||||
|
||||
@@ -50,6 +49,8 @@ public:
|
||||
UBlueprint* BP = F.Walk(Blueprint).Cast<UBlueprint>();
|
||||
if (!BP) return;
|
||||
|
||||
F.PreEdit();
|
||||
|
||||
int32 SuccessCount = 0;
|
||||
int32 TotalDisconnected = 0;
|
||||
|
||||
@@ -97,10 +98,7 @@ public:
|
||||
TotalDisconnected += DisconnectedCount;
|
||||
}
|
||||
|
||||
if (TotalDisconnected > 0)
|
||||
{
|
||||
FBlueprintEditorUtils::MarkBlueprintAsModified(BP);
|
||||
}
|
||||
F.PostEdit();
|
||||
|
||||
Result.Appendf(TEXT("Done: %d/%d succeeded, %d links broken.\n"),
|
||||
SuccessCount, Disconnections.Array.Num(), TotalDisconnected);
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#include "MCPFetcher.h"
|
||||
#include "MCPUtils.h"
|
||||
#include "EdGraph/EdGraphPin.h"
|
||||
#include "Kismet2/BlueprintEditorUtils.h"
|
||||
#include "GraphPin_SetDefault.generated.h"
|
||||
|
||||
|
||||
|
||||
@@ -91,9 +91,10 @@ public:
|
||||
}
|
||||
|
||||
// Set parent.
|
||||
MI->PreEditChange(nullptr);
|
||||
TArray<UObject*> Chain = { MI };
|
||||
MCPUtils::PreEdit(Chain);
|
||||
MI->Parent = ParentMaterialObj;
|
||||
MI->PostEditChange();
|
||||
MCPUtils::PostEdit(Chain);
|
||||
|
||||
// Save.
|
||||
bool bSaved = MCPUtils::SaveGenericPackage(MI);
|
||||
|
||||
@@ -34,9 +34,10 @@ public:
|
||||
if (!Assets.Exact(Material).Errors(Result).ENone().ETwo().Load()) return;
|
||||
UMaterial* MaterialObj = Assets.Object();
|
||||
|
||||
// Force recompile by triggering PreEditChange/PostEditChange
|
||||
MaterialObj->PreEditChange(nullptr);
|
||||
MaterialObj->PostEditChange();
|
||||
// Force recompile by triggering PreEdit/PostEdit
|
||||
TArray<UObject*> Chain = { MaterialObj };
|
||||
MCPUtils::PreEdit(Chain);
|
||||
MCPUtils::PostEdit(Chain);
|
||||
|
||||
// Check for compilation errors via FMaterialResource on current platform
|
||||
TArray<FString> Errors;
|
||||
|
||||
@@ -84,7 +84,8 @@ public:
|
||||
// Apply optional properties.
|
||||
bool bHasTwoSided = Json->HasField(TEXT("twoSided"));
|
||||
|
||||
MaterialObj->PreEditChange(nullptr);
|
||||
TArray<UObject*> Chain = { MaterialObj };
|
||||
MCPUtils::PreEdit(Chain);
|
||||
|
||||
if (!Domain.IsEmpty())
|
||||
MaterialObj->MaterialDomain = ParsedDomain;
|
||||
@@ -95,7 +96,7 @@ public:
|
||||
if (bHasTwoSided)
|
||||
MaterialObj->TwoSided = TwoSided;
|
||||
|
||||
MaterialObj->PostEditChange();
|
||||
MCPUtils::PostEdit(Chain);
|
||||
|
||||
bool bSaved = MCPUtils::SaveMaterialPackage(MaterialObj);
|
||||
|
||||
|
||||
@@ -74,9 +74,9 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
MI->PreEditChange(nullptr);
|
||||
MCPUtils::PreEdit({MI});
|
||||
MI->Parent = NewParentObj;
|
||||
MI->PostEditChange();
|
||||
MCPUtils::PostEdit({MI});
|
||||
MCPUtils::SaveGenericPackage(MI);
|
||||
|
||||
Result.Appendf(TEXT("Reparented %s: %s -> %s\n"),
|
||||
|
||||
@@ -159,9 +159,8 @@ public:
|
||||
|
||||
if (!DryRun)
|
||||
{
|
||||
MI->PreEditChange(nullptr);
|
||||
MI->PostEditChange();
|
||||
MI->MarkPackageDirty();
|
||||
MCPUtils::PreEdit({MI});
|
||||
MCPUtils::PostEdit({MI});
|
||||
MCPUtils::SaveGenericPackage(MI);
|
||||
}
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ public:
|
||||
bool bValue = Json->GetBoolField(TEXT("value"));
|
||||
OldValue = Getter() ? 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"))
|
||||
@@ -65,7 +65,7 @@ public:
|
||||
EMaterialDomain NewDomain;
|
||||
if (!MCPUtils::StringToEnum(ValueStr, NewDomain, Result, TEXT("MD_"))) return;
|
||||
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"))
|
||||
{
|
||||
@@ -74,7 +74,7 @@ public:
|
||||
EBlendMode NewBlend;
|
||||
if (!MCPUtils::StringToEnum(ValueStr, NewBlend, Result, TEXT("BLEND_"))) return;
|
||||
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"))
|
||||
{
|
||||
@@ -83,14 +83,14 @@ public:
|
||||
EMaterialShadingModel NewModel;
|
||||
if (!MCPUtils::StringToEnum(ValueStr, NewModel, Result, TEXT("MSM_"))) return;
|
||||
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"))
|
||||
{
|
||||
double OpacityValue = Json->GetNumberField(TEXT("value"));
|
||||
OldValue = FString::Printf(TEXT("%g"), Mat->OpacityMaskClipValue);
|
||||
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"))
|
||||
{
|
||||
@@ -124,9 +124,12 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
// Save if not dry run
|
||||
// Notify and save if not dry run
|
||||
if (!DryRun)
|
||||
{
|
||||
TArray<UObject*> Chain = { Mat };
|
||||
MCPUtils::PreEdit(Chain);
|
||||
MCPUtils::PostEdit(Chain);
|
||||
if (!MCPUtils::SaveMaterialPackage(Mat))
|
||||
Result.Append(TEXT("WARNING: Package save failed\n"));
|
||||
}
|
||||
|
||||
@@ -74,9 +74,8 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
// Update properties
|
||||
// Count and apply property changes
|
||||
int32 ChangedCount = 0;
|
||||
TransNode->PreEditChange(nullptr);
|
||||
|
||||
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"));
|
||||
return;
|
||||
}
|
||||
TransNode->PostEditChange();
|
||||
|
||||
TArray<UObject*> Chain = { TransNode };
|
||||
MCPUtils::PreEdit(Chain);
|
||||
MCPUtils::PostEdit(Chain);
|
||||
|
||||
// Compile and save
|
||||
FKismetEditorUtilities::CompileBlueprint(AnimBP);
|
||||
|
||||
@@ -1132,7 +1132,7 @@ void MCPUtils::PostEdit(const TArray<UObject*>& Objects)
|
||||
Obj->MarkPackageDirty();
|
||||
|
||||
if (UBlueprint* BP = Cast<UBlueprint>(Obj))
|
||||
FBlueprintEditorUtils::MarkBlueprintAsModified(BP);
|
||||
FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(BP);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user