2024-10-28 17:40:29 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "K2Node_RaiseError.h"
# include "BlueprintActionDatabaseRegistrar.h"
# include "BlueprintNodeSpawner.h"
# include "Containers/EnumAsByte.h"
# include "Containers/UnrealString.h"
# include "EdGraph/EdGraph.h"
# include "EdGraph/EdGraphSchema.h"
# include "EdGraphSchema_K2.h"
# include "EdGraphSchema_K2_Actions.h"
# include "EditorCategoryUtils.h"
# include "Engine/Blueprint.h"
# include "HAL/PlatformCrt.h"
# include "Internationalization/Internationalization.h"
# include "K2Node_CallFunction.h"
# include "K2Node_MakeArray.h"
# include "K2Node_MakeStruct.h"
# include "Kismet/KismetMathLibrary.h"
# include "Kismet/KismetSystemLibrary.h"
# include "Kismet/KismetTextLibrary.h"
# include "Kismet2/BlueprintEditorUtils.h"
# include "Kismet2/CompilerResultsLog.h"
# include "KismetCompiler.h"
# include "Math/Vector2D.h"
# include "Misc/AssertionMacros.h"
# include "Misc/CString.h"
# include "ScopedTransaction.h"
# include "Templates/Casts.h"
# include "Templates/SubclassOf.h"
# include "UObject/Class.h"
# include "UObject/ObjectPtr.h"
# include "UObject/Package.h"
# include "UObject/UnrealNames.h"
# include "UObject/UnrealType.h"
# include "UObject/WeakObjectPtr.h"
# include "UObject/WeakObjectPtrTemplates.h"
# define LOCTEXT_NAMESPACE "K2Node_RaiseError"
2024-11-13 18:18:32 -05:00
// All argument pins will have Names that start with "A:"
2024-10-28 17:40:29 -04:00
2024-11-13 18:18:32 -05:00
static bool IsArgumentPin ( const UEdGraphPin * Pin ) {
TCHAR pname [ FName : : StringBufferSize ] ;
Pin - > PinName . ToString ( pname ) ;
return pname [ 0 ] = = ' A ' & & pname [ 1 ] = = ' : ' ;
}
2024-10-28 17:40:29 -04:00
2024-11-13 18:18:32 -05:00
static FName ArgumentNameAddPrefix ( const FString & name ) {
FString Prefixed = FString ( " A: " ) + name ;
return FName ( * Prefixed ) ;
2024-11-11 19:20:13 -05:00
}
2024-10-28 17:40:29 -04:00
2024-11-13 18:18:32 -05:00
static FString ArgumentNameRemovePrefix ( const FName & name ) {
return name . ToString ( ) . Mid ( 2 , FName : : StringBufferSize ) ;
2024-11-11 19:20:13 -05:00
}
2024-11-13 18:18:32 -05:00
static const FName FormatPinName ( TEXT ( " Format " ) ) ;
static bool IsFormatPin ( const UEdGraphPin * Pin ) {
return ( Pin - > PinName = = FormatPinName ) ;
2024-11-11 19:20:13 -05:00
}
2024-10-28 17:40:29 -04:00
UK2Node_RaiseError : : UK2Node_RaiseError ( const FObjectInitializer & ObjectInitializer )
: Super ( ObjectInitializer )
{
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. " ) ;
}
void UK2Node_RaiseError : : AllocateDefaultPins ( )
{
Super : : AllocateDefaultPins ( ) ;
2024-11-11 19:20:13 -05:00
CreateCorrectPins ( ) ;
}
2024-10-28 17:40:29 -04:00
2024-11-11 19:20:13 -05:00
void UK2Node_RaiseError : : CreateCorrectPins ( )
{
2024-11-13 18:18:32 -05:00
if ( FindPin ( UEdGraphSchema_K2 : : PN_Execute ) = = nullptr ) {
UEdGraphPin * P = CreatePin ( EGPD_Input , UEdGraphSchema_K2 : : PC_Exec , UEdGraphSchema_K2 : : PN_Execute ) ;
2024-11-11 19:20:13 -05:00
}
2024-11-13 18:18:32 -05:00
if ( FindPin ( UEdGraphSchema_K2 : : PN_Then ) = = nullptr ) {
UEdGraphPin * P = CreatePin ( EGPD_Output , UEdGraphSchema_K2 : : PC_Exec , UEdGraphSchema_K2 : : PN_Then ) ;
}
if ( FindPin ( FormatPinName , EGPD_Input ) = = nullptr ) {
UEdGraphPin * P = CreatePin ( EGPD_Input , UEdGraphSchema_K2 : : PC_Text , FormatPinName ) ;
2024-11-11 19:20:13 -05:00
}
// 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 ) )
{
2024-11-13 18:18:32 -05:00
OldPins . Add ( ArgumentNameRemovePrefix ( CheckPin - > PinName ) , CheckPin ) ;
2024-11-11 19:20:13 -05:00
It . RemoveCurrent ( ) ;
}
}
2024-10-28 17:40:29 -04:00
2024-11-11 19:20:13 -05:00
// Create Argument pins in the correct order, reusing old pins where possible.
2024-11-13 18:18:32 -05:00
for ( const FString & Name : PinNames )
2024-10-28 17:40:29 -04:00
{
2024-11-13 18:18:32 -05:00
UEdGraphPin * * OldPin = OldPins . Find ( Name ) ;
2024-11-11 19:20:13 -05:00
if ( OldPin ! = nullptr ) {
Pins . Emplace ( * OldPin ) ;
2024-11-13 18:18:32 -05:00
OldPins . Remove ( Name ) ;
2024-11-11 19:20:13 -05:00
} else {
2024-11-13 18:18:32 -05:00
FName PrefixedName = ArgumentNameAddPrefix ( Name ) ;
UEdGraphPin * P = CreatePin ( EGPD_Input , UEdGraphSchema_K2 : : PC_Wildcard , PrefixedName ) ;
2024-11-11 19:20:13 -05:00
}
}
// Delete any unused pins.
for ( auto & iter : OldPins )
{
iter . Value - > Modify ( ) ;
iter . Value - > MarkAsGarbage ( ) ;
2024-10-28 17:40:29 -04:00
}
2024-11-11 19:20:13 -05:00
OldPins . Empty ( ) ;
2024-10-28 17:40:29 -04:00
}
2024-11-11 19:20:13 -05:00
2024-10-28 17:40:29 -04:00
void UK2Node_RaiseError : : SynchronizeArgumentPinType ( UEdGraphPin * Pin )
{
2024-11-11 19:20:13 -05:00
if ( IsArgumentPin ( Pin ) )
2024-10-28 17:40:29 -04:00
{
const UEdGraphSchema_K2 * K2Schema = Cast < const UEdGraphSchema_K2 > ( GetSchema ( ) ) ;
bool bPinTypeChanged = false ;
if ( Pin - > LinkedTo . Num ( ) = = 0 )
{
static const FEdGraphPinType WildcardPinType = FEdGraphPinType ( UEdGraphSchema_K2 : : PC_Wildcard , NAME_None , nullptr , EPinContainerType : : None , false , FEdGraphTerminalType ( ) ) ;
// Ensure wildcard
if ( Pin - > PinType ! = WildcardPinType )
{
Pin - > PinType = WildcardPinType ;
bPinTypeChanged = true ;
}
}
else
{
UEdGraphPin * ArgumentSourcePin = Pin - > LinkedTo [ 0 ] ;
// Take the type of the connected pin
if ( Pin - > PinType ! = ArgumentSourcePin - > PinType )
{
Pin - > PinType = ArgumentSourcePin - > PinType ;
bPinTypeChanged = true ;
}
}
if ( bPinTypeChanged )
{
// Let the graph know to refresh
GetGraph ( ) - > NotifyNodeChanged ( this ) ;
UBlueprint * Blueprint = GetBlueprint ( ) ;
if ( ! Blueprint - > bBeingCompiled )
{
FBlueprintEditorUtils : : MarkBlueprintAsModified ( Blueprint ) ;
}
}
}
}
FText UK2Node_RaiseError : : GetNodeTitle ( ENodeTitleType : : Type TitleType ) const
{
return LOCTEXT ( " RaiseError_Title " , " Raise Error " ) ;
}
FText UK2Node_RaiseError : : GetPinDisplayName ( const UEdGraphPin * Pin ) const
{
2024-11-13 18:18:32 -05:00
// These pins should be unlabeled.
if ( ( Pin - > PinType . PinCategory = = UEdGraphSchema_K2 : : PC_Exec ) | | ( IsFormatPin ( Pin ) ) ) {
return FText : : GetEmpty ( ) ;
}
// For argument pins, we must strip off the Argument Pin Prefix.
if ( IsArgumentPin ( Pin ) ) {
return FText : : FromString ( ArgumentNameRemovePrefix ( Pin - > PinName ) ) ;
}
// Probably should never get here.
2024-10-28 17:40:29 -04:00
return FText : : FromName ( Pin - > PinName ) ;
}
void UK2Node_RaiseError : : PostEditChangeProperty ( struct FPropertyChangedEvent & PropertyChangedEvent )
{
const FName PropertyName = ( PropertyChangedEvent . Property ? PropertyChangedEvent . Property - > GetFName ( ) : NAME_None ) ;
if ( PropertyName = = GET_MEMBER_NAME_CHECKED ( UK2Node_RaiseError , PinNames ) )
{
ReconstructNode ( ) ;
}
Super : : PostEditChangeProperty ( PropertyChangedEvent ) ;
GetGraph ( ) - > NotifyNodeChanged ( this ) ;
}
void UK2Node_RaiseError : : PinConnectionListChanged ( UEdGraphPin * Pin )
{
Modify ( ) ;
SynchronizeArgumentPinType ( Pin ) ;
}
void UK2Node_RaiseError : : PinDefaultValueChanged ( UEdGraphPin * Pin )
{
2024-11-11 19:20:13 -05:00
if ( IsFormatPin ( Pin ) )
2024-10-28 17:40:29 -04:00
{
2024-11-13 18:18:32 -05:00
PinNames . Empty ( ) ;
FText : : GetFormatPatternParameters ( Pin - > DefaultTextValue , PinNames ) ;
2024-11-11 19:20:13 -05:00
CreateCorrectPins ( ) ;
2024-10-28 17:40:29 -04:00
GetGraph ( ) - > NotifyNodeChanged ( this ) ;
}
}
void UK2Node_RaiseError : : PinTypeChanged ( UEdGraphPin * Pin )
{
SynchronizeArgumentPinType ( Pin ) ;
Super : : PinTypeChanged ( Pin ) ;
}
FText UK2Node_RaiseError : : GetTooltipText ( ) const
{
return NodeTooltip ;
}
UEdGraphPin * FindOutputStructPinChecked ( UEdGraphNode * Node )
{
check ( NULL ! = Node ) ;
UEdGraphPin * OutputPin = NULL ;
for ( int32 PinIndex = 0 ; PinIndex < Node - > Pins . Num ( ) ; + + PinIndex )
{
UEdGraphPin * Pin = Node - > Pins [ PinIndex ] ;
if ( Pin & & ( EGPD_Output = = Pin - > Direction ) )
{
OutputPin = Pin ;
break ;
}
}
check ( NULL ! = OutputPin ) ;
return OutputPin ;
}
void UK2Node_RaiseError : : PostReconstructNode ( )
{
Super : : PostReconstructNode ( ) ;
UEdGraph * OuterGraph = GetGraph ( ) ;
if ( ! IsTemplate ( ) & & OuterGraph & & OuterGraph - > Schema ) {
for ( UEdGraphPin * CurrentPin : Pins )
{
// Potentially update an argument pin type
SynchronizeArgumentPinType ( CurrentPin ) ;
}
}
}
void UK2Node_RaiseError : : ExpandNode ( class FKismetCompilerContext & CompilerContext , UEdGraph * SourceGraph )
{
Super : : ExpandNode ( CompilerContext , SourceGraph ) ;
/**
At the end of this , the UK2Node_RaiseError will not be a part of the Blueprint , it merely handles connecting
the other nodes into the Blueprint .
*/
const UEdGraphSchema_K2 * Schema = CompilerContext . GetSchema ( ) ;
// Create a "Make Array" node to compile the list of arguments into an array for the Format function being called
UK2Node_MakeArray * MakeArrayNode = CompilerContext . SpawnIntermediateNode < UK2Node_MakeArray > ( this , SourceGraph ) ;
MakeArrayNode - > AllocateDefaultPins ( ) ;
CompilerContext . MessageLog . NotifyIntermediateObjectCreation ( MakeArrayNode , this ) ;
// This is the node that does all the Format work.
UK2Node_CallFunction * CallFormatFunction = CompilerContext . SpawnIntermediateNode < UK2Node_CallFunction > ( this , SourceGraph ) ;
CallFormatFunction - > SetFromFunction ( UKismetTextLibrary : : StaticClass ( ) - > FindFunctionByName ( GET_MEMBER_NAME_CHECKED ( UKismetTextLibrary , Format ) ) ) ;
CallFormatFunction - > AllocateDefaultPins ( ) ;
CompilerContext . MessageLog . NotifyIntermediateObjectCreation ( CallFormatFunction , this ) ;
2024-11-13 18:18:32 -05:00
// This is the node that outputs the text.
UK2Node_CallFunction * CallPrintFunction = CompilerContext . SpawnIntermediateNode < UK2Node_CallFunction > ( this , SourceGraph ) ;
CallPrintFunction - > SetFromFunction ( UKismetSystemLibrary : : StaticClass ( ) - > FindFunctionByName ( GET_MEMBER_NAME_CHECKED ( UKismetSystemLibrary , PrintText ) ) ) ;
CallPrintFunction - > AllocateDefaultPins ( ) ;
CompilerContext . MessageLog . NotifyIntermediateObjectCreation ( CallPrintFunction , this ) ;
2024-10-28 17:40:29 -04:00
// Connect the output of the "Make Array" pin to the function's "InArgs" pin
2024-11-13 18:18:32 -05:00
UEdGraphPin * ArrayOut = MakeArrayNode - > GetOutputPin ( ) ;
2024-10-28 17:40:29 -04:00
ArrayOut - > MakeLinkTo ( CallFormatFunction - > FindPinChecked ( TEXT ( " InArgs " ) ) ) ;
// This will set the "Make Array" node's type, only works if one pin is connected.
MakeArrayNode - > PinConnectionListChanged ( ArrayOut ) ;
2024-11-13 18:18:32 -05:00
// Connect the output of the "Format" node to the PrintText function's "InText" pin
UEdGraphPin * FormatOut = CallFormatFunction - > GetReturnValuePin ( ) ;
FormatOut - > MakeLinkTo ( CallPrintFunction - > FindPinChecked ( TEXT ( " InText " ) ) ) ;
// Configure the Print function to keep the text onscreen for 30 seconds.
UEdGraphPin * DurationIn = CallPrintFunction - > FindPinChecked ( TEXT ( " Duration " ) ) ;
CallPrintFunction - > GetSchema ( ) - > TrySetDefaultValue ( * DurationIn , " 30 " ) ;
2024-10-28 17:40:29 -04:00
// For each argument, we will need to add in a "Make Struct" node.
for ( int32 ArgIdx = 0 ; ArgIdx < PinNames . Num ( ) ; + + ArgIdx )
{
2024-11-13 18:18:32 -05:00
FString OriginalName = PinNames [ ArgIdx ] ;
UEdGraphPin * ArgumentPin = FindPin ( ArgumentNameAddPrefix ( OriginalName ) , EGPD_Input ) ;
2024-10-28 17:40:29 -04:00
static UScriptStruct * FormatArgumentDataStruct = FindObjectChecked < UScriptStruct > ( FindObjectChecked < UPackage > ( nullptr , TEXT ( " /Script/Engine " ) ) , TEXT ( " FormatArgumentData " ) ) ;
// Spawn a "Make Struct" node to create the struct needed for formatting the text.
UK2Node_MakeStruct * MakeFormatArgumentDataStruct = CompilerContext . SpawnIntermediateNode < UK2Node_MakeStruct > ( this , SourceGraph ) ;
MakeFormatArgumentDataStruct - > StructType = FormatArgumentDataStruct ;
MakeFormatArgumentDataStruct - > AllocateDefaultPins ( ) ;
MakeFormatArgumentDataStruct - > bMadeAfterOverridePinRemoval = true ;
CompilerContext . MessageLog . NotifyIntermediateObjectCreation ( MakeFormatArgumentDataStruct , this ) ;
// Set the struct's "ArgumentName" pin literal to be the argument pin's name.
2024-11-11 19:20:13 -05:00
MakeFormatArgumentDataStruct - > GetSchema ( ) - > TrySetDefaultValue ( * MakeFormatArgumentDataStruct - > FindPinChecked ( GET_MEMBER_NAME_STRING_CHECKED ( FFormatArgumentData , ArgumentName ) ) , OriginalName ) ;
2024-10-28 17:40:29 -04:00
UEdGraphPin * ArgumentTypePin = MakeFormatArgumentDataStruct - > FindPinChecked ( GET_MEMBER_NAME_STRING_CHECKED ( FFormatArgumentData , ArgumentValueType ) ) ;
// Move the connection of the argument pin to the correct argument value pin, and also set the correct argument type based on the pin that was hooked up.
if ( ArgumentPin - > LinkedTo . Num ( ) > 0 )
{
const FName & ArgumentPinCategory = ArgumentPin - > PinType . PinCategory ;
// Adds an implicit conversion node to this argument based on its function and pin name
auto AddConversionNode = [ & ] ( const FName FuncName , const TCHAR * PinName )
{
// Set the default value if there was something passed in, or default to "Text"
MakeFormatArgumentDataStruct - > GetSchema ( ) - > TrySetDefaultValue ( * ArgumentTypePin , TEXT ( " Text " ) ) ;
// Spawn conversion node based on the given function name
UK2Node_CallFunction * ToTextFunction = CompilerContext . SpawnIntermediateNode < UK2Node_CallFunction > ( this , SourceGraph ) ;
ToTextFunction - > SetFromFunction ( UKismetTextLibrary : : StaticClass ( ) - > FindFunctionByName ( FuncName ) ) ;
ToTextFunction - > AllocateDefaultPins ( ) ;
CompilerContext . MessageLog . NotifyIntermediateObjectCreation ( ToTextFunction , this ) ;
CompilerContext . MovePinLinksToIntermediate ( * ArgumentPin , * ToTextFunction - > FindPinChecked ( PinName ) ) ;
ToTextFunction - > FindPinChecked ( UEdGraphSchema_K2 : : PN_ReturnValue ) - > MakeLinkTo ( MakeFormatArgumentDataStruct - > FindPinChecked ( GET_MEMBER_NAME_STRING_CHECKED ( FFormatArgumentData , ArgumentValue ) ) ) ;
} ;
if ( ArgumentPinCategory = = UEdGraphSchema_K2 : : PC_Int )
{
MakeFormatArgumentDataStruct - > GetSchema ( ) - > TrySetDefaultValue ( * ArgumentTypePin , TEXT ( " Int " ) ) ;
// Need a manual cast from int -> int64
UK2Node_CallFunction * CallFloatToDoubleFunction = CompilerContext . SpawnIntermediateNode < UK2Node_CallFunction > ( this , SourceGraph ) ;
CallFloatToDoubleFunction - > SetFromFunction ( UKismetMathLibrary : : StaticClass ( ) - > FindFunctionByName ( GET_MEMBER_NAME_CHECKED ( UKismetMathLibrary , Conv_IntToInt64 ) ) ) ;
CallFloatToDoubleFunction - > AllocateDefaultPins ( ) ;
CompilerContext . MessageLog . NotifyIntermediateObjectCreation ( CallFloatToDoubleFunction , this ) ;
// Move the byte output pin to the input pin of the conversion node
CompilerContext . MovePinLinksToIntermediate ( * ArgumentPin , * CallFloatToDoubleFunction - > FindPinChecked ( TEXT ( " InInt " ) ) ) ;
// Connect the int output pin to the argument value
CallFloatToDoubleFunction - > FindPinChecked ( UEdGraphSchema_K2 : : PN_ReturnValue ) - > MakeLinkTo ( MakeFormatArgumentDataStruct - > FindPinChecked ( GET_MEMBER_NAME_STRING_CHECKED ( FFormatArgumentData , ArgumentValueInt ) ) ) ;
}
else if ( ArgumentPinCategory = = UEdGraphSchema_K2 : : PC_Real )
{
if ( ArgumentPin - > PinType . PinSubCategory = = UEdGraphSchema_K2 : : PC_Float )
{
MakeFormatArgumentDataStruct - > GetSchema ( ) - > TrySetDefaultValue ( * ArgumentTypePin , TEXT ( " Float " ) ) ;
CompilerContext . MovePinLinksToIntermediate ( * ArgumentPin , * MakeFormatArgumentDataStruct - > FindPinChecked ( GET_MEMBER_NAME_STRING_CHECKED ( FFormatArgumentData , ArgumentValueFloat ) ) ) ;
}
else if ( ArgumentPin - > PinType . PinSubCategory = = UEdGraphSchema_K2 : : PC_Double )
{
MakeFormatArgumentDataStruct - > GetSchema ( ) - > TrySetDefaultValue ( * ArgumentTypePin , TEXT ( " Double " ) ) ;
CompilerContext . MovePinLinksToIntermediate ( * ArgumentPin , * MakeFormatArgumentDataStruct - > FindPinChecked ( GET_MEMBER_NAME_STRING_CHECKED ( FFormatArgumentData , ArgumentValueDouble ) ) ) ;
}
else
{
check ( false ) ;
}
}
else if ( ArgumentPinCategory = = UEdGraphSchema_K2 : : PC_Int64 )
{
MakeFormatArgumentDataStruct - > GetSchema ( ) - > TrySetDefaultValue ( * ArgumentTypePin , TEXT ( " Int64 " ) ) ;
CompilerContext . MovePinLinksToIntermediate ( * ArgumentPin , * MakeFormatArgumentDataStruct - > FindPinChecked ( GET_MEMBER_NAME_STRING_CHECKED ( FFormatArgumentData , ArgumentValueInt ) ) ) ;
}
else if ( ArgumentPinCategory = = UEdGraphSchema_K2 : : PC_Text )
{
MakeFormatArgumentDataStruct - > GetSchema ( ) - > TrySetDefaultValue ( * ArgumentTypePin , TEXT ( " Text " ) ) ;
CompilerContext . MovePinLinksToIntermediate ( * ArgumentPin , * MakeFormatArgumentDataStruct - > FindPinChecked ( GET_MEMBER_NAME_STRING_CHECKED ( FFormatArgumentData , ArgumentValue ) ) ) ;
}
else if ( ArgumentPinCategory = = UEdGraphSchema_K2 : : PC_Byte & & ! ArgumentPin - > PinType . PinSubCategoryObject . IsValid ( ) )
{
MakeFormatArgumentDataStruct - > GetSchema ( ) - > TrySetDefaultValue ( * ArgumentTypePin , TEXT ( " Int " ) ) ;
// Need a manual cast from byte -> int
UK2Node_CallFunction * CallByteToIntFunction = CompilerContext . SpawnIntermediateNode < UK2Node_CallFunction > ( this , SourceGraph ) ;
CallByteToIntFunction - > SetFromFunction ( UKismetMathLibrary : : StaticClass ( ) - > FindFunctionByName ( GET_MEMBER_NAME_CHECKED ( UKismetMathLibrary , Conv_ByteToInt64 ) ) ) ;
CallByteToIntFunction - > AllocateDefaultPins ( ) ;
CompilerContext . MessageLog . NotifyIntermediateObjectCreation ( CallByteToIntFunction , this ) ;
// Move the byte output pin to the input pin of the conversion node
CompilerContext . MovePinLinksToIntermediate ( * ArgumentPin , * CallByteToIntFunction - > FindPinChecked ( TEXT ( " InByte " ) ) ) ;
// Connect the int output pin to the argument value
CallByteToIntFunction - > FindPinChecked ( UEdGraphSchema_K2 : : PN_ReturnValue ) - > MakeLinkTo ( MakeFormatArgumentDataStruct - > FindPinChecked ( GET_MEMBER_NAME_STRING_CHECKED ( FFormatArgumentData , ArgumentValueInt ) ) ) ;
}
else if ( ArgumentPinCategory = = UEdGraphSchema_K2 : : PC_Byte | | ArgumentPinCategory = = UEdGraphSchema_K2 : : PC_Enum )
{
static UEnum * TextGenderEnum = FindObjectChecked < UEnum > ( nullptr , TEXT ( " /Script/Engine.ETextGender " ) , /*ExactClass*/ true ) ;
if ( ArgumentPin - > PinType . PinSubCategoryObject = = TextGenderEnum )
{
MakeFormatArgumentDataStruct - > GetSchema ( ) - > TrySetDefaultValue ( * ArgumentTypePin , TEXT ( " Gender " ) ) ;
CompilerContext . MovePinLinksToIntermediate ( * ArgumentPin , * MakeFormatArgumentDataStruct - > FindPinChecked ( GET_MEMBER_NAME_STRING_CHECKED ( FFormatArgumentData , ArgumentValueGender ) ) ) ;
}
}
else if ( ArgumentPinCategory = = UEdGraphSchema_K2 : : PC_Boolean )
{
AddConversionNode ( GET_MEMBER_NAME_CHECKED ( UKismetTextLibrary , Conv_BoolToText ) , TEXT ( " InBool " ) ) ;
}
else if ( ArgumentPinCategory = = UEdGraphSchema_K2 : : PC_Name )
{
AddConversionNode ( GET_MEMBER_NAME_CHECKED ( UKismetTextLibrary , Conv_NameToText ) , TEXT ( " InName " ) ) ;
}
else if ( ArgumentPinCategory = = UEdGraphSchema_K2 : : PC_String )
{
AddConversionNode ( GET_MEMBER_NAME_CHECKED ( UKismetTextLibrary , Conv_StringToText ) , TEXT ( " InString " ) ) ;
}
else if ( ArgumentPinCategory = = UEdGraphSchema_K2 : : PC_Object )
{
AddConversionNode ( GET_MEMBER_NAME_CHECKED ( UKismetTextLibrary , Conv_ObjectToText ) , TEXT ( " InObj " ) ) ;
}
else
{
// Unexpected pin type!
2024-11-13 18:18:32 -05:00
CompilerContext . MessageLog . Error ( * FText : : Format ( LOCTEXT ( " Error_UnexpectedPinType " , " Pin '{0}' has an unexpected type: {1} " ) , FText : : FromString ( OriginalName ) , FText : : FromName ( ArgumentPinCategory ) ) . ToString ( ) ) ;
2024-10-28 17:40:29 -04:00
}
}
else
{
// No connected pin - just default to an empty text
MakeFormatArgumentDataStruct - > GetSchema ( ) - > TrySetDefaultValue ( * ArgumentTypePin , TEXT ( " Text " ) ) ;
MakeFormatArgumentDataStruct - > GetSchema ( ) - > TrySetDefaultText ( * MakeFormatArgumentDataStruct - > FindPinChecked ( GET_MEMBER_NAME_STRING_CHECKED ( FFormatArgumentData , ArgumentValue ) ) , FText : : GetEmpty ( ) ) ;
}
// The "Make Array" node already has one pin available, so don't create one for ArgIdx == 0
if ( ArgIdx > 0 )
{
MakeArrayNode - > AddInputPin ( ) ;
}
// Find the input pin on the "Make Array" node by index.
const FString PinName = FString : : Printf ( TEXT ( " [%d] " ) , ArgIdx ) ;
UEdGraphPin * InputPin = MakeArrayNode - > FindPinChecked ( PinName ) ;
// Find the output for the pin's "Make Struct" node and link it to the corresponding pin on the "Make Array" node.
FindOutputStructPinChecked ( MakeFormatArgumentDataStruct ) - > MakeLinkTo ( InputPin ) ;
}
// Move connection of RaiseError's "Format" pin to the call function's "InPattern" pin
2024-11-13 18:18:32 -05:00
CompilerContext . MovePinLinksToIntermediate ( * FindPinChecked ( FormatPinName ) , * CallFormatFunction - > FindPinChecked ( TEXT ( " InPattern " ) ) ) ;
2024-10-28 17:40:29 -04:00
2024-11-13 18:18:32 -05:00
// Link up the Exec pins.
CompilerContext . MovePinLinksToIntermediate ( * GetExecPin ( ) , * CallPrintFunction - > GetExecPin ( ) ) ;
CompilerContext . MovePinLinksToIntermediate ( * GetThenPin ( ) , * CallPrintFunction - > GetThenPin ( ) ) ;
2024-10-28 17:40:29 -04:00
BreakAllNodeLinks ( ) ;
}
UK2Node : : ERedirectType UK2Node_RaiseError : : DoPinsMatchForReconstruction ( const UEdGraphPin * NewPin , int32 NewPinIndex , const UEdGraphPin * OldPin , int32 OldPinIndex ) const
{
ERedirectType RedirectType = ERedirectType_None ;
// if the pin names do match
if ( NewPin - > PinName . ToString ( ) . Equals ( OldPin - > PinName . ToString ( ) , ESearchCase : : CaseSensitive ) )
{
// Make sure we're not dealing with a menu node
UEdGraph * OuterGraph = GetGraph ( ) ;
if ( OuterGraph & & OuterGraph - > Schema )
{
const UEdGraphSchema_K2 * K2Schema = Cast < const UEdGraphSchema_K2 > ( GetSchema ( ) ) ;
if ( ! K2Schema | | K2Schema - > IsSelfPin ( * NewPin ) | | K2Schema - > ArePinTypesCompatible ( OldPin - > PinType , NewPin - > PinType ) )
{
RedirectType = ERedirectType_Name ;
}
else
{
RedirectType = ERedirectType_None ;
}
}
}
else
{
// try looking for a redirect if it's a K2 node
if ( UK2Node * Node = Cast < UK2Node > ( NewPin - > GetOwningNode ( ) ) )
{
// if you don't have matching pin, now check if there is any redirect param set
TArray < FString > OldPinNames ;
GetRedirectPinNames ( * OldPin , OldPinNames ) ;
FName NewPinName ;
RedirectType = ShouldRedirectParam ( OldPinNames , /*out*/ NewPinName , Node ) ;
// make sure they match
if ( ( RedirectType ! = ERedirectType_None ) & & ( ! NewPin - > PinName . ToString ( ) . Equals ( NewPinName . ToString ( ) , ESearchCase : : CaseSensitive ) ) )
{
RedirectType = ERedirectType_None ;
}
}
}
return RedirectType ;
}
bool UK2Node_RaiseError : : IsConnectionDisallowed ( const UEdGraphPin * MyPin , const UEdGraphPin * OtherPin , FString & OutReason ) const
{
// The format pin cannot be connected to anything. It must be a constant string.
2024-11-11 19:20:13 -05:00
if ( IsFormatPin ( MyPin ) )
{
2024-10-28 17:40:29 -04:00
OutReason = LOCTEXT ( " Error_FormatStringMustBeHardwired " , " Format string must be a hardwired constant. " ) . ToString ( ) ;
return true ;
}
2024-11-11 19:20:13 -05:00
// Argument input pins may only be connected to Byte, Integer, Float, Text, and ETextGender pins...
if ( IsArgumentPin ( MyPin ) )
2024-10-28 17:40:29 -04:00
{
const UEdGraphSchema_K2 * K2Schema = Cast < const UEdGraphSchema_K2 > ( GetSchema ( ) ) ;
const FName & OtherPinCategory = OtherPin - > PinType . PinCategory ;
bool bIsValidType = false ;
if ( OtherPinCategory = = UEdGraphSchema_K2 : : PC_Int | | OtherPinCategory = = UEdGraphSchema_K2 : : PC_Real | | OtherPinCategory = = UEdGraphSchema_K2 : : PC_Text | |
( OtherPinCategory = = UEdGraphSchema_K2 : : PC_Byte & & ! OtherPin - > PinType . PinSubCategoryObject . IsValid ( ) ) | |
OtherPinCategory = = UEdGraphSchema_K2 : : PC_Boolean | | OtherPinCategory = = UEdGraphSchema_K2 : : PC_String | | OtherPinCategory = = UEdGraphSchema_K2 : : PC_Name | | OtherPinCategory = = UEdGraphSchema_K2 : : PC_Object | |
OtherPinCategory = = UEdGraphSchema_K2 : : PC_Wildcard | | OtherPinCategory = = UEdGraphSchema_K2 : : PC_Int64 )
{
bIsValidType = true ;
}
else if ( OtherPinCategory = = UEdGraphSchema_K2 : : PC_Byte | | OtherPinCategory = = UEdGraphSchema_K2 : : PC_Enum )
{
static UEnum * TextGenderEnum = FindObjectChecked < UEnum > ( nullptr , TEXT ( " /Script/Engine.ETextGender " ) , /*ExactClass*/ true ) ;
if ( OtherPin - > PinType . PinSubCategoryObject = = TextGenderEnum )
{
bIsValidType = true ;
}
}
if ( ! bIsValidType )
{
OutReason = LOCTEXT ( " Error_InvalidArgumentType " , " Format arguments may only be Byte, Integer, Int64, Float, Double, Text, String, Name, Boolean, Object, Wildcard or ETextGender. " ) . ToString ( ) ;
return true ;
}
}
return Super : : IsConnectionDisallowed ( MyPin , OtherPin , OutReason ) ;
}
void UK2Node_RaiseError : : GetMenuActions ( FBlueprintActionDatabaseRegistrar & ActionRegistrar ) const
{
// actions get registered under specific object-keys; the idea is that
// actions might have to be updated (or deleted) if their object-key is
// mutated (or removed)... here we use the node's class (so if the node
// type disappears, then the action should go with it)
UClass * ActionKey = GetClass ( ) ;
// to keep from needlessly instantiating a UBlueprintNodeSpawner, first
// check to make sure that the registrar is looking for actions of this type
// (could be regenerating actions for a specific asset, and therefore the
// registrar would only accept actions corresponding to that asset)
if ( ActionRegistrar . IsOpenForRegistration ( ActionKey ) )
{
UBlueprintNodeSpawner * NodeSpawner = UBlueprintNodeSpawner : : Create ( GetClass ( ) ) ;
check ( NodeSpawner ! = nullptr ) ;
ActionRegistrar . AddBlueprintAction ( ActionKey , NodeSpawner ) ;
}
}
FText UK2Node_RaiseError : : GetMenuCategory ( ) const
{
return FEditorCategoryUtils : : GetCommonCategory ( FCommonEditorCategory : : Text ) ;
}
# undef LOCTEXT_NAMESPACE