Files
Brandyn / Techy fcc1b09210 init
2026-04-04 15:40:51 -05:00

349 lines
12 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "NiagaraNodeIf.h"
#include "NiagaraEditorUtilities.h"
#include "NiagaraHlslTranslator.h"
#include UE_INLINE_GENERATED_CPP_BY_NAME(NiagaraNodeIf)
#define LOCTEXT_NAMESPACE "NiagaraNodeIf"
const FString UNiagaraNodeIf::InputTruePinSuffix(" if True");
const FString UNiagaraNodeIf::InputFalsePinSuffix(" if False");
const FName UNiagaraNodeIf::ConditionPinName("Condition");
UNiagaraNodeIf::UNiagaraNodeIf(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
}
void UNiagaraNodeIf::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent)
{
// @TODO why do we need to have this post-change property here at all?
// Doing a null check b/c otherwise if doing a Duplicate via Ctrl-W, we die inside AllocateDefaultPins due to
// the point where we get this call not being completely formed.
if (PropertyChangedEvent.Property != nullptr)
{
ReallocatePins();
}
}
void UNiagaraNodeIf::PostLoad()
{
Super::PostLoad();
if (PathAssociatedPinGuids.Num() != OutputVars.Num())
{
PathAssociatedPinGuids.SetNum(OutputVars.Num());
}
auto LoadGuid = [&](FGuid& Guid, const FString& Name, const EEdGraphPinDirection Direction, const FString* LegacyName = nullptr)
{
UEdGraphPin* Pin = FindPin(Name, Direction);
if ( Pin == nullptr && LegacyName != nullptr )
{
Pin = FindPin(*LegacyName, Direction);
if (Pin)
{
Pin->PinName = FName(*Name);
}
}
if (Pin)
{
if (!Pin->PersistentGuid.IsValid())
{
Pin->PersistentGuid = FGuid::NewGuid();
}
Guid = Pin->PersistentGuid;
}
else
{
UE_LOG(LogNiagaraEditor, Error, TEXT("Unable to find output pin named %s"), *Name);
}
};
LoadGuid(ConditionPinGuid, ConditionPinName.ToString(), EGPD_Input);
for (int32 i = 0; i < OutputVars.Num(); i++)
{
const FString VarName = OutputVars[i].GetName().ToString();
LoadGuid(PathAssociatedPinGuids[i].OutputPinGuid, VarName, EGPD_Output);
const FString InputTrueName = VarName + InputTruePinSuffix;
const FString LegacyInputTrueName = VarName + TEXT(" A");
LoadGuid(PathAssociatedPinGuids[i].InputTruePinGuid, InputTrueName, EGPD_Input, &LegacyInputTrueName);
const FString InputFalseName = VarName + InputFalsePinSuffix;
const FString LegacyInputFalseName = VarName + TEXT(" B");
LoadGuid(PathAssociatedPinGuids[i].InputFalsePinGuid, InputFalseName, EGPD_Input, &LegacyInputFalseName);
}
}
bool UNiagaraNodeIf::AllowNiagaraTypeForAddPin(const FNiagaraTypeDefinition& InType) const
{
// Explicitly allow Numeric types, and explicitly disallow ParameterMap types
return (Super::AllowNiagaraTypeForAddPin(InType) || InType == FNiagaraTypeDefinition::GetGenericNumericDef()) && InType != FNiagaraTypeDefinition::GetParameterMapDef();
}
void UNiagaraNodeIf::AllocateDefaultPins()
{
const UEdGraphSchema_Niagara* Schema = GetDefault<UEdGraphSchema_Niagara>();
//Add the condition pin.
UEdGraphPin* ConditionPin = CreatePin(EGPD_Input, Schema->TypeDefinitionToPinType(FNiagaraTypeDefinition::GetBoolDef()), ConditionPinName);
UNiagaraNode::SetPinDefaultToTypeDefaultIfUnset(ConditionPin);
ConditionPin->PersistentGuid = ConditionPinGuid;
//Create the inputs for each path.
for (int32 Index = 0; Index < OutputVars.Num(); Index++)
{
const FNiagaraVariable& Var = OutputVars[Index];
UEdGraphPin* NewPin = CreatePin(EGPD_Input, Schema->TypeDefinitionToPinType(Var.GetType()), *(Var.GetName().ToString() + InputTruePinSuffix));
UNiagaraNode::SetPinDefaultToTypeDefaultIfUnset(NewPin);
NewPin->PersistentGuid = PathAssociatedPinGuids[Index].InputTruePinGuid;
}
for (int32 Index = 0; Index < OutputVars.Num(); Index++)
{
const FNiagaraVariable& Var = OutputVars[Index];
UEdGraphPin* NewPin = CreatePin(EGPD_Input, Schema->TypeDefinitionToPinType(Var.GetType()), *(Var.GetName().ToString() + InputFalsePinSuffix));
UNiagaraNode::SetPinDefaultToTypeDefaultIfUnset(NewPin);
NewPin->PersistentGuid = PathAssociatedPinGuids[Index].InputFalsePinGuid;
}
for (int32 Index = 0; Index < OutputVars.Num(); Index++)
{
const FNiagaraVariable& Var = OutputVars[Index];
UEdGraphPin* NewPin = CreatePin(EGPD_Output, Schema->TypeDefinitionToPinType(Var.GetType()), Var.GetName());
NewPin->PersistentGuid = PathAssociatedPinGuids[Index].OutputPinGuid;
}
CreateAddPin(EGPD_Output);
}
void UNiagaraNodeIf::Compile(FTranslator* Translator, TArray<int32>& Outputs) const
{
checkSlow(PathAssociatedPinGuids.Num() == OutputVars.Num());
const UEdGraphSchema_Niagara* Schema = CastChecked<UEdGraphSchema_Niagara>(GetSchema());
int32 Condition = Translator->CompileInputPin(GetPinByGuid(ConditionPinGuid));
TArray<int32> PathTrue;
PathTrue.Reserve(PathAssociatedPinGuids.Num());
for (const FPinGuidsForPath& PerPathAssociatedPinGuids : PathAssociatedPinGuids)
{
const UEdGraphPin* InputTruePin = GetPinByGuid(PerPathAssociatedPinGuids.InputTruePinGuid);
if (Schema->PinToTypeDefinition(InputTruePin) == FNiagaraTypeDefinition::GetParameterMapDef())
{
Translator->Error(LOCTEXT("UnsupportedParamMapInIf", "Parameter maps are not supported in if nodes."), this, InputTruePin);
}
PathTrue.Add(Translator->CompileInputPin(InputTruePin));
}
TArray<int32> PathFalse;
PathFalse.Reserve(PathAssociatedPinGuids.Num());
for (const FPinGuidsForPath& PerPathAssociatedPinGuids : PathAssociatedPinGuids)
{
const UEdGraphPin* InputFalsePin = GetPinByGuid(PerPathAssociatedPinGuids.InputFalsePinGuid);
if (Schema->PinToTypeDefinition(InputFalsePin) == FNiagaraTypeDefinition::GetParameterMapDef())
{
Translator->Error(LOCTEXT("UnsupportedParamMapInIf", "Parameter maps are not supported in if nodes."), this, InputFalsePin);
}
PathFalse.Add(Translator->CompileInputPin(InputFalsePin));
}
Translator->If(this, OutputVars, Condition, PathTrue, PathFalse, Outputs);
}
ENiagaraNumericOutputTypeSelectionMode UNiagaraNodeIf::GetNumericOutputTypeSelectionMode() const
{
return ENiagaraNumericOutputTypeSelectionMode::Largest;
}
void UNiagaraNodeIf::ResolveNumerics(const UEdGraphSchema_Niagara* Schema, bool bSetInline, TMap<TPair<FGuid, UEdGraphNode*>, FNiagaraTypeDefinition>* PinCache)
{
int32 VarStartIdx = 1;
for (int32 i = 0; i < OutputVars.Num(); ++i)
{
// Fix up numeric input pins and keep track of numeric types to decide the output type.
TArray<UEdGraphPin*> InputPins;
TArray<UEdGraphPin*> OutputPins;
InputPins.Add(Pins[i + VarStartIdx]);
InputPins.Add(Pins[i + VarStartIdx + OutputVars.Num()]);
OutputPins.Add(Pins[i + VarStartIdx + 2 * OutputVars.Num()]);
NumericResolutionByPins(Schema, InputPins, OutputPins, bSetInline, PinCache);
}
}
bool UNiagaraNodeIf::AllowExternalPinTypeChanges(const UEdGraphPin* InGraphPin) const
{
// only allow pin changes for output pins
if (InGraphPin->Direction == EGPD_Output)
{
return true;
}
return false;
}
bool UNiagaraNodeIf::AllowNiagaraTypeForPinTypeChange(const FNiagaraTypeDefinition& InType, UEdGraphPin* Pin) const
{
return InType.GetScriptStruct() != nullptr
&& InType != FNiagaraTypeDefinition::GetGenericNumericDef()
&& !InType.IsInternalType();
}
bool UNiagaraNodeIf::OnNewPinTypeRequested(UEdGraphPin* PinToChange, FNiagaraTypeDefinition NewType)
{
if (PinToChange->Direction == EGPD_Output)
{
ChangeOutputType(PinToChange, NewType);
return true;
}
return false;
}
bool UNiagaraNodeIf::RefreshFromExternalChanges()
{
// TODO - Leverage code in reallocate pins to determine if any pins have changed...
ReallocatePins();
return true;
}
FGuid UNiagaraNodeIf::AddOutput(FNiagaraTypeDefinition Type, const FName& Name)
{
FPinGuidsForPath& NewPinGuidsForPath = PathAssociatedPinGuids.Add_GetRef(FPinGuidsForPath());
FNiagaraVariable NewOutput(Type, Name);
OutputVars.Add(NewOutput);
FGuid Guid = FGuid::NewGuid();
NewPinGuidsForPath.OutputPinGuid = Guid;
const UEdGraphSchema_Niagara* Schema = CastChecked<UEdGraphSchema_Niagara>(GetSchema());
FGuid PinTrueGuid = FGuid::NewGuid();
UEdGraphPin* PinTrue = CreatePin(EGPD_Input, Schema->TypeDefinitionToPinType(Type), *(Name.ToString() + InputTruePinSuffix), PathAssociatedPinGuids.Num());
PinTrue->PersistentGuid = PinTrueGuid;
UNiagaraNode::SetPinDefaultToTypeDefaultIfUnset(PinTrue);
NewPinGuidsForPath.InputTruePinGuid = PinTrueGuid;
FGuid PinFalseGuid = FGuid::NewGuid();
UEdGraphPin* PinFalse = CreatePin(EGPD_Input, Schema->TypeDefinitionToPinType(Type), *(Name.ToString() + InputFalsePinSuffix), PathAssociatedPinGuids.Num() * 2);
PinFalse->PersistentGuid = PinFalseGuid;
UNiagaraNode::SetPinDefaultToTypeDefaultIfUnset(PinFalse);
NewPinGuidsForPath.InputFalsePinGuid = PinFalseGuid;
return Guid;
}
void UNiagaraNodeIf::ChangeOutputType(UEdGraphPin* OutputPin, FNiagaraTypeDefinition TypeDefinition)
{
for (int32 i = 0; i < PathAssociatedPinGuids.Num(); i++)
{
const FPinGuidsForPath& PinGuids = PathAssociatedPinGuids[i];
if (PinGuids.OutputPinGuid == OutputPin->PersistentGuid)
{
TSet<FName> OutputNames;
for (const FNiagaraVariable& Output : OutputVars)
{
OutputNames.Add(Output.GetName());
}
FName OutputName = FNiagaraUtilities::GetUniqueName(*TypeDefinition.GetNameText().ToString(), OutputNames);
// replace the old var with a new one at the same index, so the matchup between IDs and vars is still the same
OutputVars[i] = FNiagaraVariable(TypeDefinition, OutputName);
GetPinByPersistentGuid(PinGuids.InputTruePinGuid)->bOrphanedPin = true;
GetPinByPersistentGuid(PinGuids.InputFalsePinGuid)->bOrphanedPin = true;
OutputPin->bOrphanedPin = true;
ReallocatePins(true);
return;
}
}
}
const UEdGraphPin* UNiagaraNodeIf::GetPinByGuid(const FGuid& InGuid) const
{
UEdGraphPin* FoundPin = *Pins.FindByPredicate([&InGuid](const UEdGraphPin* Pin) { return Pin->PersistentGuid == InGuid; });
checkf(FoundPin != nullptr, TEXT("Failed to get pin by cached Guid!"));
return FoundPin;
}
void UNiagaraNodeIf::OnPinRemoved(UEdGraphPin* PinToRemove)
{
auto FindByOutputPinGuidPredicate = [=](const FPinGuidsForPath& PerPinGuidsForPath) { return PerPinGuidsForPath.OutputPinGuid == PinToRemove->PersistentGuid && PinToRemove->bOrphanedPin == false; };
int32 FoundIndex = PathAssociatedPinGuids.IndexOfByPredicate(FindByOutputPinGuidPredicate);
if (FoundIndex != INDEX_NONE)
{
OutputVars.RemoveAt(FoundIndex);
PathAssociatedPinGuids.RemoveAt(FoundIndex);
}
ReallocatePins();
}
void UNiagaraNodeIf::OnNewTypedPinAdded(UEdGraphPin*& NewPin)
{
Super::OnNewTypedPinAdded(NewPin);
const UEdGraphSchema_Niagara* Schema = GetDefault<UEdGraphSchema_Niagara>();
FNiagaraTypeDefinition OutputType = Schema->PinToTypeDefinition(NewPin);
TSet<FName> OutputNames;
for (const FNiagaraVariable& Output : OutputVars)
{
OutputNames.Add(Output.GetName());
}
FName OutputName = FNiagaraUtilities::GetUniqueName(*OutputType.GetNameText().ToString(), OutputNames);
FGuid Guid = AddOutput(OutputType, OutputName);
// Update the pin's data too so that it's connection is maintained after reallocating.
NewPin->PinName = OutputName;
NewPin->PersistentGuid = Guid;
}
void UNiagaraNodeIf::OnPinRenamed(UEdGraphPin* RenamedPin, const FString& OldName)
{
auto FindByOutputPinGuidPredicate = [=](const FPinGuidsForPath& PerPinGuidsForPath) { return PerPinGuidsForPath.OutputPinGuid == RenamedPin->PersistentGuid; };
int32 FoundIndex = PathAssociatedPinGuids.IndexOfByPredicate(FindByOutputPinGuidPredicate);
if(FoundIndex != INDEX_NONE)
{
TSet<FName> OutputNames;
for (int32 Index = 0; Index < OutputVars.Num(); Index++)
{
if (FoundIndex != Index)
{
OutputNames.Add(OutputVars[Index].GetName());
}
}
const FName OutputName = FNiagaraUtilities::GetUniqueName(RenamedPin->PinName, OutputNames);
OutputVars[FoundIndex].SetName(OutputName);
}
ReallocatePins();
}
bool UNiagaraNodeIf::CanRenamePin(const UEdGraphPin* Pin) const
{
return Super::CanRenamePin(Pin) && Pin->Direction == EGPD_Output;
}
bool UNiagaraNodeIf::CanRemovePin(const UEdGraphPin* Pin) const
{
return Super::CanRemovePin(Pin) && Pin->Direction == EGPD_Output;
}
FText UNiagaraNodeIf::GetTooltipText() const
{
return LOCTEXT("IfDesc", "If Condition is true, the output value will be the True pin, otherwise output will be the False pin.");
}
FText UNiagaraNodeIf::GetNodeTitle(ENodeTitleType::Type TitleType) const
{
return LOCTEXT("IfTitle", "If");
}
#undef LOCTEXT_NAMESPACE