Files
UnrealEngineUWP/Engine/Source/Editor/BlueprintGraph/Private/K2Node_GetDataTableRow.cpp
marc audy 4320117e97 Copying //UE4/Dev-Framework to //UE4/Dev-Main (Source: //UE4/Dev-Framework [at] 4343008)
#lockdown Nick.Penwarden
#rb
#rnx

============================
  MAJOR FEATURES & CHANGES
============================

Change 4289396 by Marc.Audy

	Fix get data table row result pin not properly updating if it was split.
	#jira UE-62896

Change 4289407 by Marc.Audy

	Don't allow set member input pin to be split at all
	#jira UE-62924

Change 4291871 by Mieszko.Zielinski

	Exporting EnvQueryGenerator_SimpleGrid with AIMODULE_API #UE4

	#jira UE-62697

Change 4292078 by Marc.Audy

	Fix GetDataTableRow title not updating when changing type

	#jira UE-62896

Change 4292770 by Dan.Oconnor

	Interpreter Optimization 7 of N: CPF_ZeroConstructor assigned for struct properties that that are User Defined Structs

Change 4293207 by Dan.Oconnor

	Interpreter Optimization 8 of N: CPF_IsPlainOldData and CPF_NoDestructor assigned for struct properties that that are User Defined Structs

Change 4297023 by Marc.Audy

	Remove dumb returns

Change 4298303 by Dan.Oconnor

	Fix for issues compiling blueprints after changing a UserDefinedStructure

	#jira UE-63002

Change 4301603 by Phillip.Kavan

	Fix incorrect code generation at cook time when Blueprint nativization is enabled for objects instanced through the editor and assigned to an instanced object reference property.

	Change summary:
	- Modified FEmitDefaultValueHelper::HandleSpecialTypes() to emit runtime code to look for an existing instance of a default subobject only if the 'RF_DefaultSubObject' flag is set on the source instance. This works around instances that return 'true' for IsDefaultSubobject() but were not created with CreateDefaultSubobject() (e.g. - instanced in the editor UI).

	#jira UE-62883

Change 4302720 by Dan.Oconnor

	Prevent user from entering 'None' as parameter name on a blueprint function

	#jira UE-63033

Change 4303695 by Fred.Kimberley

	Don't allow the user to attempt to import a csv unless they've specified the rowstruct for datatables or the interpolation for curve tables.

	#jira UE-62856

Change 4304633 by Ben.Zeigler

	#jira UE-63173 Fix crash ending PIE while a level is waiting to load, SetShouldForceUnloadStreamingLevels now actually force unloads levels

Change 4313208 by Dan.Oconnor

	Warn users when the outputs of a node that is pruned are used

	#jira UE-44518

Change 4313339 by Dan.Oconnor

	Interpreter Optimization 9 of N: Mark ubergraph function as final so that calls to it don't need to search the target object

Change 4313652 by Dan.Oconnor

	Don't warn when a non-pure node that is connected only via its exec is orphaned - fixes overzealous warnings EngineTest

	#jira None

Change 4313661 by Dan.Oconnor

	Comment typo fixes

Change 4313729 by Dan.Oconnor

	Avoid crashing when running the help command for the GenerateBlueprintAPICommandlet

	#jira UE-63283

Change 4318175 by Marc.Audy

	PR #5024: Require BlueprintAssignable delegate parameters to be supported by blueprints (Contributed by slonopotamus)
	#jira UE-635250

Change 4318302 by Marc.Audy

	Use define instead of duplicating text

Change 4318681 by Fred.Kimberley

	Don't allow users to try to rename rows to emtpy strings, whitespace only, or names that have invalid characters.

	#jira UE-63058

Change 4318683 by Fred.Kimberley

	Don't reorder the rowmap when removing a row.

	#jira UE-62754

Change 4318686 by Fred.Kimberley

	Get rid of the failed to import message when cancelling the import of a csv or json file.

	#jira UE-62625

Change 4318689 by Fred.Kimberley

	Back out changelist 4281972

