Files
UnrealEngineUWP/Engine/Source/Editor/BlueprintGraph/Private/K2Node_AssignmentStatement.cpp
dave jones2 64ae24ec12 Removed extraneous GetSelfPin implementations.
Since GetThenPin was added to UK2Node in 5.x, derived classes don't need to provide their own implementations. These were largely identical to the one in UK2Node. Additionally, overriding non-virtual functions can be error prone if there's an expectation of polymorphic behavior.

#rb dan.oconnor, jodon.karlik
#rnx
[FYI] George.Rolfe

[CL 35782464 by dave jones2 in ue5-main branch]
2024-08-23 16:46:50 -04:00

257 lines
8.4 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "K2Node_AssignmentStatement.h"
#include "BlueprintActionDatabaseRegistrar.h"
#include "BlueprintNodeSpawner.h"
#include "Containers/Array.h"
#include "Containers/Map.h"
#include "EdGraph/EdGraph.h"
#include "EdGraph/EdGraphPin.h"
#include "EdGraph/EdGraphSchema.h"
#include "EdGraphSchema_K2.h"
#include "EdGraphUtilities.h"
#include "EditorCategoryUtils.h"
#include "HAL/PlatformMath.h"
#include "Internationalization/Internationalization.h"
#include "Kismet2/CompilerResultsLog.h"
#include "KismetCastingUtils.h"
#include "KismetCompiledFunctionContext.h"
#include "KismetCompiler.h"
#include "Misc/AssertionMacros.h"
#include "UObject/Class.h"
#include "UObject/NameTypes.h"
#include "UObject/WeakObjectPtrTemplates.h"
#include "VariableSetHandler.h"
struct FBPTerminal;
#define LOCTEXT_NAMESPACE "K2Node_AssignmentStatement"
//////////////////////////////////////////////////////////////////////////
// FKCHandler_AssignmentStatement
class FKCHandler_AssignmentStatement : public FKCHandler_VariableSet
{
public:
FKCHandler_AssignmentStatement(FKismetCompilerContext& InCompilerContext)
: FKCHandler_VariableSet(InCompilerContext)
{
}
virtual void RegisterNets(FKismetFunctionContext& Context, UEdGraphNode* Node) override
{
using namespace UE::KismetCompiler;
UEdGraphPin* VariablePin = Node->FindPin(TEXT("Variable"));
UEdGraphPin* ValuePin = Node->FindPin(TEXT("Value"));
if ((VariablePin == NULL) || (ValuePin == NULL))
{
CompilerContext.MessageLog.Error(*LOCTEXT("MissingPins_Error", "Missing pin(s) on @@; expected a pin named Variable and a pin named Value").ToString(), Node);
return;
}
if (VariablePin->LinkedTo.Num() == 0)
{
CompilerContext.MessageLog.Error(*LOCTEXT("NoVariableConnected_Error", "A variable needs to be connected to @@").ToString(), VariablePin);
return;
}
ValidateAndRegisterNetIfLiteral(Context, ValuePin);
UEdGraphPin* VariablePinNet = FEdGraphUtilities::GetNetFromPin(VariablePin);
UEdGraphPin* ValuePinNet = FEdGraphUtilities::GetNetFromPin(ValuePin);
if (VariablePinNet && ValuePinNet)
{
CastingUtils::FConversion Conversion =
CastingUtils::GetFloatingPointConversion(*ValuePinNet, *VariablePinNet);
if (Conversion.Type != CastingUtils::FloatingPointCastType::None)
{
FBPTerminal* NewTerm = CastingUtils::MakeImplicitCastTerminal(Context, VariablePinNet, Node);
Context.ImplicitCastMap.Add(VariablePin, CastingUtils::FImplicitCastParams{Conversion, NewTerm, Node});
}
}
else
{
CompilerContext.MessageLog.Error(*LOCTEXT("NoVariableOrValueNets_Error", "Expected Variable and Value pins to have valid connections in @@").ToString(), Node);
}
}
virtual void Compile(FKismetFunctionContext& Context, UEdGraphNode* Node) override
{
using namespace UE::KismetCompiler;
UEdGraphPin* VariablePin = Node->FindPin(TEXT("Variable"));
UEdGraphPin* ValuePin = Node->FindPin(TEXT("Value"));
check(VariablePin);
check(VariablePin->LinkedTo.Num() == 1);
check(ValuePin);
InnerAssignment(Context, Node, VariablePin, ValuePin);
// Generate the output impulse from this node
GenerateSimpleThenGoto(Context, *Node);
// The assignment node is very much a non-standard node: its pins don't directly reference any data, but their nets do.
// The only cast that could happen is from the value pin's net to the variable's pin net, which we handle in RegisterNets.
// Due to how RegisterImplicitCasts works, it can actually register an erroneous entry to the value pin,
// which we need to remove ourselves.
CastingUtils::RemoveRegisteredImplicitCast(Context, ValuePin);
}
protected:
virtual bool UsesVariablePinAsKey() const override { return true; }
};
FName UK2Node_AssignmentStatement::VariablePinName(TEXT("Variable"));
FName UK2Node_AssignmentStatement::ValuePinName(TEXT("Value"));
UK2Node_AssignmentStatement::UK2Node_AssignmentStatement(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
}
void UK2Node_AssignmentStatement::AllocateDefaultPins()
{
CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Exec, UEdGraphSchema_K2::PN_Execute);
CreatePin(EGPD_Output, UEdGraphSchema_K2::PC_Exec, UEdGraphSchema_K2::PN_Then);
UEdGraphPin* VariablePin = CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Wildcard, VariablePinName);
UEdGraphPin* ValuePin = CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Wildcard, ValuePinName);
Super::AllocateDefaultPins();
}
FText UK2Node_AssignmentStatement::GetTooltipText() const
{
return LOCTEXT("AssignmentStatementTooltip", "Assigns Value to Variable");
}
FText UK2Node_AssignmentStatement::GetNodeTitle(ENodeTitleType::Type TitleType) const
{
return LOCTEXT("Assign", "Assign");
}
bool UK2Node_AssignmentStatement::IsCompatibleWithGraph(const UEdGraph* TargetGraph) const
{
bool bIsCompatible = Super::IsCompatibleWithGraph(TargetGraph);
if (bIsCompatible)
{
const EGraphType GraphType = TargetGraph->GetSchema()->GetGraphType(TargetGraph);
bIsCompatible = (GraphType == GT_Macro);
}
return bIsCompatible;
}
bool UK2Node_AssignmentStatement::CanPasteHere(const UEdGraph* TargetGraph) const
{
// These nodes can be pasted anywhere that UK2Node's are compatible with the graph
// Avoiding the call to IsCompatibleWithGraph because these nodes should normally only
// be placed in Macros, but it's nice to be able to paste Macro functionality anywhere.
return Super::IsCompatibleWithGraph(TargetGraph);
}
void UK2Node_AssignmentStatement::NotifyPinConnectionListChanged(UEdGraphPin* Pin)
{
Super::NotifyPinConnectionListChanged(Pin);
UEdGraphPin* VariablePin = FindPin(TEXT("Variable"));
UEdGraphPin* ValuePin = FindPin(TEXT("Value"));
if ((VariablePin->LinkedTo.Num() == 0) && (ValuePin->LinkedTo.Num() == 0))
{
// Restore the wildcard status
VariablePin->PinType.PinCategory = UEdGraphSchema_K2::PC_Wildcard;
VariablePin->PinType.PinSubCategory = TEXT("");
VariablePin->PinType.PinSubCategoryObject = NULL;
ValuePin->PinType.PinCategory = UEdGraphSchema_K2::PC_Wildcard;
ValuePin->PinType.PinSubCategory = TEXT("");
ValuePin->PinType.PinSubCategoryObject = NULL;
}
else if (Pin->LinkedTo.Num() > 0 &&
( Pin->LinkedTo[0]->PinType.PinCategory != UEdGraphSchema_K2::PC_Wildcard ||
Pin->LinkedTo[0]->PinType.PinCategory == Pin->PinType.PinCategory) )
{
Pin->PinType = Pin->LinkedTo[0]->PinType;
// Enforce the type on the other pin
if (VariablePin == Pin)
{
ValuePin->PinType = VariablePin->PinType;
UEdGraphSchema_K2::ValidateExistingConnections(ValuePin);
}
else
{
VariablePin->PinType = ValuePin->PinType;
UEdGraphSchema_K2::ValidateExistingConnections(VariablePin);
}
}
}
void UK2Node_AssignmentStatement::PostReconstructNode()
{
UEdGraphPin* VariablePin = FindPin(TEXT("Variable"));
UEdGraphPin* ValuePin = FindPin(TEXT("Value"));
PinConnectionListChanged(VariablePin);
PinConnectionListChanged(ValuePin);
Super::PostReconstructNode();
}
UEdGraphPin* UK2Node_AssignmentStatement::GetVariablePin() const
{
UEdGraphPin* Pin = FindPin(VariablePinName);
check(Pin != NULL);
return Pin;
}
UEdGraphPin* UK2Node_AssignmentStatement::GetValuePin() const
{
UEdGraphPin* Pin = FindPin(ValuePinName);
check(Pin != NULL);
return Pin;
}
FNodeHandlingFunctor* UK2Node_AssignmentStatement::CreateNodeHandler(FKismetCompilerContext& CompilerContext) const
{
return new FKCHandler_AssignmentStatement(CompilerContext);
}
void UK2Node_AssignmentStatement::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_AssignmentStatement::GetMenuCategory() const
{
return FEditorCategoryUtils::GetCommonCategory(FCommonEditorCategory::Macro);
}
#undef LOCTEXT_NAMESPACE