Files
UnrealEngine/Engine/Plugins/FX/Niagara/Source/NiagaraEditor/Private/NiagaraNodeReroute.cpp
Brandyn / Techy fcc1b09210 init
2026-04-04 15:40:51 -05:00

270 lines
7.5 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "NiagaraNodeReroute.h"
#include "NiagaraEditorUtilities.h"
#include "NiagaraHlslTranslator.h"
#include "NiagaraConstants.h"
#include UE_INLINE_GENERATED_CPP_BY_NAME(NiagaraNodeReroute)
#define LOCTEXT_NAMESPACE "NiagaraNodeReroute"
UNiagaraNodeReroute::UNiagaraNodeReroute(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
}
void UNiagaraNodeReroute::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();
}
}
ENiagaraNumericOutputTypeSelectionMode UNiagaraNodeReroute::GetNumericOutputTypeSelectionMode() const
{
return ENiagaraNumericOutputTypeSelectionMode::Largest;
}
bool UNiagaraNodeReroute::AllowExternalPinTypeChanges(const UEdGraphPin* InGraphPin) const
{
return true;
}
void UNiagaraNodeReroute::PostLoad()
{
Super::PostLoad();
}
void UNiagaraNodeReroute::AllocateDefaultPins()
{
const UEdGraphSchema_Niagara* Schema = CastChecked<UEdGraphSchema_Niagara>(GetSchema());
FEdGraphPinType Type = Schema->TypeDefinitionToPinType(FNiagaraTypeDefinition::GetWildcardDef());
UEdGraphPin* MyInputPin = CreatePin(EGPD_Input, Type, FNiagaraConstants::InputPinName);
MyInputPin->bDefaultValueIsIgnored = true;
CreatePin(EGPD_Output, Type, FNiagaraConstants::OutputPinName);
}
FText UNiagaraNodeReroute::GetTooltipText() const
{
return FText::GetEmpty();
}
FText UNiagaraNodeReroute::GetNodeTitle(ENodeTitleType::Type TitleType) const
{
if (TitleType == ENodeTitleType::EditableTitle)
{
return FText::FromString(NodeComment);
}
return LOCTEXT("RerouteNodeTitle", "Reroute Node");
}
bool UNiagaraNodeReroute::ShouldOverridePinNames() const
{
return true;
}
FText UNiagaraNodeReroute::GetPinNameOverride(const UEdGraphPin& Pin) const
{
// Keep the pin size tiny
return FText::GetEmpty();
}
void UNiagaraNodeReroute::OnRenameNode(const FString& NewName)
{
NodeComment = NewName;
}
bool UNiagaraNodeReroute::CanSplitPin(const UEdGraphPin* Pin) const
{
return false;
}
UEdGraphPin* UNiagaraNodeReroute::GetPassThroughPin(const UEdGraphPin* FromPin) const
{
if (FromPin && Pins.Contains(FromPin))
{
return FromPin == Pins[0] ? Pins[1] : Pins[0];
}
return nullptr;
}
bool UNiagaraNodeReroute::ShouldDrawNodeAsControlPointOnly(int32& OutInputPinIndex, int32& OutOutputPinIndex) const
{
OutInputPinIndex = 0;
OutOutputPinIndex = 1;
return true;
}
void UNiagaraNodeReroute::Compile(FTranslator* Translator, TArray<int32>& Outputs) const
{
FPinCollectorArray InputPins;
GetCompilationInputPins(InputPins);
FPinCollectorArray OutputPins;
GetCompilationOutputPins(OutputPins);
// Initialize the outputs to invalid values.
check(Outputs.Num() == 0);
Outputs.Reserve(OutputPins.Num());
for (int32 i = 0; i < OutputPins.Num(); i++)
{
if (InputPins.IsValidIndex(i))
{
int32 CompiledInput = Translator->CompileInputPin(InputPins[i]);
Outputs.Add(CompiledInput);
}
else
{
Outputs.Add(INDEX_NONE);
}
}
if (InputPins.Num() != OutputPins.Num())
{
Translator->Error(LOCTEXT("IncorrectNumOutputsError", "Input and Output pin counts must match."), this, nullptr);
}
}
bool UNiagaraNodeReroute::RefreshFromExternalChanges()
{
ReallocatePins();
PropagatePinType();
return true;
}
void UNiagaraNodeReroute::PinConnectionListChanged(UEdGraphPin* Pin)
{
PropagatePinType();
Super::PinConnectionListChanged(Pin);
}
void UNiagaraNodeReroute::BuildParameterMapHistory(FNiagaraParameterMapHistoryBuilder& OutHistory, bool bRecursive /*= true*/, bool bFilterForCompilation /*= true*/) const
{
RegisterPassthroughPin(OutHistory, GetInputPin(0), GetOutputPin(0), bFilterForCompilation, true);
}
/** Traces one of this node's output pins to its source output pin if it is a reroute node output pin.*/
UEdGraphPin* UNiagaraNodeReroute::GetTracedOutputPin(UEdGraphPin* LocallyOwnedOutputPin, bool bFilterForCompilation, TArray<const UNiagaraNode*>* OutNodesVisitedDuringTrace) const
{
check(Pins.Contains(LocallyOwnedOutputPin) && LocallyOwnedOutputPin->Direction == EGPD_Output);
UEdGraphPin* InputPin = GetInputPin(0);
if (InputPin && InputPin->LinkedTo.Num() == 1 && InputPin->LinkedTo[0] != nullptr)
{
UEdGraphPin* LinkedPin = InputPin->LinkedTo[0];
UNiagaraNode* LinkedNode = CastChecked<UNiagaraNode>(LinkedPin->GetOwningNode());
return LinkedNode->GetTracedOutputPin(LinkedPin, bFilterForCompilation, OutNodesVisitedDuringTrace);
}
return nullptr;
}
void UNiagaraNodeReroute::PropagatePinType()
{
UEdGraphPin* MyInputPin = GetInputPin(0);
UEdGraphPin* MyOutputPin = GetOutputPin(0);
for (UEdGraphPin* Inputs : MyInputPin->LinkedTo)
{
if (!UEdGraphSchema_Niagara::IsPinWildcard(Inputs))
{
PropagatePinTypeFromDirection(true);
return;
}
}
for (UEdGraphPin* Outputs : MyOutputPin->LinkedTo)
{
if(!UEdGraphSchema_Niagara::IsPinWildcard(Outputs))
{
PropagatePinTypeFromDirection(false);
return;
}
}
// if all inputs/outputs are wildcards, still favor the inputs first (propagate array/reference/etc. state)
if (MyInputPin->LinkedTo.Num() > 0)
{
// If we can't mirror from output type, we should at least get the type information from the input connection chain
PropagatePinTypeFromDirection(true);
}
else if (MyOutputPin->LinkedTo.Num() > 0)
{
// Try to mirror from output first to make sure we get appropriate member references
PropagatePinTypeFromDirection(false);
}
else
{
const UEdGraphSchema_Niagara* Schema = CastChecked<UEdGraphSchema_Niagara>(GetSchema());
FEdGraphPinType WildcardPinType = Schema->TypeDefinitionToPinType(FNiagaraTypeDefinition::GetWildcardDef());
// Revert to wildcard
MyInputPin->BreakAllPinLinks();
MyInputPin->PinType.ResetToDefaults();
MyInputPin->PinType = WildcardPinType;
MyOutputPin->BreakAllPinLinks();
MyOutputPin->PinType.ResetToDefaults();
MyOutputPin->PinType = WildcardPinType;
}
}
void UNiagaraNodeReroute::PropagatePinTypeFromDirection(bool bFromInput)
{
if (bRecursionGuard)
{
return;
}
// Set the type of the pin based on the source connection, and then percolate
// that type information up until we no longer reach another Reroute node
UEdGraphPin* MySourcePin = bFromInput ? GetInputPin(0) : GetOutputPin(0);
UEdGraphPin* MyDestinationPin = bFromInput ? GetOutputPin(0) : GetInputPin(0);
TGuardValue<bool> RecursionGuard(bRecursionGuard, true);
// Make sure any source knot pins compute their type, this will try to call back
// into this function but the recursion guard will stop it
for (UEdGraphPin* InPin : MySourcePin->LinkedTo)
{
if (UNiagaraNodeReroute* KnotNode = Cast<UNiagaraNodeReroute>(InPin->GetOwningNode()))
{
KnotNode->PropagatePinTypeFromDirection(bFromInput);
}
}
UEdGraphPin* TypeSource = MySourcePin->LinkedTo.Num() ? MySourcePin->LinkedTo[0] : nullptr;
if (TypeSource)
{
MySourcePin->PinType = TypeSource->PinType;
MyDestinationPin->PinType = TypeSource->PinType;
for (UEdGraphPin* LinkPin : MyDestinationPin->LinkedTo)
{
if (UNiagaraNodeReroute* OwningNode = Cast<UNiagaraNodeReroute>(LinkPin->GetOwningNode()))
{
// Notify any pins in the destination direction
if (UNiagaraNodeReroute* RerouteNode = Cast<UNiagaraNodeReroute>(OwningNode))
{
RerouteNode->PropagatePinTypeFromDirection(bFromInput);
}
else
{
OwningNode->PinConnectionListChanged(LinkPin);
}
}
}
}
}
#undef LOCTEXT_NAMESPACE