Change 4318713 by Marc.Audy

	Validate CommutativeAssociativeBinaryOperator metadata in UHT and also at the K2Node level in case the function changes to an invalid construct later
	#jira UE-60186

Change 4319363 by Dan.Oconnor

	Warnings and errors generated by macro expansion now include a link back to the macro instance that created the suspect nodes

	#jira None

Change 4319559 by Dan.Oconnor

	PR #5028: UE-63225: Use correct source BP when retrieving the tooltip text (Contributed by projectgheist)

	#jira UE-63225

Change 4323740 by Marc.Audy

	Don't crash if an ICH is (somewhat surprisingly) missing
	#jira UE-63305

Change 4328877 by mason.seay

	BP for pin bug

Change 4336999 by Fred.Kimberley

	Unshelved from pending changelist '4299645':

	PR #5003: Changed SendGameplayEvent()'s category from "Abilities" to "Ability" for consistency (Contributed by rlabrecque)


	#jira UE-63067

Change 4337645 by Marc.Audy

	PR #5049: Make GetPlayerControllerID pure (Contributed by KristofMorva)
	#jira UE-63472

Change 4338211 by Phillip.Kavan

	Fix missing backend support for initializing a container variable (including unconnected function output pins) to a default (literal) value term in nativized Blueprint C++ code.

	Change summary:
	- Added a 'CoerceProperty' argument to FBlueprintCompilerCppBackEnd::TermToText() and FEmitHelper::LiteralTerm(). This is passed through as the LHS term's associated property when compiling 'KCST_Assignment' statements.
	- Modified FEmitHelper::LiteralTerm() to emit an initialization list to C++. This occurs when the RHS of a variable assignment statement is a literal container term, which includes the initialization of K2Node_FunctionResult pins to a default (empty) value.
	- Added FBlueprintCompilerCppBackEnd::TermToText() and FEmitHelper::LiteralTerm() methods that accept a struct value for specifying arguments rather than increasing the number of parameters with default values. Modified the implementations to match.

	#jira UE-48397

Change 4338908 by Marc.Audy

	Don't check when fetching world settings from IsPaused as it is already set up to handle it coming back null
	#jira UE-63583

Change 4339262 by Marc.Audy

	Add comments to ERedirectType

Change 4339718 by Mieszko.Zielinski

	Clearing editor world's EnvironmentQueryManager instace's LocalContextMap whenever a BP finished compiling #UE4

	#jira UE-63481

Change 4340548 by Marc.Audy

	ChildActor's need to be spawned from the ChildActorTemplate otherwise any non-replicated  customized properties will be incorrect on the Client.
	#jira UE-63427

Change 4340756 by Marc.Audy

	Don't allow a new pin to be matched twice
	#jira UE-63504

Change 4342704 by mason.seay

	Updated Pin Testing blueprints

Change 4319930 by Marc.Audy

	Mark FPartyState as a BlueprintType

Change 4329176 by Dan.Oconnor

	Add optional message identifier to tokenized message, use message identifier to facilitate suppressing a new warning in the blueprint compiler, remove the unused (and unusable) FTokenizedMiscData

	#jira None

Change 4337859 by Fred.Kimberley

	Fixing misc restricted gameplay tag UI bugs

	#jira UE-63600, UE-63602, UE-63603

#ROBOMERGE-OWNER: jason.bestimt
#ROBOMERGE-SOURCE: CL 4344176 in //UE4/Main/...
#ROBOMERGE-BOT: DEVVR (Main -> Dev-VR)

[CL 4344180 by marc audy in Dev-VR branch]
2018-09-05 09:57:16 -04:00

504 lines
17 KiB
C++

