#include "K2Node_SEAndBranch.h"
#include "EdGraphSchema_K2.h"
#include "BlueprintActionDatabaseRegistrar.h"
#include "BlueprintNodeSpawner.h"
#include "GraphEditorSettings.h"
#include "EditorCategoryUtils.h"
#include "KismetCompiler.h"
#include "K2Node_IfThenElse.h"
#include "K2Node_Knot.h"
#define LOCTEXT_NAMESPACE "K2Node_SEAndBranch"
// ノードのデフォルトのピン定義
void UK2Node_SEAndBranch::AllocateDefaultPins()
{
// 入力実行ピン
CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Exec, UEdGraphSchema_K2::PN_Execute);
// 出力Then実行ピン
UEdGraphPin* TruePin = CreatePin(EGPD_Output, UEdGraphSchema_K2::PC_Exec, UEdGraphSchema_K2::PN_Then);
TruePin - > PinFriendlyName = LOCTEXT("AllocateDefaultPins_True", "true");
// 出力Else実行ピン
UEdGraphPin* FalsePin = CreatePin(EGPD_Output, UEdGraphSchema_K2::PC_Exec, UEdGraphSchema_K2::PN_Else);
FalsePin - > PinFriendlyName = LOCTEXT("AllocateDefaultPins_False", "false");
// 入力Conditionピン
AddUniqueConditionPin();
Super::AllocateDefaultPins();
}
// ノードタイトルの設定
FText UK2Node_SEAndBranch::GetNodeTitle(ENodeTitleType::Type TitleType) const
{
return LOCTEXT("GetNodeTitleDefault", "SE And Branch");
}
// ノード説明の設定
FText UK2Node_SEAndBranch::GetTooltipText() const
{
return LOCTEXT("GetTooltipText", "Evaluate from the smaller pin number.");
}
// ノードタイトル色の設定
FLinearColor UK2Node_SEAndBranch::GetNodeTitleColor() const
{
return GetDefault() - > ExecBranchNodeTitleColor;
}
// ノードのメニュー上におけるカテゴリの設定
FText UK2Node_SEAndBranch::GetMenuCategory() const
{
return FEditorCategoryUtils::GetCommonCategory(FCommonEditorCategory::FlowControl);
}
// ノードアイコンの設定
FSlateIcon UK2Node_SEAndBranch::GetIconAndTint(FLinearColor& amp; OutColor) const
{
static FSlateIcon Icon("EditorStyle", "GraphEditor.Branch_16x");
return Icon;
}
// 番号つきConditionピンの名前を取得
FName UK2Node_SEAndBranch::GetPinNameGivenIndex(int32 Index) const
{
return *FString::Printf(TEXT("%s_%d"), *UEdGraphSchema_K2::PN_Condition.ToString(), Index);
}
// 指定したピンがConditionピンか取得
bool UK2Node_SEAndBranch::IsConditionPin(UEdGraphPin* TargetPin) const
{
return TargetPin & amp; & TargetPin - > PinType.PinCategory == UEdGraphSchema_K2::PC_Boolean;
}
// Thenピンの取得(主にExpandNode内や、SpawnIntermediateNodeでUK2Node_SEAndBranchが使われるときに使用する)
UEdGraphPin* UK2Node_SEAndBranch::GetThenPin() const
{
UEdGraphPin* Pin = FindPin(UEdGraphSchema_K2::PN_Then);
check(Pin);
return Pin;
}
// Elseピンの取得(主にExpandNode内や、SpawnIntermediateNodeでUK2Node_SEAndBranchが使われるときに使用する)
UEdGraphPin* UK2Node_SEAndBranch::GetElsePin() const
{
UEdGraphPin* Pin = FindPin(UEdGraphSchema_K2::PN_Else);
check(Pin);
return Pin;
}
// Conditionピンの取得(主にExpandNode内や、SpawnIntermediateNodeでUK2Node_SEAndBranchが使われるときに使用する)
UEdGraphPin* UK2Node_SEAndBranch::GetConditionPinGivenIndex(const int32 Index)
{
return FindPin(GetPinNameGivenIndex(Index));
}
// ワイヤーの繋がっていないConditionピンを含むか
bool UK2Node_SEAndBranch::IsHaveUnlinkConditionPin() const
{
for (const auto& amp; Pin: Pins)
{
if (IsConditionPin(Pin) & amp; & Pin - > LinkedTo.Num() == 0)
{
return true;
}
}
return false;
}
// 未使用番号のConditionピンの名前を取得
FName UK2Node_SEAndBranch::GetUniquePinName() const
{
FName NewPinName;
for (int32 i = 0; true; i++)
{
NewPinName = GetPinNameGivenIndex(i);
if (!FindPin(NewPinName))
{
break;
}
}
return NewPinName;
}
// 未使用番号のConditionピンを作成する
UEdGraphPin* UK2Node_SEAndBranch::AddUniqueConditionPin()
{
UEdGraphPin* Pin = CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Boolean, GetUniquePinName());
Pin - > DefaultValue = TEXT("true");
return Pin;
}
// ピンの削除
void UK2Node_SEAndBranch::RemovePin(UEdGraphPin* TargetPin)
{
// 指定したピンを削除する
DestroyPin(TargetPin);
Pins.Remove(TargetPin);
// Conditionピンの番号を詰める
int32 ThenIndex = 0;
for (auto Pin : Pins)
{
if (IsConditionPin(Pin))
{
Pin - > PinName = GetPinNameGivenIndex(ThenIndex++);
}
}
}
// ピンの追加と削除(ピンとワイヤーが接続されたり切断されたときに呼ばれる)
void UK2Node_SEAndBranch::PinConnectionListChanged(UEdGraphPin* Pin)
{
if (IsConditionPin(Pin))
{
// Conditionピンからワイヤーが切断されたとき、切断されたワイヤーを削除
if (Pin - > LinkedTo.Num() == 0)
{
RemovePin(Pin);
}
// ワイヤーで繋がったピンしかないとき、ピンを追加
if (!IsHaveUnlinkConditionPin())
{
AddUniqueConditionPin();
}
// ノード外観を更新する
GetGraph() - > NotifyGraphChanged();
}
Super::PinConnectionListChanged(Pin);
}
// ピンの再構築(主にこのノードがあるBlueprintGraphがロードされたときに呼ばれる関数)
void UK2Node_SEAndBranch::ReallocatePinsDuringReconstruction(TArray& lt; UEdGraphPin*& gt; & OldPins)
{
Super::ReallocatePinsDuringReconstruction(OldPins); // 内部でAllocateDefaultPins()が呼ばれる
const int32 AlreadyPinNum = Pins.Num();
for (int i = 0; i & lt; OldPins.Num() - AlreadyPinNum; i++)
{
AddUniqueConditionPin();
}
}
// メニューアクションの登録(コンテキストメニューからノードをスポーンさせるようにする)
void UK2Node_SEAndBranch::GetMenuActions(FBlueprintActionDatabaseRegistrar& amp; 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);
}
}
void UK2Node_SEAndBranch::ExpandNode(FKismetCompilerContext& amp; CompilerContext, UEdGraph* SourceGraph)
{
Super::ExpandNode(CompilerContext, SourceGraph);
// Conditionピンを取得
TArray& lt; UEdGraphPin*& gt; ConditionPins;
for (int32 i = 0; true; i++)
{
// TODO
// 必要であればデフォルトピンの値による自明なフロー制御を行う
// ・Trueデフォルトピンは、ConditionPinsに含めない
// ・Falseデフォルトピンは、結果が自明(必ずElseに実行が流れる)
UEdGraphPin* ConditionPin = FindPin(GetPinNameGivenIndex(i));
if (!ConditionPin)
{
break;
}
ConditionPins.Add(ConditionPin);
}
// Rerouteノードをスポーンする
UK2Node_Knot* RerouteNode = CompilerContext.SpawnIntermediateNode(this, SourceGraph);
RerouteNode - > AllocateDefaultPins();
UEdGraphPin* RerouteExecPin = RerouteNode - > GetInputPin();
// Branchノードをスポーンする
TArray& lt; UK2Node_IfThenElse*& gt; BranchNodes;
for (auto ConditionPin : ConditionPins)
{
UK2Node_IfThenElse* BranchNode = CompilerContext.SpawnIntermediateNode(this, SourceGraph);
BranchNode - > AllocateDefaultPins();
BranchNode - > GetElsePin() - > MakeLinkTo(RerouteExecPin);
CompilerContext.MovePinLinksToIntermediate(*ConditionPin, *BranchNode - > GetConditionPin());
BranchNodes.Add(BranchNode);
}
// Branchノード同士を接続する
for (int32 i = 0; i & lt; BranchNodes.Num() - 1; i++) {
UEdGraphPin* PrevBranchThenPin = BranchNodes[i] - > GetThenPin();
UEdGraphPin* PostBranchExecPin = BranchNodes[i + 1] - > GetExecPin();
PrevBranchThenPin - > MakeLinkTo(PostBranchExecPin);
}
// ピンリンクの移動
CompilerContext.MovePinLinksToIntermediate(*GetExecPin(), *BranchNodes[0] - > GetExecPin());
CompilerContext.MovePinLinksToIntermediate(*GetThenPin(), *BranchNodes.Last() - > GetThenPin());
CompilerContext.MovePinLinksToIntermediate(*GetElsePin(), *RerouteNode - > GetOutputPin());
BreakAllNodeLinks();
}
#undef LOCTEXT_NAMESPACE