|
// Fill out your copyright notice in the Description page of Project Settings. |
|
|
|
#include "GNNode_RegisterTweakableVariable.h" |
|
#include "GNBaseHUD.h" |
|
#include "Framework/Commands/UIAction.h" |
|
#include "Framework/MultiBox/MultiBoxBuilder.h" |
|
#include "EdGraphSchema_K2.h" |
|
#include "EdGraph/EdGraphNodeUtils.h" |
|
#include "K2Node_InputKeyEvent.h" |
|
#include "K2Node_CallFunction.h" |
|
#include "K2Node_InputKey.h" |
|
#include "K2Node_VariableSetRef.h" |
|
#include "Kismet2/BlueprintEditorUtils.h" |
|
|
|
#include "BlueprintActionDatabaseRegistrar.h" |
|
#include "BlueprintNodeSpawner.h" |
|
#include "EditorCategoryUtils.h" |
|
#include "KismetCompiler.h" |
|
#include "ScopedTransaction.h" |
|
#include "Kismet/KismetMathLibrary.h" |
|
|
|
#define LOCTEXT_NAMESPACE "GNNode_RegisterTweakableVariable" |
|
|
|
static FName TargetVariablePinName(TEXT("Target Variable")); |
|
static FName ChangeAmountPinName(TEXT("Change Amount")); |
|
static FName HUDPinName(TEXT("HUD")); |
|
|
|
UGNNode_RegisterTweakableVariable::UGNNode_RegisterTweakableVariable(const FObjectInitializer& ObjectInitializer) |
|
: Super(ObjectInitializer) |
|
{ |
|
|
|
} |
|
|
|
void UGNNode_RegisterTweakableVariable::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) |
|
{ |
|
Super::PostEditChangeProperty(PropertyChangedEvent); |
|
|
|
CachedNodeTitle.Clear(); |
|
CachedTooltip.Clear(); |
|
} |
|
|
|
void UGNNode_RegisterTweakableVariable::AllocateDefaultPins() |
|
{ |
|
Super::AllocateDefaultPins(); |
|
|
|
const UEdGraphSchema_K2* K2Schema = GetDefault<UEdGraphSchema_K2>(); |
|
|
|
// Create exec pins for input, update, and finished events |
|
CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Exec, UEdGraphSchema_K2::PN_Execute); |
|
CreatePin(EGPD_Output, UEdGraphSchema_K2::PC_Exec, UEdGraphSchema_K2::PN_Then); |
|
|
|
// Target variable pin |
|
UEdGraphPin* TargetVariablePin = CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Float, TargetVariablePinName); |
|
SetPinToolTip(*TargetVariablePin, LOCTEXT("UpKeyPinDescription", "The target variable.")); |
|
TargetVariablePin->PinType.bIsReference = true; |
|
|
|
// Name pin |
|
|
|
|
|
// Change amount pin |
|
UEdGraphPin* ChangeAmountPin = CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Float, ChangeAmountPinName); |
|
SetPinToolTip(*ChangeAmountPin, LOCTEXT("ChangeAmountPinDescription", "Amount the variable changes on each keypress.")); |
|
K2Schema->SetPinAutogeneratedDefaultValue(ChangeAmountPin, TEXT("0.1")); |
|
ChangeAmountPin->bNotConnectable = true; |
|
|
|
// HUD pin |
|
UEdGraphPin* HUDPin = CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Object, AGNBaseHUD::StaticClass(), HUDPinName); |
|
SetPinToolTip(*HUDPin, LOCTEXT("HUDPinDescription", "The HUD which will display the tweakable variable text info.")); |
|
} |
|
|
|
FText UGNNode_RegisterTweakableVariable::GetIncrementKeyText() const |
|
{ |
|
return IncrementInputKey.GetDisplayName(); |
|
} |
|
|
|
FText UGNNode_RegisterTweakableVariable::GetDecrementKeyText() const |
|
{ |
|
return DecrementInputKey.GetDisplayName(); |
|
} |
|
|
|
FText UGNNode_RegisterTweakableVariable::GetNodeTitle(ENodeTitleType::Type TitleType) const |
|
{ |
|
if (CachedNodeTitle.IsOutOfDate(this)) |
|
{ |
|
FFormatNamedArguments Args; |
|
Args.Add(TEXT("IncrementKey"), GetIncrementKeyText()); |
|
Args.Add(TEXT("DecrementKey"), GetDecrementKeyText()); |
|
|
|
// FText::Format() is slow, so we cache this to save on performance |
|
CachedNodeTitle.SetCachedText(FText::Format(NSLOCTEXT("GNNode", "RegisterTweakableVariable_Name_WithModifiers", "Register Tweakable Variable: Shift-{IncrementKey} / {DecrementKey}"), Args), this); |
|
} |
|
return CachedNodeTitle; |
|
} |
|
|
|
FText UGNNode_RegisterTweakableVariable::GetTooltipText() const |
|
{ |
|
if (CachedTooltip.IsOutOfDate(this)) |
|
{ |
|
FText IncrementKeyText = GetIncrementKeyText(); |
|
FText DecrementKeyText = GetDecrementKeyText(); |
|
|
|
// FText::Format() is slow, so we cache this to save on performance |
|
CachedTooltip.SetCachedText(FText::Format(NSLOCTEXT("K2Node", "RegisterTweakableVariable_Tooltip_Modifiers", "Creates events for tweaking a variable. The variable increments by the given amount when pressing Shift-{0}, and decrements when pressing Shift-{1}."), IncrementKeyText, DecrementKeyText), this); |
|
} |
|
|
|
return CachedTooltip; |
|
} |
|
|
|
FSlateIcon UGNNode_RegisterTweakableVariable::GetIconAndTint(FLinearColor& OutColor) const |
|
{ |
|
OutColor = GetNodeTitleColor(); |
|
static FSlateIcon Icon("EditorStyle", EKeys::GetMenuCategoryPaletteIcon(IncrementInputKey.GetMenuCategory())); |
|
return Icon; |
|
} |
|
|
|
void UGNNode_RegisterTweakableVariable::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 UGNNode_RegisterTweakableVariable::PinDefaultValueChanged(UEdGraphPin* Pin) |
|
{ |
|
|
|
} |
|
|
|
void UGNNode_RegisterTweakableVariable::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 UGNNode_RegisterTweakableVariable::GetMenuCategory() const |
|
{ |
|
static FNodeTextCache CachedCategory; |
|
if (CachedCategory.IsOutOfDate(this)) |
|
{ |
|
// FText::Format() is slow, so we cache this to save on performance |
|
CachedCategory.SetCachedText(FEditorCategoryUtils::BuildCategoryString(FCommonEditorCategory::Math, LOCTEXT("DevCategory", "Development")), this); |
|
} |
|
return CachedCategory; |
|
} |
|
|
|
bool UGNNode_RegisterTweakableVariable::IsCompatibleWithGraph(UEdGraph const* Graph) const |
|
{ |
|
// This node expands into event nodes and must be placed in a Ubergraph |
|
EGraphType const GraphType = Graph->GetSchema()->GetGraphType(Graph); |
|
bool bIsCompatible = (GraphType == EGraphType::GT_Ubergraph); |
|
|
|
if (bIsCompatible) |
|
{ |
|
UBlueprint* Blueprint = FBlueprintEditorUtils::FindBlueprintForGraph(Graph); |
|
|
|
UEdGraphSchema_K2 const* K2Schema = Cast<UEdGraphSchema_K2>(Graph->GetSchema()); |
|
bool const bIsConstructionScript = (K2Schema != nullptr) ? UEdGraphSchema_K2::IsConstructionScript(Graph) : false; |
|
|
|
bIsCompatible = (Blueprint != nullptr) && Blueprint->SupportsInputEvents() && !bIsConstructionScript && Super::IsCompatibleWithGraph(Graph); |
|
} |
|
return bIsCompatible; |
|
} |
|
|
|
void UGNNode_RegisterTweakableVariable::ValidateNodeDuringCompilation(class FCompilerResultsLog& MessageLog) const |
|
{ |
|
Super::ValidateNodeDuringCompilation(MessageLog); |
|
|
|
// Check increment key validity |
|
if (!IncrementInputKey.IsValid()) |
|
{ |
|
MessageLog.Warning(*FText::Format(NSLOCTEXT("KismetCompiler", "Invalid_IncrementInputKey_Warning", "IncrementInputKey Event specifies invalid FKey'{0}' for @@"), FText::FromString(IncrementInputKey.ToString())).ToString(), this); |
|
} |
|
else if (!IncrementInputKey.IsBindableInBlueprints()) |
|
{ |
|
MessageLog.Warning(*FText::Format(NSLOCTEXT("KismetCompiler", "NotBindanble_IncrementInputKey_Warning", "IncrementInputKey Event specifies FKey'{0}' that is not blueprint bindable for @@"), FText::FromString(IncrementInputKey.ToString())).ToString(), this); |
|
} |
|
|
|
// Check decrement key validity |
|
if (!DecrementInputKey.IsValid()) |
|
{ |
|
MessageLog.Warning(*FText::Format(NSLOCTEXT("KismetCompiler", "Invalid_DecrementInputKey_Warning", "DecrementInputKey Event specifies invalid FKey'{0}' for @@"), FText::FromString(DecrementInputKey.ToString())).ToString(), this); |
|
} |
|
else if (!DecrementInputKey.IsBindableInBlueprints()) |
|
{ |
|
MessageLog.Warning(*FText::Format(NSLOCTEXT("KismetCompiler", "NotBindanble_DecrementInputKey_Warning", "DecrementInputKey Event specifies FKey'{0}' that is not blueprint bindable for @@"), FText::FromString(DecrementInputKey.ToString())).ToString(), this); |
|
} |
|
|
|
// Check if sharing the same key |
|
if (IncrementInputKey.IsValid() && DecrementInputKey.IsValid()) |
|
{ |
|
if (GetIncrementKeyText().EqualTo(GetDecrementKeyText())) |
|
{ |
|
MessageLog.Warning(*FText::Format(NSLOCTEXT("KismetCompiler", "SameKey_Warning", "IncrementInputKey Event and DecrementInputKey Event cannot both specify FKey'{0}' for @@"), FText::FromString(DecrementInputKey.ToString())).ToString(), this); |
|
} |
|
} |
|
} |
|
|
|
void UGNNode_RegisterTweakableVariable::ExpandNode(class FKismetCompilerContext& CompilerContext, UEdGraph* SourceGraph) |
|
{ |
|
Super::ExpandNode(CompilerContext, SourceGraph); |
|
bool bIsErrorFree = true; |
|
|
|
const UEdGraphSchema_K2* Schema = CompilerContext.GetSchema(); |
|
|
|
FName UpdateHUDNativeFunctionName = GET_FUNCTION_NAME_CHECKED(AGNBaseHUD, UpdateTweakableVariable); |
|
UEdGraphPin* HUDPin = FindPin(HUDPinName); |
|
|
|
FName TweakableVariableName = NAME_None; |
|
|
|
// Get the name string for the target variable, if there is one. Add a prefix with the input key names. |
|
if (FindPin(TargetVariablePinName)->LinkedTo.Num() > 0) |
|
{ |
|
FText VariableName = FindPin(TargetVariablePinName)->LinkedTo[0]->GetDisplayName(); |
|
TweakableVariableName = FName(*FString::Printf(TEXT("%s / %s: %s"), *IncrementInputKey.GetDisplayName().ToString(), *DecrementInputKey.GetDisplayName().ToString(), *VariableName.ToString())); |
|
} |
|
|
|
/////////////////////////////////////////////////////////// |
|
|
|
// Create increment input key event |
|
UK2Node_InputKeyEvent* IncrementInputKeyEvent = CompilerContext.SpawnIntermediateEventNode<UK2Node_InputKeyEvent>(this, nullptr, SourceGraph); |
|
IncrementInputKeyEvent->CustomFunctionName = FName(*FString::Printf(TEXT("IncInpActEvt_%s_%s"), *IncrementInputKey.ToString(), *IncrementInputKeyEvent->GetName())); |
|
IncrementInputKeyEvent->InputChord.Key = IncrementInputKey; |
|
IncrementInputKeyEvent->InputChord.bShift = true; |
|
IncrementInputKeyEvent->bInternalEvent = true; |
|
IncrementInputKeyEvent->AllocateDefaultPins(); |
|
|
|
// Create Set By Ref node for Increment |
|
UK2Node_VariableSetRef* SetIncrementRefNode = CompilerContext.SpawnIntermediateNode<UK2Node_VariableSetRef>(this, SourceGraph); |
|
SetIncrementRefNode->AllocateDefaultPins(); |
|
CompilerContext.MessageLog.NotifyIntermediateObjectCreation(SetIncrementRefNode, this); |
|
|
|
// Create Add Float node |
|
FName AddFloatNativeFunctionName = GET_FUNCTION_NAME_CHECKED(UKismetMathLibrary, Add_FloatFloat); |
|
UK2Node_CallFunction* AddFloatNode = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this, SourceGraph); |
|
AddFloatNode->FunctionReference.SetExternalMember(AddFloatNativeFunctionName, UKismetMathLibrary::StaticClass()); |
|
AddFloatNode->AllocateDefaultPins(); |
|
CompilerContext.MessageLog.NotifyIntermediateObjectCreation(AddFloatNode, this); |
|
|
|
// Connect up the Add node |
|
Schema->CopyPinLinks(*FindPin(TargetVariablePinName), *AddFloatNode->FindPin(TEXT("A")), true); |
|
Schema->CopyPinLinks(*FindPin(ChangeAmountPinName), *AddFloatNode->FindPin(TEXT("B")), true); |
|
|
|
// Connect up the Increment Set Ref node |
|
Schema->TryCreateConnection(AddFloatNode->GetReturnValuePin(), SetIncrementRefNode->GetValuePin()); |
|
Schema->TryCreateConnection(Schema->FindExecutionPin(*IncrementInputKeyEvent, EGPD_Output), SetIncrementRefNode->GetExecPin()); |
|
Schema->CopyPinLinks(*FindPin(TargetVariablePinName), *SetIncrementRefNode->GetTargetPin(), true); |
|
|
|
// Create HUD UpdateTweakableVariable Increment function call |
|
UK2Node_CallFunction* IncrementUpdateHUDNode = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this, SourceGraph); |
|
IncrementUpdateHUDNode->FunctionReference.SetExternalMember(UpdateHUDNativeFunctionName, AGNBaseHUD::StaticClass()); |
|
IncrementUpdateHUDNode->AllocateDefaultPins(); |
|
CompilerContext.MessageLog.NotifyIntermediateObjectCreation(IncrementUpdateHUDNode, this); |
|
|
|
// Connect up the HUD UpdateTweakableVariable Increment function call node |
|
Schema->TryCreateConnection(Schema->FindExecutionPin(*SetIncrementRefNode, EGPD_Output), IncrementUpdateHUDNode->GetExecPin()); |
|
Schema->CopyPinLinks(*HUDPin, *IncrementUpdateHUDNode->FindPin(UEdGraphSchema_K2::PN_Self), true); |
|
Schema->CopyPinLinks(*FindPin(TargetVariablePinName), *IncrementUpdateHUDNode->FindPin(TEXT("Value")), true); |
|
Schema->TrySetDefaultValue(*IncrementUpdateHUDNode->FindPin(TEXT("Name")), TweakableVariableName.ToString()); |
|
|
|
/////////////////////////////////////////////////////////// |
|
|
|
// Create decrement input key event |
|
UK2Node_InputKeyEvent* DecrementInputKeyEvent = CompilerContext.SpawnIntermediateEventNode<UK2Node_InputKeyEvent>(this, nullptr, SourceGraph); |
|
DecrementInputKeyEvent->CustomFunctionName = FName(*FString::Printf(TEXT("DecInpActEvt_%s_%s"), *DecrementInputKey.ToString(), *DecrementInputKeyEvent->GetName())); |
|
DecrementInputKeyEvent->InputChord.Key = DecrementInputKey; |
|
DecrementInputKeyEvent->InputChord.bShift = true; |
|
DecrementInputKeyEvent->bInternalEvent = true; |
|
DecrementInputKeyEvent->AllocateDefaultPins(); |
|
|
|
// Create Set By Ref node for Decrement |
|
UK2Node_VariableSetRef* SetDecrementRefNode = CompilerContext.SpawnIntermediateNode<UK2Node_VariableSetRef>(this, SourceGraph); |
|
SetDecrementRefNode->AllocateDefaultPins(); |
|
CompilerContext.MessageLog.NotifyIntermediateObjectCreation(SetDecrementRefNode, this); |
|
|
|
// Create Subtract Float node |
|
FName SubtractFloatNativeFunctionName = GET_FUNCTION_NAME_CHECKED(UKismetMathLibrary, Subtract_FloatFloat); |
|
UK2Node_CallFunction* SubtractFloatNode = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this, SourceGraph); |
|
SubtractFloatNode->FunctionReference.SetExternalMember(SubtractFloatNativeFunctionName, UKismetMathLibrary::StaticClass()); |
|
SubtractFloatNode->AllocateDefaultPins(); |
|
CompilerContext.MessageLog.NotifyIntermediateObjectCreation(SubtractFloatNode, this); |
|
|
|
// Connect up the Subtract node |
|
Schema->CopyPinLinks(*FindPin(TargetVariablePinName), *SubtractFloatNode->FindPin(TEXT("A")), true); |
|
Schema->CopyPinLinks(*FindPin(ChangeAmountPinName), *SubtractFloatNode->FindPin(TEXT("B")), true); |
|
|
|
// Connect up the Decrement Set Ref node |
|
Schema->TryCreateConnection(SubtractFloatNode->GetReturnValuePin(), SetDecrementRefNode->GetValuePin()); |
|
Schema->TryCreateConnection(Schema->FindExecutionPin(*DecrementInputKeyEvent, EGPD_Output), SetDecrementRefNode->GetExecPin()); |
|
Schema->CopyPinLinks(*FindPin(TargetVariablePinName), *SetDecrementRefNode->GetTargetPin(), true); |
|
|
|
// Create HUD UpdateTweakableVariable Decrement function call |
|
UK2Node_CallFunction* DecrementUpdateHUDNode = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this, SourceGraph); |
|
DecrementUpdateHUDNode->FunctionReference.SetExternalMember(UpdateHUDNativeFunctionName, AGNBaseHUD::StaticClass()); |
|
DecrementUpdateHUDNode->AllocateDefaultPins(); |
|
CompilerContext.MessageLog.NotifyIntermediateObjectCreation(DecrementUpdateHUDNode, this); |
|
|
|
// Connect up the HUD UpdateTweakableVariable Decrement function call node |
|
Schema->TryCreateConnection(Schema->FindExecutionPin(*SetDecrementRefNode, EGPD_Output), DecrementUpdateHUDNode->GetExecPin()); |
|
Schema->CopyPinLinks(*HUDPin, *DecrementUpdateHUDNode->FindPin(UEdGraphSchema_K2::PN_Self), true); |
|
Schema->CopyPinLinks(*FindPin(TargetVariablePinName), *DecrementUpdateHUDNode->FindPin(TEXT("Value")), true); |
|
Schema->TrySetDefaultValue(*DecrementUpdateHUDNode->FindPin(TEXT("Name")), TweakableVariableName.ToString()); |
|
|
|
/////////////////////////////////////////////////////////// |
|
|
|
// Create HUD UpdateTweakableVariable Initial function call |
|
UK2Node_CallFunction* InitialUpdateHUDNode = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this, SourceGraph); |
|
InitialUpdateHUDNode->FunctionReference.SetExternalMember(UpdateHUDNativeFunctionName, AGNBaseHUD::StaticClass()); |
|
InitialUpdateHUDNode->AllocateDefaultPins(); |
|
CompilerContext.MessageLog.NotifyIntermediateObjectCreation(InitialUpdateHUDNode, this); |
|
|
|
// Connect up the HUD UpdateTweakableVariable Initial function call node |
|
CompilerContext.MovePinLinksToIntermediate(*GetExecPin(), *InitialUpdateHUDNode->GetExecPin()); |
|
CompilerContext.MovePinLinksToIntermediate(*FindPin(UEdGraphSchema_K2::PN_Then), *InitialUpdateHUDNode->GetThenPin()); |
|
Schema->CopyPinLinks(*HUDPin, *InitialUpdateHUDNode->FindPin(UEdGraphSchema_K2::PN_Self), true); |
|
Schema->CopyPinLinks(*FindPin(TargetVariablePinName), *InitialUpdateHUDNode->FindPin(TEXT("Value")), true); |
|
Schema->TrySetDefaultValue(*InitialUpdateHUDNode->FindPin(TEXT("Name")), TweakableVariableName.ToString()); |
|
|
|
if (!bIsErrorFree) |
|
{ |
|
CompilerContext.MessageLog.Error(*LOCTEXT("InternalConnectionError", "GNNode_SimpleTween: Internal connection error. @@").ToString(), this); |
|
} |
|
|
|
// Cleanup links to ourself and we are done! |
|
BreakAllNodeLinks(); |
|
} |
|
|
|
#undef LOCTEXT_NAMESPACE |