// Copyright 1998-2018 Epic Games, Inc. All Rights Reserved.
#include "K2Node_GetDataTableRow.h"
#include "Engine/DataTable.h"
#include "EdGraphSchema_K2.h"
#include "K2Node_CallFunction.h"
#include "K2Node_IfThenElse.h"
#include "Kismet2/BlueprintEditorUtils.h"
#include "KismetCompiler.h"
#include "DataTableEditorUtils.h"
#include "Kismet/DataTableFunctionLibrary.h"
#include "BlueprintNodeSpawner.h"
#include "EditorCategoryUtils.h"
#include "BlueprintActionDatabaseRegistrar.h"
#define LOCTEXT_NAMESPACE "K2Node_GetDataTableRow"
struct UK2Node_GetDataTableRowHelper
{
static FName DataTablePinName;
static FName RowNamePinName;
static FName RowNotFoundPinName;
};
FName UK2Node_GetDataTableRowHelper::DataTablePinName(*LOCTEXT("DataTablePinName","DataTable").ToString());
FName UK2Node_GetDataTableRowHelper::RowNotFoundPinName(*LOCTEXT("RowNotFoundPinName","RowNotFound").ToString());
FName UK2Node_GetDataTableRowHelper::RowNamePinName(*LOCTEXT("RowNamePinName","RowName").ToString());
UK2Node_GetDataTableRow::UK2Node_GetDataTableRow(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
NodeTooltip = LOCTEXT("NodeTooltip", "Attempts to retrieve a TableRow from a DataTable via it's RowName");
}
void UK2Node_GetDataTableRow::AllocateDefaultPins()
{
const UEdGraphSchema_K2* K2Schema = GetDefault<UEdGraphSchema_K2>();
// Add execution pins
CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Exec, UEdGraphSchema_K2::PN_Execute);
UEdGraphPin* RowFoundPin = CreatePin(EGPD_Output, UEdGraphSchema_K2::PC_Exec, UEdGraphSchema_K2::PN_Then);
RowFoundPin->PinFriendlyName = LOCTEXT("GetDataTableRow Row Found Exec pin", "Row Found");
CreatePin(EGPD_Output, UEdGraphSchema_K2::PC_Exec, UK2Node_GetDataTableRowHelper::RowNotFoundPinName);
// Add DataTable pin
UEdGraphPin* DataTablePin = CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Object, UDataTable::StaticClass(), UK2Node_GetDataTableRowHelper::DataTablePinName);
SetPinToolTip(*DataTablePin, LOCTEXT("DataTablePinDescription", "The DataTable you want to retreive a row from"));
// Row Name pin
UEdGraphPin* RowNamePin = CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Name, UK2Node_GetDataTableRowHelper::RowNamePinName);
SetPinToolTip(*RowNamePin, LOCTEXT("RowNamePinDescription", "The name of the row to retrieve from the DataTable"));
// Result pin
UEdGraphPin* ResultPin = CreatePin(EGPD_Output, UEdGraphSchema_K2::PC_Wildcard, UEdGraphSchema_K2::PN_ReturnValue);
ResultPin->PinFriendlyName = LOCTEXT("GetDataTableRow Output Row", "Out Row");
SetPinToolTip(*ResultPin, LOCTEXT("ResultPinDescription", "The returned TableRow, if found"));
Super::AllocateDefaultPins();
}
void UK2Node_GetDataTableRow::SetPinToolTip(UEdGraphPin& MutatablePin, const FText& PinDescription) const
{
MutatablePin.PinToolTip = UEdGraphSchema_K2::TypeToText(MutatablePin.PinType).ToString();
UEdGraphSchema_K2 const* const K2Schema = Cast<const UEdGraphSchema_K2>(GetSchema());
if (K2Schema != nullptr)
{
MutatablePin.PinToolTip += TEXT(" ");
MutatablePin.PinToolTip += K2Schema->GetPinDisplayName(&MutatablePin).ToString();
}
MutatablePin.PinToolTip += FString(TEXT("\n")) + PinDescription.ToString();
}
void UK2Node_GetDataTableRow::RefreshOutputPinType()
{
UScriptStruct* OutputType = GetDataTableRowStructType();
SetReturnTypeForStruct(OutputType);
}
void UK2Node_GetDataTableRow::RefreshRowNameOptions()
{
// When the DataTable pin gets a new value assigned, we need to update the Slate UI so that SGraphNodeCallParameterCollectionFunction will update the ParameterName drop down
UEdGraph* Graph = GetGraph();
Graph->NotifyGraphChanged();
}
void UK2Node_GetDataTableRow::SetReturnTypeForStruct(UScriptStruct* NewRowStruct)
{
UScriptStruct* OldRowStruct = GetReturnTypeForStruct();
if (NewRowStruct != OldRowStruct)
{
UEdGraphPin* ResultPin = GetResultPin();
if (ResultPin->SubPins.Num() > 0)
{
GetSchema()->RecombinePin(ResultPin);
}
// NOTE: purposefully not disconnecting the ResultPin (even though it changed type)... we want the user to see the old
// connections, and incompatible connections will produce an error (plus, some super-struct connections may still be valid)
ResultPin->PinType.PinSubCategoryObject = NewRowStruct;
ResultPin->PinType.PinCategory = (NewRowStruct == nullptr) ? UEdGraphSchema_K2::PC_Wildcard : UEdGraphSchema_K2::PC_Struct;
CachedNodeTitle.Clear();
}
}
UScriptStruct* UK2Node_GetDataTableRow::GetReturnTypeForStruct()
{
UScriptStruct* ReturnStructType = (UScriptStruct*)(GetResultPin()->PinType.PinSubCategoryObject.Get());
return ReturnStructType;
}
UScriptStruct* UK2Node_GetDataTableRow::GetDataTableRowStructType() const
{
UScriptStruct* RowStructType = nullptr;
UEdGraphPin* DataTablePin = GetDataTablePin();
if(DataTablePin && DataTablePin->DefaultObject != nullptr && DataTablePin->LinkedTo.Num() == 0)
{
if (DataTablePin->DefaultObject->IsA(UDataTable::StaticClass()))
{
UDataTable* DataTable = (UDataTable*)DataTablePin->DefaultObject;
if (DataTable)
{
RowStructType = DataTable->RowStruct;
}
}
}
if (RowStructType == nullptr)
{
UEdGraphPin* ResultPin = GetResultPin();
if (ResultPin && ResultPin->LinkedTo.Num() > 0)
{
RowStructType = Cast<UScriptStruct>(ResultPin->LinkedTo[0]->PinType.PinSubCategoryObject.Get());
for (int32 LinkIndex = 1; LinkIndex < ResultPin->LinkedTo.Num(); ++LinkIndex)
{
UEdGraphPin* Link = ResultPin->LinkedTo[LinkIndex];
UScriptStruct* LinkType = Cast<UScriptStruct>(Link->PinType.PinSubCategoryObject.Get());
if (RowStructType->IsChildOf(LinkType))
{
RowStructType = LinkType;
}
}
}
}
return RowStructType;
}
void UK2Node_GetDataTableRow::OnDataTableRowListChanged(const UDataTable* DataTable)
{
UEdGraphPin* DataTablePin = GetDataTablePin();
if (DataTable && DataTablePin && DataTable == DataTablePin->DefaultObject)
{
UEdGraphPin* RowNamePin = GetRowNamePin();
const bool TryRefresh = RowNamePin && !RowNamePin->LinkedTo.Num();
const FName CurrentName = RowNamePin ? FName(*RowNamePin->GetDefaultAsString()) : NAME_None;
if (TryRefresh && RowNamePin && !DataTable->GetRowNames().Contains(CurrentName))
{
if (UBlueprint* BP = GetBlueprint())
{
FBlueprintEditorUtils::MarkBlueprintAsModified(BP);
}
}
}
}
void UK2Node_GetDataTableRow::ReallocatePinsDuringReconstruction(TArray<UEdGraphPin*>& OldPins)
{
Super::ReallocatePinsDuringReconstruction(OldPins);
if (UEdGraphPin* DataTablePin = GetDataTablePin(&OldPins))
{
if (UDataTable* DataTable = Cast<UDataTable>(DataTablePin->DefaultObject))
{
// make sure to properly load the data-table object so that we can
// farm the "RowStruct" property from it (below, in GetDataTableRowStructType)
PreloadObject(DataTable);
}
}
}
void UK2Node_GetDataTableRow::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_GetDataTableRow::GetMenuCategory() const
{
return FEditorCategoryUtils::GetCommonCategory(FCommonEditorCategory::Utilities);
}
bool UK2Node_GetDataTableRow::IsConnectionDisallowed(const UEdGraphPin* MyPin, const UEdGraphPin* OtherPin, FString& OutReason) const
{
if (MyPin == GetResultPin() && MyPin->PinType.PinCategory == UEdGraphSchema_K2::PC_Wildcard)
{
bool bDisallowed = true;
if (OtherPin->PinType.PinCategory == UEdGraphSchema_K2::PC_Struct)
{
if (UScriptStruct* ConnectionType = Cast<UScriptStruct>(OtherPin->PinType.PinSubCategoryObject.Get()))
{
bDisallowed = !FDataTableEditorUtils::IsValidTableStruct(ConnectionType);
}
}
else if (OtherPin->PinType.PinCategory == UEdGraphSchema_K2::PC_Wildcard)
{
bDisallowed = false;
}
if (bDisallowed)
{
OutReason = TEXT("Must be a struct that can be used in a DataTable");
}
return bDisallowed;
}
return false;
}
void UK2Node_GetDataTableRow::PinDefaultValueChanged(UEdGraphPin* ChangedPin)
{
if (ChangedPin && ChangedPin->PinName == UK2Node_GetDataTableRowHelper::DataTablePinName)
{
RefreshOutputPinType();
UEdGraphPin* RowNamePin = GetRowNamePin();
UDataTable* DataTable = Cast<UDataTable>(ChangedPin->DefaultObject);
if (RowNamePin)
{
if (DataTable && (RowNamePin->DefaultValue.IsEmpty() || !DataTable->RowMap.Contains(*RowNamePin->DefaultValue)))
{
if (auto Iterator = DataTable->RowMap.CreateConstIterator())
{
RowNamePin->DefaultValue = Iterator.Key().ToString();
}
}
RefreshRowNameOptions();
}
}
}
FText UK2Node_GetDataTableRow::GetTooltipText() const
{
return NodeTooltip;
}
UEdGraphPin* UK2Node_GetDataTableRow::GetThenPin()const
{
const UEdGraphSchema_K2* K2Schema = GetDefault<UEdGraphSchema_K2>();
UEdGraphPin* Pin = FindPinChecked(UEdGraphSchema_K2::PN_Then);
check(Pin->Direction == EGPD_Output);
return Pin;
}
UEdGraphPin* UK2Node_GetDataTableRow::GetDataTablePin(const TArray<UEdGraphPin*>* InPinsToSearch /*= NULL*/) const
{
const TArray<UEdGraphPin*>* PinsToSearch = InPinsToSearch ? InPinsToSearch : &Pins;
UEdGraphPin* Pin = nullptr;
for (UEdGraphPin* TestPin : *PinsToSearch)
{
if (TestPin && TestPin->PinName == UK2Node_GetDataTableRowHelper::DataTablePinName)
{
Pin = TestPin;
break;
}
}
check(Pin == nullptr || Pin->Direction == EGPD_Input);
return Pin;
}
UEdGraphPin* UK2Node_GetDataTableRow::GetRowNamePin() const
{
UEdGraphPin* Pin = FindPinChecked(UK2Node_GetDataTableRowHelper::RowNamePinName);
check(Pin->Direction == EGPD_Input);
return Pin;
}
UEdGraphPin* UK2Node_GetDataTableRow::GetRowNotFoundPin() const
{
UEdGraphPin* Pin = FindPinChecked(UK2Node_GetDataTableRowHelper::RowNotFoundPinName);
check(Pin->Direction == EGPD_Output);
return Pin;
}
UEdGraphPin* UK2Node_GetDataTableRow::GetResultPin() const
{
const UEdGraphSchema_K2* K2Schema = GetDefault<UEdGraphSchema_K2>();
UEdGraphPin* Pin = FindPinChecked(UEdGraphSchema_K2::PN_ReturnValue);
check(Pin->Direction == EGPD_Output);
return Pin;
}
FText UK2Node_GetDataTableRow::GetNodeTitle(ENodeTitleType::Type TitleType) const
{
if (TitleType == ENodeTitleType::MenuTitle)
{
return LOCTEXT("ListViewTitle", "Get Data Table Row");
}
else if (UEdGraphPin* DataTablePin = GetDataTablePin())
{
if (DataTablePin->LinkedTo.Num() > 0)
{
return NSLOCTEXT("K2Node", "DataTable_Title_Unknown", "Get Data Table Row");
}
else if (DataTablePin->DefaultObject == nullptr)
{
return NSLOCTEXT("K2Node", "DataTable_Title_None", "Get Data Table Row NONE");
}
else if (CachedNodeTitle.IsOutOfDate(this))
{
FFormatNamedArguments Args;
Args.Add(TEXT("DataTableName"), FText::FromString(DataTablePin->DefaultObject->GetName()));
FText LocFormat = NSLOCTEXT("K2Node", "DataTable", "Get Data Table Row {DataTableName}");
// FText::Format() is slow, so we cache this to save on performance
CachedNodeTitle.SetCachedText(FText::Format(LocFormat, Args), this);
}
}
else
{
return NSLOCTEXT("K2Node", "DataTable_Title_None", "Get Data Table Row NONE");
}
return CachedNodeTitle;
}
void UK2Node_GetDataTableRow::ExpandNode(class FKismetCompilerContext& CompilerContext, UEdGraph* SourceGraph)
{
Super::ExpandNode(CompilerContext, SourceGraph);
UEdGraphPin* OriginalDataTableInPin = GetDataTablePin();
UDataTable* Table = (OriginalDataTableInPin != NULL) ? Cast<UDataTable>(OriginalDataTableInPin->DefaultObject) : NULL;
if((nullptr == OriginalDataTableInPin) || (0 == OriginalDataTableInPin->LinkedTo.Num() && nullptr == Table))
{
CompilerContext.MessageLog.Error(*LOCTEXT("GetDataTableRowNoDataTable_Error", "GetDataTableRow must have a DataTable specified.").ToString(), this);
// we break exec links so this is the only error we get
BreakAllNodeLinks();
return;
}
// FUNCTION NODE
const FName FunctionName = GET_FUNCTION_NAME_CHECKED(UDataTableFunctionLibrary, GetDataTableRowFromName);
UK2Node_CallFunction* GetDataTableRowFunction = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this, SourceGraph);
GetDataTableRowFunction->FunctionReference.SetExternalMember(FunctionName, UDataTableFunctionLibrary::StaticClass());
GetDataTableRowFunction->AllocateDefaultPins();
CompilerContext.MovePinLinksToIntermediate(*GetExecPin(), *(GetDataTableRowFunction->GetExecPin()));
// Connect the input of our GetDataTableRow to the Input of our Function pin
UEdGraphPin* DataTableInPin = GetDataTableRowFunction->FindPinChecked(TEXT("Table"));
if(OriginalDataTableInPin->LinkedTo.Num() > 0)
{
// Copy the connection
CompilerContext.MovePinLinksToIntermediate(*OriginalDataTableInPin, *DataTableInPin);
}
else
{
// Copy literal
DataTableInPin->DefaultObject = OriginalDataTableInPin->DefaultObject;
}
UEdGraphPin* RowNameInPin = GetDataTableRowFunction->FindPinChecked(TEXT("RowName"));
CompilerContext.MovePinLinksToIntermediate(*GetRowNamePin(), *RowNameInPin);
// Get some pins to work with
UEdGraphPin* OriginalOutRowPin = FindPinChecked(UEdGraphSchema_K2::PN_ReturnValue);
UEdGraphPin* FunctionOutRowPin = GetDataTableRowFunction->FindPinChecked(TEXT("OutRow"));
UEdGraphPin* FunctionReturnPin = GetDataTableRowFunction->FindPinChecked(UEdGraphSchema_K2::PN_ReturnValue);
UEdGraphPin* FunctionThenPin = GetDataTableRowFunction->GetThenPin();
// Set the type of the OutRow pin on this expanded mode to match original
FunctionOutRowPin->PinType = OriginalOutRowPin->PinType;
FunctionOutRowPin->PinType.PinSubCategoryObject = OriginalOutRowPin->PinType.PinSubCategoryObject;
//BRANCH NODE
UK2Node_IfThenElse* BranchNode = CompilerContext.SpawnIntermediateNode<UK2Node_IfThenElse>(this, SourceGraph);
BranchNode->AllocateDefaultPins();
// Hook up inputs to branch
FunctionThenPin->MakeLinkTo(BranchNode->GetExecPin());
FunctionReturnPin->MakeLinkTo(BranchNode->GetConditionPin());
// Hook up outputs
CompilerContext.MovePinLinksToIntermediate(*GetThenPin(), *(BranchNode->GetThenPin()));
CompilerContext.MovePinLinksToIntermediate(*GetRowNotFoundPin(), *(BranchNode->GetElsePin()));
CompilerContext.MovePinLinksToIntermediate(*OriginalOutRowPin, *FunctionOutRowPin);
BreakAllNodeLinks();
}
FSlateIcon UK2Node_GetDataTableRow::GetIconAndTint(FLinearColor& OutColor) const
{
OutColor = GetNodeTitleColor();
static FSlateIcon Icon("EditorStyle", "Kismet.AllClasses.FunctionIcon");
return Icon;
}
void UK2Node_GetDataTableRow::PostReconstructNode()
{
Super::PostReconstructNode();
RefreshOutputPinType();
}
void UK2Node_GetDataTableRow::EarlyValidation(class FCompilerResultsLog& MessageLog) const
{
Super::EarlyValidation(MessageLog);
const UEdGraphPin* DataTablePin = GetDataTablePin();
const UEdGraphPin* RowNamePin = GetRowNamePin();
if (!DataTablePin || !RowNamePin)
{
MessageLog.Error(*LOCTEXT("MissingPins", "Missing pins in @@").ToString(), this);
return;
}
if (DataTablePin->LinkedTo.Num() == 0)
{
const UDataTable* DataTable = Cast<UDataTable>(DataTablePin->DefaultObject);
if (!DataTable)
{
MessageLog.Error(*LOCTEXT("NoDataTable", "No DataTable in @@").ToString(), this);
return;
}
if (!RowNamePin->LinkedTo.Num())
{
const FName CurrentName = FName(*RowNamePin->GetDefaultAsString());
if (!DataTable->GetRowNames().Contains(CurrentName))
{
const FString Msg = FText::Format(
LOCTEXT("WrongRowNameFmt", "'{0}' row name is not stored in '{1}'. @@"),
FText::FromString(CurrentName.ToString()),
FText::FromString(GetFullNameSafe(DataTable))
).ToString();
MessageLog.Error(*Msg, this);
return;
}
}
}
}
void UK2Node_GetDataTableRow::PreloadRequiredAssets()
{
if (UEdGraphPin* DataTablePin = GetDataTablePin())
{
if (UDataTable* DataTable = Cast<UDataTable>(DataTablePin->DefaultObject))
{
// make sure to properly load the data-table object so that we can
// farm the "RowStruct" property from it (below, in GetDataTableRowStructType)
PreloadObject(DataTable);
}
}
return Super::PreloadRequiredAssets();
}
void UK2Node_GetDataTableRow::NotifyPinConnectionListChanged(UEdGraphPin* Pin)
{
Super::NotifyPinConnectionListChanged(Pin);
if (Pin == GetResultPin())
{
UEdGraphPin* TablePin = GetDataTablePin();
// this connection would only change the output type if the table pin is undefined
const bool bIsTypeAuthority = (TablePin->LinkedTo.Num() > 0 || TablePin->DefaultObject == nullptr);
if (bIsTypeAuthority)
{
RefreshOutputPinType();
}
}
else if (Pin == GetDataTablePin())
{
const bool bConnectionAdded = Pin->LinkedTo.Num() > 0;
if (bConnectionAdded)
{
// if a connection was made, then we may need to rid ourselves of the row dropdown
RefreshRowNameOptions();
// if the output connection was previously, incompatible, it now becomes the authority on this node's output type
RefreshOutputPinType();
}
}
}
#undef LOCTEXT_NAMESPACE