More work on raise error K2 node

This commit is contained in:
2024-11-11 19:20:13 -05:00
parent e716c857fc
commit ce0a06c51c
3 changed files with 80 additions and 119 deletions

View File

@@ -40,24 +40,28 @@
#define LOCTEXT_NAMESPACE "K2Node_RaiseError"
/////////////////////////////////////////////////////
// UK2Node_RaiseError
// It simplifies everything if we can identify pins by name, but to do this
// we need for pin names to be unique. To ensure that there's no overlap
// between the hardwired names and the scripter's names, we add a single
// whitespace to any pin name specified in the format string.
struct FRaiseErrorNodeHelper
{
static const FName FormatPinName;
static const FName FormatPinName(TEXT("Format"));
static const FName ResultPinName(TEXT("Result"));
static const FName GetFormatPinName()
{
return FormatPinName;
}
};
static bool IsFormatPin(const UEdGraphPin *Pin) {
return (Pin->PinName == FormatPinName);
}
const FName FRaiseErrorNodeHelper::FormatPinName(TEXT("Format"));
static bool IsResultPin(const UEdGraphPin *Pin) {
return (Pin->PinName == ResultPinName);
}
static bool IsArgumentPin(const UEdGraphPin *Pin) {
return ((Pin->PinName != FormatPinName) && (Pin->Direction == EGPD_Input));
}
UK2Node_RaiseError::UK2Node_RaiseError(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
, CachedFormatPin(NULL)
{
NodeTooltip = LOCTEXT("NodeTooltip", "Builds a formatted string using available format argument values.\n \u2022 Use {} to denote format arguments.\n \u2022 Argument types may be Byte, Integer, Float, Text, String, Name, Boolean, Object or ETextGender.");
}
@@ -65,20 +69,58 @@ UK2Node_RaiseError::UK2Node_RaiseError(const FObjectInitializer& ObjectInitializ
void UK2Node_RaiseError::AllocateDefaultPins()
{
Super::AllocateDefaultPins();
CreateCorrectPins();
}
CachedFormatPin = CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Text, FRaiseErrorNodeHelper::GetFormatPinName());
CreatePin(EGPD_Output, UEdGraphSchema_K2::PC_Text, TEXT("Result"));
void UK2Node_RaiseError::CreateCorrectPins()
{
// Create the Format Pin if it doesn't already exist.
if (FindPin(FormatPinName, EGPD_Input) == nullptr) {
CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Text, FormatPinName);
}
// Create the Result Pin if it doesn't already exist.
if (FindPin(ResultPinName, EGPD_Output) == nullptr) {
CreatePin(EGPD_Output, UEdGraphSchema_K2::PC_Text, ResultPinName);
}
// Transfer all Existing Argument pins to the Old Pins Map.
TMap<FString, UEdGraphPin *> OldPins;
for (auto It = Pins.CreateIterator(); It; ++It)
{
UEdGraphPin* CheckPin = *It;
if (IsArgumentPin(CheckPin))
{
OldPins.Add(CheckPin->PinName.ToString(), CheckPin);
It.RemoveCurrent();
}
}
// Create Argument pins in the correct order, reusing old pins where possible.
for (const FName& PinName : PinNames)
{
CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Wildcard, PinName);
UEdGraphPin **OldPin = OldPins.Find(PinName.ToString());
if (OldPin != nullptr) {
Pins.Emplace(*OldPin);
OldPins.Remove(PinName.ToString());
} else {
CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Wildcard, PinName);
}
}
// Delete any unused pins.
for (auto &iter : OldPins)
{
iter.Value->Modify();
iter.Value->MarkAsGarbage();
}
OldPins.Empty();
}
void UK2Node_RaiseError::SynchronizeArgumentPinType(UEdGraphPin* Pin)
{
const UEdGraphPin* FormatPin = GetFormatPin();
if (Pin != FormatPin && Pin->Direction == EGPD_Input)
if (IsArgumentPin(Pin))
{
const UEdGraphSchema_K2* K2Schema = Cast<const UEdGraphSchema_K2>(GetSchema());
@@ -143,82 +185,31 @@ void UK2Node_RaiseError::PostEditChangeProperty(struct FPropertyChangedEvent& Pr
void UK2Node_RaiseError::PinConnectionListChanged(UEdGraphPin* Pin)
{
UEdGraphPin* FormatPin = GetFormatPin();
Modify();
// Clear all pins.
if(Pin == FormatPin && !FormatPin->DefaultTextValue.IsEmpty())
{
PinNames.Empty();
GetSchema()->TrySetDefaultText(*FormatPin, FText::GetEmpty());
for(auto It = Pins.CreateConstIterator(); It; ++It)
{
UEdGraphPin* CheckPin = *It;
if(CheckPin != FormatPin && CheckPin->Direction == EGPD_Input)
{
CheckPin->Modify();
CheckPin->MarkAsGarbage();
Pins.Remove(CheckPin);
--It;
}
}
FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(GetBlueprint());
}
// Potentially update an argument pin type
SynchronizeArgumentPinType(Pin);
}
void UK2Node_RaiseError::PinDefaultValueChanged(UEdGraphPin* Pin)
{
const UEdGraphPin* FormatPin = GetFormatPin();
if(Pin == FormatPin && FormatPin->LinkedTo.Num() == 0)
if(IsFormatPin(Pin))
{
TArray< FString > ArgumentParams;
FText::GetFormatPatternParameters(FormatPin->DefaultTextValue, ArgumentParams);
FText::GetFormatPatternParameters(Pin->DefaultTextValue, ArgumentParams);
PinNames.Reset();
for (const FString& Param : ArgumentParams)
{
const FName ParamName(*Param);
if (!FindArgumentPin(ParamName))
{
CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Wildcard, ParamName);
}
PinNames.Add(ParamName);
FString WithWhite = Param + TEXT(" ");
PinNames.Add(FName(*WithWhite));
}
for (auto It = Pins.CreateIterator(); It; ++It)
{
UEdGraphPin* CheckPin = *It;
if (CheckPin != FormatPin && CheckPin->Direction == EGPD_Input)
{
const bool bIsValidArgPin = ArgumentParams.ContainsByPredicate([&CheckPin](const FString& InPinName)
{
return InPinName.Equals(CheckPin->PinName.ToString(), ESearchCase::CaseSensitive);
});
if(!bIsValidArgPin)
{
CheckPin->MarkAsGarbage();
It.RemoveCurrent();
}
}
}
CreateCorrectPins();
GetGraph()->NotifyNodeChanged(this);
}
}
void UK2Node_RaiseError::PinTypeChanged(UEdGraphPin* Pin)
{
// Potentially update an argument pin type
SynchronizeArgumentPinType(Pin);
Super::PinTypeChanged(Pin);
}
@@ -291,7 +282,11 @@ void UK2Node_RaiseError::ExpandNode(class FKismetCompilerContext& CompilerContex
// For each argument, we will need to add in a "Make Struct" node.
for(int32 ArgIdx = 0; ArgIdx < PinNames.Num(); ++ArgIdx)
{
UEdGraphPin* ArgumentPin = FindArgumentPin(PinNames[ArgIdx]);
UEdGraphPin* ArgumentPin = FindPin(PinNames[ArgIdx], EGPD_Input);
// All argument pins have a whitespace appended to their pin names.
// We need the original name before the whitespace was appended.
FString OriginalName = ArgumentPin->PinName.ToString().LeftChop(1);
static UScriptStruct* FormatArgumentDataStruct = FindObjectChecked<UScriptStruct>(FindObjectChecked<UPackage>(nullptr, TEXT("/Script/Engine")), TEXT("FormatArgumentData"));
@@ -303,7 +298,7 @@ void UK2Node_RaiseError::ExpandNode(class FKismetCompilerContext& CompilerContex
CompilerContext.MessageLog.NotifyIntermediateObjectCreation(MakeFormatArgumentDataStruct, this);
// Set the struct's "ArgumentName" pin literal to be the argument pin's name.
MakeFormatArgumentDataStruct->GetSchema()->TrySetDefaultValue(*MakeFormatArgumentDataStruct->FindPinChecked(GET_MEMBER_NAME_STRING_CHECKED(FFormatArgumentData, ArgumentName)), ArgumentPin->PinName.ToString());
MakeFormatArgumentDataStruct->GetSchema()->TrySetDefaultValue(*MakeFormatArgumentDataStruct->FindPinChecked(GET_MEMBER_NAME_STRING_CHECKED(FFormatArgumentData, ArgumentName)), OriginalName);
UEdGraphPin* ArgumentTypePin = MakeFormatArgumentDataStruct->FindPinChecked(GET_MEMBER_NAME_STRING_CHECKED(FFormatArgumentData, ArgumentValueType));
@@ -440,26 +435,13 @@ void UK2Node_RaiseError::ExpandNode(class FKismetCompilerContext& CompilerContex
}
// Move connection of RaiseError's "Result" pin to the call function's return value pin.
CompilerContext.MovePinLinksToIntermediate(*FindPinChecked(TEXT("Result")), *CallFormatFunction->GetReturnValuePin());
CompilerContext.MovePinLinksToIntermediate(*FindPinChecked(ResultPinName, EGPD_Output), *CallFormatFunction->GetReturnValuePin());
// Move connection of RaiseError's "Format" pin to the call function's "InPattern" pin
CompilerContext.MovePinLinksToIntermediate(*GetFormatPin(), *CallFormatFunction->FindPinChecked(TEXT("InPattern")));
CompilerContext.MovePinLinksToIntermediate(*FindPinChecked(FormatPinName, EGPD_Input), *CallFormatFunction->FindPinChecked(TEXT("InPattern")));
BreakAllNodeLinks();
}
UEdGraphPin* UK2Node_RaiseError::FindArgumentPin(const FName InPinName) const
{
const UEdGraphPin* FormatPin = GetFormatPin();
for (UEdGraphPin* Pin : Pins)
{
if( Pin != FormatPin && Pin->Direction != EGPD_Output && Pin->PinName.ToString().Equals(InPinName.ToString(), ESearchCase::CaseSensitive) )
{
return Pin;
}
}
return nullptr;
}
UK2Node::ERedirectType UK2Node_RaiseError::DoPinsMatchForReconstruction(const UEdGraphPin* NewPin, int32 NewPinIndex, const UEdGraphPin* OldPin, int32 OldPinIndex) const
{
@@ -508,16 +490,15 @@ UK2Node::ERedirectType UK2Node_RaiseError::DoPinsMatchForReconstruction(const UE
bool UK2Node_RaiseError::IsConnectionDisallowed(const UEdGraphPin* MyPin, const UEdGraphPin* OtherPin, FString& OutReason) const
{
// Argument input pins may only be connected to Byte, Integer, Float, Text, and ETextGender pins...
const UEdGraphPin* FormatPin = GetFormatPin();
// The format pin cannot be connected to anything. It must be a constant string.
if (MyPin == FormatPin) {
if (IsFormatPin(MyPin))
{
OutReason = LOCTEXT("Error_FormatStringMustBeHardwired", "Format string must be a hardwired constant.").ToString();
return true;
}
if (MyPin != FormatPin && MyPin->Direction == EGPD_Input)
// Argument input pins may only be connected to Byte, Integer, Float, Text, and ETextGender pins...
if (IsArgumentPin(MyPin))
{
const UEdGraphSchema_K2* K2Schema = Cast<const UEdGraphSchema_K2>(GetSchema());
const FName& OtherPinCategory = OtherPin->PinType.PinCategory;
@@ -549,15 +530,6 @@ bool UK2Node_RaiseError::IsConnectionDisallowed(const UEdGraphPin* MyPin, const
return Super::IsConnectionDisallowed(MyPin, OtherPin, OutReason);
}
UEdGraphPin* UK2Node_RaiseError::GetFormatPin() const
{
UK2Node_RaiseError *mthis = const_cast<UK2Node_RaiseError*>(this);
if (!CachedFormatPin)
{
mthis->CachedFormatPin = FindPinChecked(FRaiseErrorNodeHelper::GetFormatPinName());
}
return CachedFormatPin;
}
void UK2Node_RaiseError::GetMenuActions(FBlueprintActionDatabaseRegistrar& ActionRegistrar) const
{

View File

@@ -53,16 +53,8 @@ class UK2Node_RaiseError : public UK2Node
//~ End UK2Node Interface.
private:
/** returns Format pin */
UEdGraphPin* GetFormatPin() const;
/**
* Finds an argument pin by name, checking strings in a strict, case sensitive fashion
*
* @param InPinName The pin name to check for
* @return NULL if the pin was not found, otherwise the found pin.
*/
UEdGraphPin* FindArgumentPin(const FName InPinName) const;
/** Create all necessary pins */
void CreateCorrectPins();
/** Synchronize the type of the given argument pin with the type its connected to, or reset it to a wildcard pin if there's no connection */
void SynchronizeArgumentPinType(UEdGraphPin* Pin);
@@ -72,9 +64,6 @@ private:
UPROPERTY()
TArray<FName> PinNames;
/** The "Format" input pin, always available on the node */
UEdGraphPin* CachedFormatPin;
/** Tooltip text for this node. */
FText NodeTooltip;
};