More refactoring in MCP

This commit is contained in:
2026-03-20 19:40:29 -04:00
parent ca6b3f9768
commit 90b35f785e
17 changed files with 166 additions and 184 deletions

View File

@@ -1,46 +1,29 @@
#include "WingBlueprintVar.h"
#include "WingFunctionArgs.h"
#include "WingJson.h"
#include "WingServer.h"
#include "WingTypes.h"
#include "WingUtils.h"
#include "EdGraphSchema_K2.h"
#include "K2Node_EditablePinBase.h"
#include "Kismet2/BlueprintEditorUtils.h"
FWingBlueprintVar::FWingBlueprintVar(UBlueprint* BP, const FString& VarName)
{
Desc = WingUtils::FindExactlyOneNamed(VarName, BP->NewVariables);
Desc = WingUtils::FindExactlyOneNamed(VarName, BP->NewVariables, TEXT("Variable"));
if (!Desc) return;
if (Desc->VarType.PinCategory == UEdGraphSchema_K2::PC_MCDelegate)
{
// Find the matching signature graph by name.
for (UEdGraph* Graph : BP->DelegateSignatureGraphs)
{
if (Graph->GetFName() == Desc->VarName)
{
SigGraph = Graph;
break;
}
}
if (!SigGraph)
{
UWingServer::Printf(TEXT("ERROR: Signature graph not found for event dispatcher '%s'\n"), *VarName);
Desc = nullptr;
return;
}
UWingServer::Printf(TEXT("Cannot edit event dispatchers using BlueprintVariable functions.\n"));
Desc = nullptr;
return;
}
else
// Try to find the default value property on the CDO.
if (BP->GeneratedClass)
{
// Try to find the default value property on the CDO.
if (BP->GeneratedClass)
{
UObject* CDO = BP->GeneratedClass->GetDefaultObject();
FProperty* Prop = BP->GeneratedClass->FindPropertyByName(Desc->VarName);
if (CDO && Prop)
DefaultValueProp = FWingProperty(Prop, CDO);
}
UObject* CDO = BP->GeneratedClass->GetDefaultObject();
FProperty* Prop = BP->GeneratedClass->FindPropertyByName(Desc->VarName);
if (CDO && Prop)
DefaultValueProp = FWingProperty(Prop, CDO);
}
}
@@ -48,7 +31,6 @@ void FWingBlueprintVar::Dump()
{
LoadFlags();
LoadDefault();
LoadDelegateArgs();
TArray<FWingProperty> Props = MergedProperties();
for (FWingProperty& P : Props)
{
@@ -62,7 +44,6 @@ void FWingBlueprintVar::Dump()
bool FWingBlueprintVar::ApplyJson(const FJsonObject* Json)
{
bool bHasDefault = Json->HasField(TEXT("DefaultValue"));
bool bHasDelegateArgs = Json->HasField(TEXT("DelegateArgs"));
bool bHasType = Json->HasField(TEXT("VarType"));
if (bHasDefault && bHasType)
{
@@ -74,7 +55,6 @@ bool FWingBlueprintVar::ApplyJson(const FJsonObject* Json)
}
LoadFlags();
LoadDelegateArgs();
TArray<FWingProperty> Props = MergedProperties();
if (!WingJson::PopulateFromJson(Props, Json, true))
@@ -82,9 +62,7 @@ bool FWingBlueprintVar::ApplyJson(const FJsonObject* Json)
SaveFlags();
if (bHasDefault)
if (!SaveDefault()) return false;
if (bHasDelegateArgs)
if (!SaveDelegateArgs()) return false;
return SaveDefault();
return true;
}
@@ -110,18 +88,6 @@ void FWingBlueprintVar::LoadDefault()
DefaultValue.Empty();
}
void FWingBlueprintVar::LoadDelegateArgs()
{
if (!SigGraph) return;
TWeakObjectPtr<UK2Node_EditablePinBase> EntryNode;
TWeakObjectPtr<UK2Node_EditablePinBase> ResultNode;
FBlueprintEditorUtils::GetEntryAndResultNodes(SigGraph, EntryNode, ResultNode);
if (EntryNode.IsValid())
DelegateArgs = WingFunctionArgs::GetArgs(EntryNode.Get());
else
DelegateArgs.Empty();
}
void FWingBlueprintVar::SaveFlags()
{
// CPF flags
@@ -165,20 +131,6 @@ bool FWingBlueprintVar::SaveDefault()
return true;
}
bool FWingBlueprintVar::SaveDelegateArgs()
{
if (!SigGraph) return true;
TWeakObjectPtr<UK2Node_EditablePinBase> EntryNode;
TWeakObjectPtr<UK2Node_EditablePinBase> ResultNode;
FBlueprintEditorUtils::GetEntryAndResultNodes(SigGraph, EntryNode, ResultNode);
if (!EntryNode.IsValid())
{
UWingServer::Print(TEXT("ERROR: Entry node not found in delegate signature graph\n"));
return false;
}
return WingFunctionArgs::SetArgs(EntryNode.Get(), DelegateArgs);
}
TArray<FWingProperty> FWingBlueprintVar::MergedProperties()
{
TArray<FWingProperty> Props = FWingProperty::GetAll(
@@ -193,20 +145,9 @@ TArray<FWingProperty> FWingBlueprintVar::MergedProperties()
Props.Append(FWingProperty::GetAll(
FWingBlueprintVar::StaticStruct(), this, (EPropertyFlags)0));
if (SigGraph)
{
FWingProperty::Remove(Props, TEXT("VarType"));
// Remove DefaultValue if we don't have a CDO property to back it.
if (!DefaultValueProp)
FWingProperty::Remove(Props, TEXT("DefaultValue"));
FWingProperty::Remove(Props, TEXT("ExposeOnSpawn"));
FWingProperty::Remove(Props, TEXT("ExposeToCinematics"));
}
else
{
FWingProperty::Remove(Props, TEXT("DelegateArgs"));
// Remove DefaultValue if we don't have a CDO property to back it.
if (!DefaultValueProp)
FWingProperty::Remove(Props, TEXT("DefaultValue"));
}
return Props;
}

View File

@@ -195,7 +195,7 @@ WingFetcher& WingFetcher::Graph(const FString& Value)
if (!BP)
return TypeMismatch(TEXT("graph"), TEXT("Blueprint or Material"));
UEdGraph* Graph = WingUtils::FindExactlyOneNamed(Value, WingUtils::AllGraphs(BP));
UEdGraph* Graph = WingUtils::FindExactlyOneNamed(Value, WingUtils::AllGraphs(BP), TEXT("Graph"));
if (!Graph) return SetError();
SetObj(Graph);
@@ -300,7 +300,7 @@ WingFetcher& WingFetcher::Component(const FString& Value)
return TypeMismatch(TEXT("component"), TEXT("Blueprint"));
TArray<FWingActorComponent> AllComponents = FWingActorComponent::GetAll(BP);
FWingActorComponent* Comp = WingUtils::FindExactlyOneNamed(Value, AllComponents);
FWingActorComponent* Comp = WingUtils::FindExactlyOneNamed(Value, AllComponents, TEXT("Component"));
if (!Comp) return SetError();
if (!Comp->IsOwnedBy(BP))
{

View File

@@ -106,3 +106,14 @@ bool WingFunctionArgs::SetArgs(UEdGraphNode* Node, const FString& Args)
Editable->ReconstructNode();
return true;
}
bool WingFunctionArgs::CheckArgs(const FString &Args)
{
TArray<FParsedArg> NewArgs;
if (!ParseArgs(Args, NewArgs))
{
UWingServer::Printf(TEXT("Invalid function arguments: %s\n"), *Args);
return false;
}
return true;
}

View File

@@ -121,6 +121,23 @@ void FWingProperty::Remove(TArray<FWingProperty>& Props, const FString& Name)
Props.RemoveAll([&](const FWingProperty& P) { return P.Prop->GetName() == Name; });
}
void FWingProperty::Move(TArray<FWingProperty> &Out, TArray<FWingProperty> &In, const FString &Name)
{
int Dst = 0;
for (int i = 0; i < In.Num(); i++)
{
if (In[i]->GetName() == Name)
{
Out.Add(In[i]);
}
else
{
In[Dst++] = In[i];
}
}
In.SetNum(Dst);
}
TArray<FWingProperty> FWingProperty::GetAll(UObject* Obj, EPropertyFlags Flags)
{
if (!Obj) return {};

View File

@@ -70,15 +70,18 @@ FString WingUtils::SanitizeName(const FString &InName)
FString WingUtils::UnsanitizeName(const FString &InName)
{
FString Name = InName;
for (int32 i = 0; i < Name.Len(); i++)
int32 Dst = 0;
for (int32 Src = 0; Src < Name.Len(); Src++)
{
TCHAR c = Name[i];
TCHAR c = Name[Src];
if (c < 0x20 || c == 0x7F) continue;
if (c == L'·') c=' ';
if (c == L'') c='<';
if (c == L'') c='>';
if (c == L'') c=',';
Name[i] = c;
Name[Dst++] = c;
}
Name.LeftInline(Dst);
return Name;
}
@@ -113,6 +116,17 @@ FString WingUtils::StandardizeMenuItem(const FString &Item)
return Sanitized;
}
FString WingUtils::CheckProposedName(const FString &Name)
{
FString Unsanitized = UnsanitizeName(Name);
if ((Unsanitized.IsEmpty()) || (SanitizeName(Unsanitized) != Name))
{
UWingServer::Printf(TEXT("Names must not contain control characters or be empty\n"));
return FString();
}
return Unsanitized;
}
// ============================================================
// Name Lookup
// ============================================================
@@ -142,6 +156,11 @@ FString WingUtils::FormatName(const UEdGraph *Graph)
return SanitizeName(Graph->GetName());
}
FString WingUtils::FormatName(const TObjectPtr<UEdGraph> &Graph)
{
return SanitizeName(Graph->GetName());
}
FString WingUtils::FormatName(const UEdGraphNode* Node)
{
return SanitizeName(Node->GetName());
@@ -335,41 +354,31 @@ bool WingUtils::StringToEnum(UEnum* Enum, const FString& Str, int64& OutValue)
// Common Error Reporting
// ============================================================
bool WingUtils::CheckExactlyOneNamed(int Count, const FString &Kind, const FString &Name)
bool WingUtils::CheckExactlyOneNamed(int Count, const TCHAR *Kind, const FString &Name)
{
if (Count == 0)
{
UWingServer::Printf(TEXT("Could not find a %s named %s.\n"), *Kind, *Name);
UWingServer::Printf(TEXT("Could not find a %s named %s.\n"), Kind, *Name);
return false;
}
if (Count > 1)
{
UWingServer::Printf(TEXT("More than one %s named %s\n"), *Kind, *Name);
UWingServer::Printf(TEXT("More than one %s named %s\n"), Kind, *Name);
return false;
}
return true;
}
bool WingUtils::CheckExactlyOneNamed(int Count, UClass *Class, const FString &Name)
{
return CheckExactlyOneNamed(Count, Class->GetName(), Name);
}
bool WingUtils::CheckExactlyNoneNamed(int Count, const FString &Kind, const FString &Name)
bool WingUtils::CheckExactlyNoneNamed(int Count, const TCHAR *Kind, const FString &Name)
{
if (Count > 0)
{
UWingServer::Printf(TEXT("A %s named %s already exists."), *Kind, *Name);
UWingServer::Printf(TEXT("A %s named %s already exists."), Kind, *Name);
return false;
}
return true;
}
bool WingUtils::CheckExactlyNoneNamed(int Count, UClass *Class, const FString &Name)
{
return CheckExactlyNoneNamed(Count, Class->GetName(), Name);
}
// ============================================================
// Blueprint helpers
// ============================================================