diff --git a/Content/Tangibles/tangiblecharacter.uasset b/Content/Tangibles/tangiblecharacter.uasset index 537b88ef..987ed3e3 100644 --- a/Content/Tangibles/tangiblecharacter.uasset +++ b/Content/Tangibles/tangiblecharacter.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:28be199cf61d9a66b2e0ba224a291ee906eff202435f39290abc0e83a0f8d774 -size 365403 +oid sha256:679f48b72656a40b3a6a83e106df2b2d4c76390a8f87948e5122526852257d44 +size 389151 diff --git a/Source/Integration/K2Node_RaiseError.cpp b/Source/Integration/K2Node_RaiseError.cpp index 8c798b97..d75ae95f 100644 --- a/Source/Integration/K2Node_RaiseError.cpp +++ b/Source/Integration/K2Node_RaiseError.cpp @@ -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 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(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(FindObjectChecked(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(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(this); - if (!CachedFormatPin) - { - mthis->CachedFormatPin = FindPinChecked(FRaiseErrorNodeHelper::GetFormatPinName()); - } - return CachedFormatPin; -} void UK2Node_RaiseError::GetMenuActions(FBlueprintActionDatabaseRegistrar& ActionRegistrar) const { diff --git a/Source/Integration/K2Node_RaiseError.h b/Source/Integration/K2Node_RaiseError.h index 23d921d7..0192c591 100644 --- a/Source/Integration/K2Node_RaiseError.h +++ b/Source/Integration/K2Node_RaiseError.h @@ -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 PinNames; - /** The "Format" input pin, always available on the node */ - UEdGraphPin* CachedFormatPin; - /** Tooltip text for this node. */ FText NodeTooltip; };