Compare commits
1 Commits
main
...
deprecate-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cb7e8feb8c |
@ -6,7 +6,7 @@
|
||||
"Description": "A set of components and classes for capturing Enhanced Input actions for buffering actions and stringing them into complex combos.",
|
||||
"Category": "Input",
|
||||
"CreatedBy": "Jamie Greunbaum",
|
||||
"EngineVersion": "5.4.0",
|
||||
"EngineVersion": "5.3.0",
|
||||
"CanContainContent": true,
|
||||
"IsBetaVersion": true,
|
||||
"IsExperimentalVersion": true,
|
||||
|
||||
|
Before Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 5.9 KiB |
|
Before Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 7.1 KiB |
|
Before Width: | Height: | Size: 295 KiB |
|
Before Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 180 KiB |
|
Before Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 518 B |
|
Before Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 382 KiB |
|
Before Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 3.1 KiB |
|
Before Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 46 KiB |
|
Before Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 124 B |
|
Before Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 138 KiB |
|
Before Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 14 KiB |
@ -44,7 +44,6 @@ public class ComboInput : ModuleRules
|
||||
"Core",
|
||||
"CoreUObject",
|
||||
"Engine",
|
||||
"GameplayTags",
|
||||
"Slate",
|
||||
"SlateCore",
|
||||
"DeveloperSettings",
|
||||
|
||||
@ -1,118 +0,0 @@
|
||||
// ©2023 Batty Bovine Productions, LLC. All Rights Reserved.
|
||||
|
||||
#include "ComboActionGraph.h"
|
||||
|
||||
#include "Nodes/ComboActionGraphEdge.h"
|
||||
#include "Nodes/ComboActionGraphNode.h"
|
||||
#include "Nodes/ComboActionGraphNode_StartNode.h"
|
||||
|
||||
#define LOCTEXT_NAMESPACE "ComboActionGraph"
|
||||
|
||||
DEFINE_LOG_CATEGORY(LogComboActionGraph);
|
||||
|
||||
|
||||
UComboActionGraph::UComboActionGraph()
|
||||
{
|
||||
this->NodeType = UComboActionGraphNode::StaticClass();
|
||||
this->EdgeType = UComboActionGraphEdge::StaticClass();
|
||||
|
||||
this->bEdgeEnabled = false;
|
||||
this->GraphGUID = FGuid::NewGuid();
|
||||
|
||||
#if WITH_EDITORONLY_DATA
|
||||
this->EdGraph = nullptr;
|
||||
|
||||
this->bCanRenameNode = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
void UComboActionGraph::CreateGraph()
|
||||
{
|
||||
#if WITH_EDITOR
|
||||
// We already have an existing graph or start node
|
||||
if (this->EdGraph != nullptr || this->StartNode != nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this->StartNode = this->ConstructActionNode<UComboActionGraphNode_StartNode>();
|
||||
if (this->StartNode != nullptr )
|
||||
{
|
||||
this->StartNode->Graph = this;
|
||||
|
||||
this->RootNodes.Add(this->StartNode);
|
||||
this->AllNodes.Add(this->StartNode);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void UComboActionGraph::ClearGraph()
|
||||
{
|
||||
for (UComboActionGraphNode *Node : this->AllNodes)
|
||||
{
|
||||
Node->ParentNodes.Empty();
|
||||
Node->ChildNodes.Empty();
|
||||
Node->Edges.Empty();
|
||||
}
|
||||
|
||||
this->AllNodes.Empty();
|
||||
this->RootNodes.Empty();
|
||||
}
|
||||
|
||||
void UComboActionGraph::PostInitProperties()
|
||||
{
|
||||
UObject::PostInitProperties();
|
||||
|
||||
// Ignore these cases
|
||||
if (this->HasAnyFlags(EObjectFlags::RF_ClassDefaultObject | EObjectFlags::RF_NeedLoad))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#if WITH_EDITOR
|
||||
this->CreateGraph();
|
||||
#endif
|
||||
}
|
||||
|
||||
#if WITH_EDITOR
|
||||
bool UComboActionGraph::ValidateGraph(TArray<FText> &ValidationErrors, bool RichTextFormat)
|
||||
{
|
||||
bool bReturnValue = true;
|
||||
|
||||
if (this->StartNode == nullptr)
|
||||
{
|
||||
const FString RichTextReturn =
|
||||
FString("* ")
|
||||
.Append(TEXT("<RichTextBlock.Bold>Dialogue Graph</>"))
|
||||
.Append(": Has no Start Node!");
|
||||
|
||||
const FString TextReturn =
|
||||
this->GetName()
|
||||
.Append(": Has no Start Node!");
|
||||
|
||||
ValidationErrors.Add(FText::FromString(RichTextFormat ? RichTextReturn : TextReturn));
|
||||
|
||||
bReturnValue = false;
|
||||
}
|
||||
|
||||
for (UComboActionGraphNode *Itr : this->AllNodes)
|
||||
{
|
||||
if (Itr != nullptr && !Itr->ValidateNode(ValidationErrors, RichTextFormat))
|
||||
{
|
||||
bReturnValue = false;
|
||||
}
|
||||
}
|
||||
|
||||
return bReturnValue;
|
||||
}
|
||||
|
||||
EDataValidationResult UComboActionGraph::IsDataValid(TArray<FText> &ValidationErrors)
|
||||
{
|
||||
//return this->ValidateGraph(ValidationErrors, false)
|
||||
// ? EDataValidationResult::Valid
|
||||
// : EDataValidationResult::Invalid;
|
||||
return EDataValidationResult::NotValidated;
|
||||
}
|
||||
#endif
|
||||
|
||||
#undef LOCTEXT_NAMESPACE
|
||||
@ -2,49 +2,42 @@
|
||||
|
||||
#include "Components/ComboManagerComponent.h"
|
||||
|
||||
#include "ComboActionGraph.h"
|
||||
#include "ComboInputAssets.h"
|
||||
#include "EnhancedInputComponent.h"
|
||||
#include "InputBufferLocalPlayerSubsystem.h"
|
||||
|
||||
#include "Components/InputBufferComponent.h"
|
||||
#include "Engine/LocalPlayer.h"
|
||||
#include "GameFramework/Character.h"
|
||||
#include "Kismet/GameplayStatics.h"
|
||||
#include "Nodes/ComboActionGraphNode_ActionNode.h"
|
||||
|
||||
DEFINE_LOG_CATEGORY(LogComboManagerComponent);
|
||||
|
||||
|
||||
UComboManagerComponent::UComboManagerComponent()
|
||||
{
|
||||
this->PrimaryComponentTick.bStartWithTickEnabled = false;
|
||||
this->PrimaryComponentTick.bTickEvenWhenPaused = false;
|
||||
this->PrimaryComponentTick.bCanEverTick = false;
|
||||
|
||||
this->bWantsInitializeComponent = true;
|
||||
PrimaryComponentTick.bStartWithTickEnabled = false;
|
||||
PrimaryComponentTick.bTickEvenWhenPaused = false;
|
||||
PrimaryComponentTick.bCanEverTick = false;
|
||||
}
|
||||
|
||||
void UComboManagerComponent::InitializeComponent()
|
||||
void UComboManagerComponent::BeginPlay()
|
||||
{
|
||||
Super::InitializeComponent();
|
||||
Super::BeginPlay();
|
||||
|
||||
checkf(this->ComboGraph, TEXT("No combo graph is set for %s in actor %s"), *UComboManagerComponent::StaticClass()->GetName(), *this->GetOwner()->GetName());
|
||||
this->PreviousNode = this->ActiveNode = this->ComboGraph->StartNode;
|
||||
}
|
||||
// If this component's owner is the player character or controller, attach it to the subsystem.
|
||||
APlayerController *PlayerController = UGameplayStatics::GetPlayerController(this, 0);
|
||||
if (this->GetOwner() == PlayerController)
|
||||
{
|
||||
UEnhancedInputComponent *InputComponent = Cast<UEnhancedInputComponent>(PlayerController->InputComponent);
|
||||
checkf(InputComponent, TEXT("Discovered player input component is not of type %s."), *UEnhancedInputComponent::StaticClass()->GetName());
|
||||
|
||||
void UComboManagerComponent::SetComboGraph(const UComboActionGraph *Graph)
|
||||
{
|
||||
checkf(Graph, TEXT("Attempting to set a null combo graph."));
|
||||
|
||||
this->ComboGraph = Graph;
|
||||
|
||||
this->FoundInputsCache.Empty();
|
||||
this->FindAllUsedInputs();
|
||||
|
||||
this->ResetCombo();
|
||||
UInputBufferLocalPlayerSubsystem *InputBufferSubsystem = PlayerController->GetLocalPlayer()->GetSubsystem<UInputBufferLocalPlayerSubsystem>();
|
||||
InputBufferSubsystem->AttachComboManager(this, InputComponent);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void UComboManagerComponent::HandleComboInput(const UComboInputAsset *Input, const EComboActionTriggerEvent &TriggerEvent)
|
||||
void UComboManagerComponent::HandleComboInput(const UInputAction *Input, const EComboActionTriggerEvent &TriggerEvent)
|
||||
{
|
||||
switch (TriggerEvent)
|
||||
{
|
||||
@ -59,10 +52,10 @@ void UComboManagerComponent::HandleComboInput(const UComboInputAsset *Input, con
|
||||
}
|
||||
}
|
||||
|
||||
void UComboManagerComponent::ActivateComboAction(const UComboInputAsset *Input)
|
||||
void UComboManagerComponent::ActivateComboAction(const UInputAction *Input)
|
||||
{
|
||||
/************ DEBUG ************/
|
||||
for (const TPair<TObjectPtr<const UComboInputAsset>, float> &Pair : this->DEBUG__UnlockTimers)
|
||||
for (const TPair<TObjectPtr<const UInputAction>, float> &Pair : this->DEBUG__UnlockTimers)
|
||||
{
|
||||
if (!this->DEBUG__TimerHandles.Contains(Pair.Key))
|
||||
{
|
||||
@ -83,85 +76,50 @@ void UComboManagerComponent::ActivateComboAction(const UComboInputAsset *Input)
|
||||
return;
|
||||
}
|
||||
|
||||
// Find the next node in the graph.
|
||||
const UComboAction *ComboAction = nullptr;
|
||||
const UComboActionGraphNode *NextNode = this->FindActiveNodeData(this->ActiveNode, Input, EComboActionTriggerEvent::Activated, ComboAction);
|
||||
if (!NextNode)
|
||||
{
|
||||
// If there is no next active node, then return to the start node.
|
||||
NextNode = this->FindActiveNodeData(this->ComboGraph->StartNode, Input, EComboActionTriggerEvent::Activated, ComboAction);
|
||||
}
|
||||
checkf(NextNode, TEXT("No combo sequence nodes available."));
|
||||
const TObjectPtr<const UComboSequenceNode> CurrentNode = (this->ActiveNode ? this->ActiveNode : this->DefaultStartNode);
|
||||
checkf(CurrentNode, TEXT("No combo sequence nodes available."));
|
||||
|
||||
const FComboSequenceAction *ActionData = CurrentNode->ComboBranch.Find(Input);
|
||||
// If this node has an action we can activate, then activate it.
|
||||
if (ComboAction)
|
||||
if (ActionData && ActionData->ComboAction)
|
||||
{
|
||||
this->BeginNodeTransition(NextNode);
|
||||
this->BroadcastDelegates(ComboAction, EComboActionTriggerEvent::Activated);
|
||||
UE_LOG(LogComboManagerComponent, Verbose, TEXT("%s activated"), *ComboAction->ActionName.ToString());
|
||||
this->BeginNodeTransition(ActionData->NextNode);
|
||||
this->BroadcastDelegates(ActionData->ComboAction, EComboActionTriggerEvent::Activated);
|
||||
UE_LOG(LogComboManagerComponent, Verbose, TEXT("%s activated"), *ActionData->ComboAction->ActionName.ToString());
|
||||
}
|
||||
// Otherwise, see if we have a fallback we can use.
|
||||
else if (const TObjectPtr<const UComboAction> *FallbackAction = this->FallbackActions.Find(Input))
|
||||
else if (const TObjectPtr<const UComboAction> *ComboAction = this->FallbackActions.Find(Input))
|
||||
{
|
||||
this->ResetCombo();
|
||||
this->BroadcastDelegates(*FallbackAction, EComboActionTriggerEvent::Activated);
|
||||
UE_LOG(LogComboManagerComponent, Verbose, TEXT("Fallback action %s activated"), *(*FallbackAction)->ActionName.ToString());
|
||||
this->BroadcastDelegates(*ComboAction, EComboActionTriggerEvent::Activated);
|
||||
UE_LOG(LogComboManagerComponent, Verbose, TEXT("Fallback action %s activated"), *(*ComboAction)->ActionName.ToString());
|
||||
}
|
||||
// If we haven't found an action to perform, end here.
|
||||
// If we haven't found an action to perform, reset the combo and activate using the default start node.
|
||||
else
|
||||
{
|
||||
UE_LOG(LogComboManagerComponent, Verbose, TEXT("No action found for %s"), *Input->ComboInputName.ToString());
|
||||
this->ActiveNode = nullptr;
|
||||
this->ActivateComboAction(Input);
|
||||
return;
|
||||
}
|
||||
}
|
||||
void UComboManagerComponent::DEBUG__UnlockAction(TObjectPtr<const UComboInputAsset> Unlock)
|
||||
void UComboManagerComponent::DEBUG__UnlockAction(TObjectPtr<const UInputAction> Unlock)
|
||||
{
|
||||
APlayerController *Controller = UGameplayStatics::GetPlayerController(this, 0);
|
||||
if (UInputBufferComponent *InputComponent = Cast<UInputBufferComponent>(Controller->InputComponent))
|
||||
{
|
||||
InputComponent->UnlockComboInput(Unlock);
|
||||
}
|
||||
UInputBufferLocalPlayerSubsystem *Subsystem = Controller->GetLocalPlayer()->GetSubsystem<UInputBufferLocalPlayerSubsystem>();
|
||||
Subsystem->UnlockComboInput(Unlock);
|
||||
}
|
||||
|
||||
void UComboManagerComponent::ReleaseComboAction(const class UComboInputAsset *Input)
|
||||
void UComboManagerComponent::ReleaseComboAction(const class UInputAction *Input)
|
||||
{
|
||||
if (this->LastComboAction && this->ActiveNode)
|
||||
if (this->LastComboAction)
|
||||
{
|
||||
// See if we have a fallback we can release.
|
||||
const TObjectPtr<const UComboAction> *FallbackAction = this->FallbackActions.Find(Input);
|
||||
if (FallbackAction && *FallbackAction == this->LastComboAction)
|
||||
{
|
||||
this->ResetCombo();
|
||||
this->BroadcastDelegates(*FallbackAction, EComboActionTriggerEvent::Released);
|
||||
UE_LOG(LogComboManagerComponent, Verbose, TEXT("Fallback action %s released"), *(*FallbackAction)->ActionName.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Find a node that matches the release action.
|
||||
const UComboAction *ComboAction = nullptr;
|
||||
for (const UComboActionGraphNode *Node : this->ActiveNode->ChildNodes)
|
||||
{
|
||||
if (const UComboActionGraphNode_ActionNode *ActionNode = StaticCast<const UComboActionGraphNode_ActionNode *>(Node))
|
||||
{
|
||||
if (ActionNode->GetTriggerEvent() == EComboActionTriggerEvent::Released)
|
||||
{
|
||||
ComboAction = ActionNode->GetComboAction();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ComboAction)
|
||||
{
|
||||
this->BroadcastDelegates(ComboAction, EComboActionTriggerEvent::Released);
|
||||
UE_LOG(LogComboManagerComponent, Verbose, TEXT("%s released"), *ComboAction->ActionName.ToString());
|
||||
}
|
||||
}
|
||||
this->BroadcastDelegates(this->LastComboAction, EComboActionTriggerEvent::Released);
|
||||
this->LastComboAction = nullptr;
|
||||
}
|
||||
|
||||
this->LastComboAction = nullptr;
|
||||
}
|
||||
|
||||
|
||||
void UComboManagerComponent::BeginNodeTransition(const UComboActionGraphNode *NextNode)
|
||||
void UComboManagerComponent::BeginNodeTransition(const UComboSequenceNode *NextNode)
|
||||
{
|
||||
this->PreviousNode = this->ActiveNode;
|
||||
this->ActiveNode = NextNode;
|
||||
@ -178,80 +136,7 @@ void UComboManagerComponent::FinishTransition()
|
||||
void UComboManagerComponent::ResetCombo()
|
||||
{
|
||||
this->GetWorld()->GetTimerManager().ClearTimer(this->DEBUG__ResetComboTimer);
|
||||
this->PreviousNode = this->ActiveNode = this->ComboGraph->StartNode;
|
||||
|
||||
APlayerController *Controller = UGameplayStatics::GetPlayerController(this, 0);
|
||||
if (UInputBufferComponent *InputComponent = Cast<UInputBufferComponent>(Controller->InputComponent))
|
||||
{
|
||||
for (const UComboInputAsset *Unlock : this->FoundInputsCache)
|
||||
{
|
||||
InputComponent->UnlockComboInput(Unlock);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TSet<const UComboInputAsset *> &UComboManagerComponent::FindAllUsedInputs()
|
||||
{
|
||||
if (this->FoundInputsCache.IsEmpty())
|
||||
{
|
||||
// First check the graph for inputs to respond to.
|
||||
this->FindAllUsedInputs_RecurseGraph(this->ComboGraph->StartNode, this->FoundInputsCache);
|
||||
|
||||
// Next check the fallback actions for supplementary inputs to respond to.
|
||||
TArray<TObjectPtr<const UComboInputAsset>> FallbackInputs;
|
||||
this->FallbackActions.GetKeys(FallbackInputs);
|
||||
for (const TObjectPtr<const UComboInputAsset> &FallbackInput : FallbackInputs)
|
||||
{
|
||||
this->FoundInputsCache.Add(FallbackInput);
|
||||
}
|
||||
|
||||
// Finally check the offset action for the final input to respond to.
|
||||
if (this->OffsetMap.ComboInput)
|
||||
{
|
||||
this->FoundInputsCache.Add(this->OffsetMap.ComboInput);
|
||||
}
|
||||
}
|
||||
|
||||
return this->FoundInputsCache;
|
||||
}
|
||||
void UComboManagerComponent::FindAllUsedInputs_RecurseGraph(const UComboActionGraphNode *CurrentNode, TSet<const UComboInputAsset *> &FoundInputs)
|
||||
{
|
||||
for (const UComboActionGraphNode *NextNode : CurrentNode->ChildNodes)
|
||||
{
|
||||
// It should be safe to assume all of our nodes are action nodes. If at some point
|
||||
// this becomes less reliable, this should be changed. But just for the sake of
|
||||
// saving a bit of performance on start-up, we're doing this right now.
|
||||
checkf(NextNode->GetClass() == UComboActionGraphNode_ActionNode::StaticClass(), TEXT("This graph contains non-action nodes. The cast in this function will fail."));
|
||||
FoundInputs.Add(StaticCast<const UComboActionGraphNode_ActionNode *>(NextNode)->GetComboInput());
|
||||
this->FindAllUsedInputs_RecurseGraph(NextNode, FoundInputs);
|
||||
}
|
||||
}
|
||||
|
||||
const UComboActionGraphNode *UComboManagerComponent::FindActiveNodeData(const UComboActionGraphNode *CurrentNode, const UComboInputAsset *Input, const EComboActionTriggerEvent TriggerEvent, const UComboAction *&ComboAction)
|
||||
{
|
||||
checkf(CurrentNode, TEXT("Attempting to find an active node from a null node."));
|
||||
|
||||
// Find a node that matches both the combo input and the trigger action.
|
||||
const UComboActionGraphNode *NextNode = nullptr;
|
||||
for (const UComboActionGraphNode *GraphNode : CurrentNode->ChildNodes)
|
||||
{
|
||||
if (const UComboActionGraphNode_ActionNode *ActionNode = Cast<UComboActionGraphNode_ActionNode>(GraphNode))
|
||||
{
|
||||
if (ActionNode->GetComboInput() == Input && ActionNode->GetTriggerEvent() == EComboActionTriggerEvent::Activated)
|
||||
{
|
||||
// If we found the right node, only acknowledge it if it's enabled.
|
||||
const UComboAction *CheckAction = ActionNode->GetComboAction();
|
||||
if (ActionNode->bEnabled || this->ComboGraph->UnlockedActions.Contains(CheckAction))
|
||||
{
|
||||
ComboAction = CheckAction;
|
||||
NextNode = ActionNode;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NextNode;
|
||||
this->ActiveNode = this->PreviousNode = nullptr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -1,250 +0,0 @@
|
||||
// ©2022 Batty Bovine Productions, LLC. All Rights Reserved.
|
||||
|
||||
#include "Components/InputBufferComponent.h"
|
||||
|
||||
#include "ComboInputAssets.h"
|
||||
#include "EnhancedInputComponent.h"
|
||||
#include "Kismet/GameplayStatics.h"
|
||||
|
||||
#include "Components/ComboManagerComponent.h"
|
||||
#include "GlobalSettings/InputBufferGlobalSettings.h"
|
||||
|
||||
DEFINE_LOG_CATEGORY(LogInputBufferComponent);
|
||||
|
||||
|
||||
UInputBufferComponent::UInputBufferComponent()
|
||||
{
|
||||
this->bWantsInitializeComponent = true;
|
||||
}
|
||||
|
||||
void UInputBufferComponent::InitializeComponent()
|
||||
{
|
||||
Super::InitializeComponent();
|
||||
|
||||
if (APlayerController *PlayerController = UGameplayStatics::GetPlayerController(this, 0))
|
||||
{
|
||||
if (UComboManagerComponent *ComboManager = PlayerController->GetComponentByClass<UComboManagerComponent>())
|
||||
{
|
||||
// Get the player character and try to connect to its combo manager.
|
||||
this->OnNewComboInput.BindUObject(ComboManager, &UComboManagerComponent::HandleComboInput);
|
||||
|
||||
const TSet<const UComboInputAsset *> &ComboInputs = ComboManager->FindAllUsedInputs();
|
||||
|
||||
// Get all unique EnhancedInput actions bound to combo input actions.
|
||||
TSet<const UInputAction *> InputActionsToBind;
|
||||
for (const UComboInputAsset *ComboInput : ComboInputs)
|
||||
{
|
||||
if (ComboInput)
|
||||
{
|
||||
this->ComboInputList.Emplace(ComboInput);
|
||||
for (const UInputAction *InputAction : ComboInput->ActionGroup)
|
||||
{
|
||||
InputActionsToBind.Add(InputAction);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(LogInputBufferComponent, Verbose, TEXT("Invalid combo input found"));
|
||||
}
|
||||
}
|
||||
for (const UInputAction *InputAction : InputActionsToBind)
|
||||
{
|
||||
this->BindAction(InputAction, ETriggerEvent::Started, this, &UInputBufferComponent::AddActionToBuffer, InputAction);
|
||||
this->BindAction(InputAction, ETriggerEvent::Completed, this, &UInputBufferComponent::ExpireAction, InputAction);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void UInputBufferComponent::AddActionToBuffer(const FInputActionValue &Value, const class UInputAction *Action)
|
||||
{
|
||||
this->MultiPressActions.Add(Action);
|
||||
this->ExpiringActions.Remove(Action);
|
||||
|
||||
// Find any combo input that matches this action, plus buffered actions.
|
||||
bool bComboInputFound = false;
|
||||
for (TObjectPtr<const UComboInputAsset> ComboInput : this->ComboInputList)
|
||||
{
|
||||
if (ComboInput->MatchesInputActions(this->MultiPressActions))
|
||||
{
|
||||
this->ActivateComboInput(ComboInput.Get());
|
||||
bComboInputFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If we haven't found any matching inputs, check if anything was somehow unhandled.
|
||||
// This can happen if, for example, a jump input can combine with an attack input to
|
||||
// create a combo action, but jump by itself has no action on its own.
|
||||
if (!bComboInputFound)
|
||||
{
|
||||
if (!this->UnhandledActions.IsEmpty())
|
||||
{
|
||||
TSet<const UInputAction*> HandledActions = this->MultiPressActions;
|
||||
for (const UInputAction *UnhandledAction : this->UnhandledActions)
|
||||
{
|
||||
HandledActions.Remove(UnhandledAction);
|
||||
}
|
||||
|
||||
for (TObjectPtr<const UComboInputAsset> ComboInput : this->ComboInputList)
|
||||
{
|
||||
if (ComboInput->MatchesInputActions(HandledActions))
|
||||
{
|
||||
this->ActivateComboInput(ComboInput);
|
||||
bComboInputFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
this->UnhandledActions.Add(Action);
|
||||
}
|
||||
|
||||
const UInputBufferGlobalSettings *Settings = GetDefault<UInputBufferGlobalSettings>();
|
||||
this->GetWorld()->GetTimerManager().SetTimer(this->MultiPressTimerHandle, this, &UInputBufferComponent::ClearMultiPresses, Settings->MultiPressTimerLength);
|
||||
}
|
||||
void UInputBufferComponent::ClearMultiPresses()
|
||||
{
|
||||
#if WITH_EDITOR
|
||||
TArray<FString> ActionNames;
|
||||
for (const UInputAction *Action : this->MultiPressActions)
|
||||
{
|
||||
ActionNames.Add(Action->GetName());
|
||||
}
|
||||
UE_LOG(LogInputBufferComponent, Verbose, TEXT("Multi-press buffer cleared (%s)"), *FString::Join(ActionNames, TEXT(" | ")));
|
||||
#endif
|
||||
this->MultiPressActions.Empty();
|
||||
this->UnhandledActions.Empty();
|
||||
}
|
||||
|
||||
void UInputBufferComponent::ActivateComboInput(const UComboInputAsset *ComboInput)
|
||||
{
|
||||
checkf(ComboInput, TEXT("Invalid %s."), *UComboInputAsset::StaticClass()->GetName());
|
||||
|
||||
const bool bNewInputLocked = this->LockedComboInputs.Contains(ComboInput);
|
||||
const bool bNewSupercedesActive = (this->InputBufferActive && this->InputBufferActive->ContainsOneOf(ComboInput->ActionGroup) && !bNewInputLocked);
|
||||
|
||||
// Make this combo input active if it isn't being locked, or if we are
|
||||
// overwriting a previous combo input with a multi-press combo input.
|
||||
if (bNewSupercedesActive || !bNewInputLocked)
|
||||
{
|
||||
// Set the combo input as active.
|
||||
this->InputBufferActive = ComboInput;
|
||||
this->InputBufferHold = nullptr;
|
||||
|
||||
const UInputBufferGlobalSettings *Settings = GetDefault<UInputBufferGlobalSettings>();
|
||||
for (const TObjectPtr<const UComboInputAsset> &LockedAsset : this->ComboInputList)
|
||||
{
|
||||
this->LockComboInput(LockedAsset);
|
||||
}
|
||||
|
||||
this->OnNewComboInput.Execute(ComboInput, EComboActionTriggerEvent::Activated);
|
||||
|
||||
// If the incoming combo input contains an expiring action,
|
||||
// we know it's been released, so send that signal too.
|
||||
if (ComboInput->ContainsOneOf(this->ExpiringActions))
|
||||
{
|
||||
this->OnNewComboInput.Execute(ComboInput, EComboActionTriggerEvent::Released);
|
||||
}
|
||||
|
||||
UE_LOG(LogInputBufferComponent, Verbose, TEXT("%s is active."), *ComboInput->ComboInputName.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
this->HoldComboInput(ComboInput);
|
||||
}
|
||||
}
|
||||
|
||||
void UInputBufferComponent::HoldComboInput(const UComboInputAsset *ComboInput)
|
||||
{
|
||||
this->InputBufferHold = ComboInput;
|
||||
UE_SUPPRESS(LogInputBufferComponent, Verbose,
|
||||
{
|
||||
if (this->LockedComboInputs.Contains(ComboInput))
|
||||
{
|
||||
UE_LOG(LogInputBufferComponent, Verbose, TEXT("%s is locked and won't be activated yet."), *ComboInput->ComboInputName.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(LogInputBufferComponent, Verbose, TEXT("%s added to buffer."), *ComboInput->ComboInputName.ToString());
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
void UInputBufferComponent::LockComboInput(const UComboInputAsset *Input)
|
||||
{
|
||||
this->LockedComboInputs.Emplace(Input);
|
||||
}
|
||||
|
||||
void UInputBufferComponent::UnlockComboInput(const UComboInputAsset *Unlocked)
|
||||
{
|
||||
// Remove the newly-unlocked asset from the locked combo inputs.
|
||||
UE_CLOG(this->LockedComboInputs.Contains(Unlocked), LogInputBufferComponent, Verbose, TEXT("%s has unlocked."), *Unlocked->ComboInputName.ToString());
|
||||
this->LockedComboInputs.Remove(Unlocked);
|
||||
|
||||
// Check if the newly unlocked combo input is in the hold.
|
||||
if (Unlocked == this->InputBufferHold)
|
||||
{
|
||||
const UComboInputAsset *OriginalActive = this->InputBufferActive;
|
||||
|
||||
// Activate the held combo input.
|
||||
const UComboInputAsset *HeldAsset = this->InputBufferHold;
|
||||
this->InputBufferHold = nullptr;
|
||||
if (HeldAsset)
|
||||
{
|
||||
this->ActivateComboInput(HeldAsset);
|
||||
}
|
||||
|
||||
UE_LOG(LogInputBufferComponent, Verbose, TEXT("%s has expired."), *OriginalActive->ComboInputName.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
void UInputBufferComponent::ExpireAction(const FInputActionValue &Value, const class UInputAction *Action)
|
||||
{
|
||||
// Only send a release event if we haven't already, i.e. if the combo input associated
|
||||
// with the action is not already buffered for another future activation.
|
||||
if (this->InputBufferActive && this->InputBufferActive != this->InputBufferHold && this->InputBufferActive->MatchesInputAction(Action))
|
||||
{
|
||||
this->OnNewComboInput.Execute(this->InputBufferActive, EComboActionTriggerEvent::Released);
|
||||
}
|
||||
|
||||
// Prepare to expire any buffered combo inputs
|
||||
this->ExpiringActions.Add(Action);
|
||||
const UInputBufferGlobalSettings *Settings = GetDefault<UInputBufferGlobalSettings>();
|
||||
this->GetWorld()->GetTimerManager().SetTimer(this->InputReleaseExpirationTimerHandle, this, &UInputBufferComponent::ExpireBufferedActions, Settings->InputReleaseExpirationTimerLength);
|
||||
}
|
||||
void UInputBufferComponent::ExpireBufferedActions()
|
||||
{
|
||||
// Only bother dealing with this if there's something to deal with in the first place.
|
||||
if (!this->ExpiringActions.IsEmpty())
|
||||
{
|
||||
UE_SUPPRESS(LogInputBufferComponent, Verbose,
|
||||
{
|
||||
TArray<FString> ActionNames;
|
||||
for (const UInputAction *Action : this->ExpiringActions)
|
||||
{
|
||||
ActionNames.Add(Action->GetName());
|
||||
}
|
||||
UE_LOG(LogInputBufferComponent, Verbose, TEXT("Released actions expired (%s)"), *FString::Join(ActionNames, TEXT(" | ")));
|
||||
}
|
||||
);
|
||||
|
||||
// If there is an action in the hold, check if it's related
|
||||
// to our current released buttons, and if so cancel it.
|
||||
if (this->InputBufferHold)
|
||||
{
|
||||
for (const UInputAction *Action : this->ExpiringActions)
|
||||
{
|
||||
if (this->InputBufferHold->MatchesInputAction(Action))
|
||||
{
|
||||
UE_LOG(LogInputBufferComponent, Verbose, TEXT("%s has been cancelled."), *this->InputBufferHold->ComboInputName.ToString());
|
||||
this->InputBufferHold = nullptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this->ExpiringActions.Empty();
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
// ©2023 Batty Bovine Productions, LLC. All Rights Reserved.
|
||||
|
||||
#include "GlobalSettings/InputBufferGlobalSettings.h"
|
||||
#include "GlobalSettings/InputBufferSubsystemGlobalSettings.h"
|
||||
|
||||
|
||||
|
||||
202
Source/ComboInput/Private/InputBufferLocalPlayerSubsystem.cpp
Normal file
@ -0,0 +1,202 @@
|
||||
// ©2022 Batty Bovine Productions, LLC. All Rights Reserved.
|
||||
|
||||
#include "InputBufferLocalPlayerSubsystem.h"
|
||||
|
||||
#include "ComboInputAssets.h"
|
||||
#include "EnhancedInputComponent.h"
|
||||
|
||||
#include "Components/ComboManagerComponent.h"
|
||||
#include "GlobalSettings/InputBufferSubsystemGlobalSettings.h"
|
||||
|
||||
DEFINE_LOG_CATEGORY(LogInputBufferLocalPlayerSubsystem);
|
||||
|
||||
|
||||
void UInputBufferLocalPlayerSubsystem::Initialize(FSubsystemCollectionBase &Collection)
|
||||
{
|
||||
Super::Initialize(Collection);
|
||||
}
|
||||
|
||||
void UInputBufferLocalPlayerSubsystem::AttachComboManager(UComboManagerComponent *ComboManager, UEnhancedInputComponent *InputComponent)
|
||||
{
|
||||
// Get the player character and try to connect to its combo manager.
|
||||
this->OnNewComboInput.BindUObject(ComboManager, &UComboManagerComponent::HandleComboInput);
|
||||
|
||||
// Get all unique EnhancedInput actions bound to combo input actions.
|
||||
const UInputBufferSubsystemGlobalSettings *Settings = GetDefault<UInputBufferSubsystemGlobalSettings>();
|
||||
TSet<const UInputAction*> InputActionsToBind;
|
||||
for (TSoftObjectPtr<const UComboInputGroup> ComboInput : Settings->ComboActions)
|
||||
{
|
||||
for (const UInputAction *InputAction : ComboInput->ActionGroup)
|
||||
{
|
||||
InputActionsToBind.Add(InputAction);
|
||||
}
|
||||
}
|
||||
for (const UInputAction *InputAction : InputActionsToBind)
|
||||
{
|
||||
InputComponent->BindAction(InputAction, ETriggerEvent::Started, this, &UInputBufferLocalPlayerSubsystem::AddActionToBuffer, InputAction);
|
||||
InputComponent->BindAction(InputAction, ETriggerEvent::Completed, this, &UInputBufferLocalPlayerSubsystem::ExpireAction, InputAction);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void UInputBufferLocalPlayerSubsystem::AddActionToBuffer(const FInputActionValue &Value, const class UInputAction *Action)
|
||||
{
|
||||
this->MostRecentActions.Add(Action);
|
||||
this->ExpiringActions.Remove(Action);
|
||||
|
||||
// Find any combo input that matches this action, plus buffered actions.
|
||||
const UInputBufferSubsystemGlobalSettings *Settings = GetDefault<UInputBufferSubsystemGlobalSettings>();
|
||||
for (TSoftObjectPtr<const UComboInputGroup> ComboInput : Settings->ComboActions)
|
||||
{
|
||||
if (ComboInput->MatchesInputActions(this->MostRecentActions))
|
||||
{
|
||||
this->ActivateComboInput(ComboInput.Get());
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this->GetWorld()->GetTimerManager().SetTimer(this->MultiPressTimerHandle, this, &UInputBufferLocalPlayerSubsystem::ClearMultiPresses, Settings->MultiPressTimerLength);
|
||||
}
|
||||
void UInputBufferLocalPlayerSubsystem::ClearMultiPresses()
|
||||
{
|
||||
#if WITH_EDITOR
|
||||
TArray<FString> ActionNames;
|
||||
for (const UInputAction *Action : this->MostRecentActions)
|
||||
{
|
||||
ActionNames.Add(Action->GetName());
|
||||
}
|
||||
UE_LOG(LogInputBufferLocalPlayerSubsystem, Verbose, TEXT("Multi-press buffer cleared (%s)"), *FString::Join(ActionNames, TEXT(" | ")));
|
||||
#endif
|
||||
this->MostRecentActions.Empty();
|
||||
}
|
||||
|
||||
void UInputBufferLocalPlayerSubsystem::ActivateComboInput(const UInputAction *ComboInput)
|
||||
{
|
||||
const bool bNewInputLocked = this->LockedComboInputs.Contains(ComboInput);
|
||||
const bool bNewSupercedesActive = (this->InputBufferActive && this->InputBufferActive->ContainsOneOf(ComboInput->ActionGroup) && !bNewInputLocked);
|
||||
|
||||
// Make this combo input active if it isn't being locked, or if we are
|
||||
// overwriting a previous combo input with a multi-press combo input.
|
||||
if (bNewSupercedesActive || !bNewInputLocked)
|
||||
{
|
||||
// Set the combo input as active.
|
||||
this->InputBufferActive = ComboInput;
|
||||
|
||||
// If we have inputs to lock, prepare the buffer.
|
||||
if (!ComboInput->LockedComboInputs.IsEmpty())
|
||||
{
|
||||
this->LockedComboInputs = ComboInput->LockedComboInputs;
|
||||
|
||||
this->InputBufferHold = nullptr;
|
||||
|
||||
UE_LOG(LogInputBufferLocalPlayerSubsystem, Verbose, TEXT("%s is active."), *ComboInput->ComboInputName.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(LogInputBufferLocalPlayerSubsystem, Verbose, TEXT("%s is active and won't lock inputs."), *ComboInput->ComboInputName.ToString());
|
||||
}
|
||||
|
||||
this->OnNewComboInput.Execute(ComboInput, EComboActionTriggerEvent::Activated);
|
||||
|
||||
// If the incoming combo input contains an expiring action,
|
||||
// we know it's been released, so send that signal too.
|
||||
if (ComboInput->ContainsOneOf(this->ExpiringActions))
|
||||
{
|
||||
this->OnNewComboInput.Execute(ComboInput, EComboActionTriggerEvent::Released);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this->HoldComboInput(ComboInput);
|
||||
}
|
||||
}
|
||||
|
||||
void UInputBufferLocalPlayerSubsystem::HoldComboInput(const UInputAction *ComboInput)
|
||||
{
|
||||
this->InputBufferHold = ComboInput;
|
||||
UE_SUPPRESS(LogInputBufferLocalPlayerSubsystem, Verbose,
|
||||
{
|
||||
if (this->LockedComboInputs.Contains(ComboInput))
|
||||
{
|
||||
UE_LOG(LogInputBufferLocalPlayerSubsystem, Verbose, TEXT("%s is locked and won't be activated yet."), *ComboInput->ComboInputName.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(LogInputBufferLocalPlayerSubsystem, Verbose, TEXT("%s added to buffer."), *ComboInput->ComboInputName.ToString());
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
void UInputBufferLocalPlayerSubsystem::UnlockComboInput(const UInputAction *Unlocked)
|
||||
{
|
||||
// Remove the newly-unlocked asset from the locked combo inputs.
|
||||
UE_CLOG(this->LockedComboInputs.Contains(Unlocked), LogInputBufferLocalPlayerSubsystem, Verbose, TEXT("%s has unlocked."), *Unlocked->ComboInputName.ToString());
|
||||
this->LockedComboInputs.Remove(Unlocked);
|
||||
|
||||
// Check if the newly unlocked combo input is in the hold.
|
||||
if (Unlocked == this->InputBufferHold)
|
||||
{
|
||||
const UComboInputAsset *OriginalActive = this->InputBufferActive;
|
||||
|
||||
// Activate the held combo input.
|
||||
const UInputAction *HeldAsset = this->InputBufferHold;
|
||||
this->InputBufferHold = nullptr;
|
||||
if (HeldAsset)
|
||||
{
|
||||
this->ActivateComboInput(HeldAsset);
|
||||
}
|
||||
|
||||
UE_LOG(LogInputBufferLocalPlayerSubsystem, Verbose, TEXT("%s has expired."), *OriginalActive->ComboInputName.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
void UInputBufferLocalPlayerSubsystem::ExpireAction(const FInputActionValue &Value, const class UInputAction *Action)
|
||||
{
|
||||
// Only send a release event if we haven't already, i.e. if the combo input associated
|
||||
// with the action is not already buffered for another future activation.
|
||||
if (this->InputBufferActive && this->InputBufferActive != this->InputBufferHold && this->InputBufferActive->MatchesInputAction(Action))
|
||||
{
|
||||
this->OnNewComboInput.Execute(this->InputBufferActive, EComboActionTriggerEvent::Released);
|
||||
}
|
||||
|
||||
// Prepare to expire any buffered combo inputs
|
||||
this->ExpiringActions.Add(Action);
|
||||
const UInputBufferSubsystemGlobalSettings *Settings = GetDefault<UInputBufferSubsystemGlobalSettings>();
|
||||
this->GetWorld()->GetTimerManager().SetTimer(this->InputReleaseExpirationTimerHandle, this, &UInputBufferLocalPlayerSubsystem::ExpireBufferedActions, Settings->InputReleaseExpirationTimerLength);
|
||||
}
|
||||
void UInputBufferLocalPlayerSubsystem::ExpireBufferedActions()
|
||||
{
|
||||
// Only bother dealing with this if there's something to deal with in the first place.
|
||||
if (!this->ExpiringActions.IsEmpty())
|
||||
{
|
||||
UE_SUPPRESS(LogInputBufferLocalPlayerSubsystem, Verbose,
|
||||
{
|
||||
TArray<FString> ActionNames;
|
||||
for (const UInputAction *Action : this->ExpiringActions)
|
||||
{
|
||||
ActionNames.Add(Action->GetName());
|
||||
}
|
||||
UE_LOG(LogInputBufferLocalPlayerSubsystem, Verbose, TEXT("Released actions expired (%s)"), *FString::Join(ActionNames, TEXT(" | ")));
|
||||
}
|
||||
);
|
||||
|
||||
// If there is an action in the hold, check if it's related
|
||||
// to our current released buttons, and if so cancel it.
|
||||
if (this->InputBufferHold)
|
||||
{
|
||||
for (const UInputAction *Action : this->ExpiringActions)
|
||||
{
|
||||
if (this->InputBufferHold->MatchesInputAction(Action))
|
||||
{
|
||||
UE_LOG(LogInputBufferLocalPlayerSubsystem, Verbose, TEXT("%s has been cancelled."), *this->InputBufferHold->ComboInputName.ToString());
|
||||
this->InputBufferHold = nullptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this->ExpiringActions.Empty();
|
||||
}
|
||||
}
|
||||
@ -1,6 +0,0 @@
|
||||
// ©2023 Batty Bovine Productions, LLC. All Rights Reserved.
|
||||
|
||||
#include "Nodes/ComboActionGraphEdge.h"
|
||||
|
||||
|
||||
|
||||
@ -1,203 +0,0 @@
|
||||
// ©2023 Batty Bovine Productions, LLC. All Rights Reserved.
|
||||
|
||||
#include "Nodes/ComboActionGraphNode.h"
|
||||
|
||||
#include "ComboActionGraph.h"
|
||||
#include "ComboInputAssets.h"
|
||||
#include "ComboInputTriggers.h"
|
||||
|
||||
DEFINE_LOG_CATEGORY(LogComboActionGraphNode);
|
||||
|
||||
#define LOCTEXT_NAMESPACE "ComboActionGraphNode"
|
||||
|
||||
|
||||
UComboActionGraphNode::UComboActionGraphNode()
|
||||
{
|
||||
this->NodeGUID = FGuid::NewGuid();
|
||||
|
||||
this->bEnabled = true;
|
||||
|
||||
#if WITH_EDITORONLY_DATA
|
||||
this->CompatibleGraphType = UComboActionGraph::StaticClass();
|
||||
|
||||
this->BackgroundColor = FLinearColor::Black;
|
||||
|
||||
this->bAllowInputNodes = true;
|
||||
this->bAllowOutputNodes = true;
|
||||
|
||||
this->bAllowCopy = true;
|
||||
this->bAllowCut = true;
|
||||
this->bAllowDelete = true;
|
||||
this->bAllowPaste = true;
|
||||
this->bAllowManualCreate = true;
|
||||
|
||||
this->NodeTypeName = LOCTEXT("ComboActionGraphNode_InternalName", "ComboActionGraphNode");
|
||||
this->NodeTooltipText = LOCTEXT("ComboActionGraphNode_Tooltip", "Combo action graph base node. Child nodes provide more information.");
|
||||
#endif
|
||||
}
|
||||
|
||||
void UComboActionGraphNode::SetNewWorld(UWorld *NewWorld)
|
||||
{
|
||||
if (NewWorld)
|
||||
{
|
||||
this->OwningWorld = NewWorld;
|
||||
}
|
||||
}
|
||||
|
||||
void UComboActionGraphNode::InitializeNode_Implementation(UWorld *InWorld)
|
||||
{
|
||||
this->SetNewWorld(InWorld);
|
||||
|
||||
if (this->Graph)
|
||||
{
|
||||
this->SetNodeIndex(this->Graph->AllNodes.Find(this));
|
||||
}
|
||||
}
|
||||
|
||||
void UComboActionGraphNode::ProcessNode(const TScriptInterface<IComboActionGraphManagerInterface> &Manager)
|
||||
{
|
||||
if (!this->GetWorld())
|
||||
{
|
||||
UE_LOG(LogComboActionGraphNode, Error, TEXT("[ProcessNode] Cannot find World!"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this->GetGraph())
|
||||
{
|
||||
UE_LOG(LogComboActionGraphNode, Error, TEXT("[ProcessNode] Invalid owning Graph!!"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void UComboActionGraphNode::SetNodeIndex(const int32 NewIndex)
|
||||
{
|
||||
check(NewIndex>INDEX_NONE);
|
||||
this->NodeIndex = NewIndex;
|
||||
}
|
||||
|
||||
#if WITH_EDITOR
|
||||
|
||||
FText UComboActionGraphNode::GetDescription_Implementation() const
|
||||
{
|
||||
return LOCTEXT("NodeDesc", "Mountea Dialogue Graph Node");
|
||||
}
|
||||
|
||||
FText UComboActionGraphNode::GetNodeCategory_Implementation() const
|
||||
{
|
||||
return LOCTEXT("NodeCategory", "Mountea Dialogue Tree Node");
|
||||
}
|
||||
|
||||
FString UComboActionGraphNode::GetNodeDocumentationLink_Implementation() const
|
||||
{
|
||||
return TEXT("A link to the documentation for this plugin will go here.");
|
||||
}
|
||||
|
||||
FText UComboActionGraphNode::GetNodeTooltipText_Implementation() const
|
||||
{
|
||||
return FText::Format(LOCTEXT("ComboActionGraphNode_FinalTooltip", "{0}\n\n{1}"), this->GetDefaultTooltipBody(), this->NodeTooltipText);
|
||||
}
|
||||
|
||||
bool UComboActionGraphNode::CanCreateConnection(UComboActionGraphNode *Other, enum EEdGraphPinDirection Direction, FText &ErrorMessage)
|
||||
{
|
||||
if (Other == nullptr)
|
||||
{
|
||||
ErrorMessage = FText::FromString("Invalid Other Node!");
|
||||
}
|
||||
|
||||
if (Other->GetMaxChildNodes() > -1 && Other->ChildNodes.Num() >= Other->GetMaxChildNodes())
|
||||
{
|
||||
const FString TextReturn =
|
||||
FString(Other->GetNodeTitle().ToString()).
|
||||
Append(": Cannot have more than ").Append(FString::FromInt(Other->GetMaxChildNodes())).Append(" Children Nodes!");
|
||||
|
||||
ErrorMessage = FText::FromString(TextReturn);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Direction == EEdGraphPinDirection::EGPD_Output)
|
||||
{
|
||||
|
||||
// Fast checking for native classes
|
||||
if ( AllowedInputClasses.Contains(Other->GetClass()) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Slower iterative checking for child classes
|
||||
for (auto Itr : AllowedInputClasses)
|
||||
{
|
||||
if (Other->GetClass()->IsChildOf(Itr))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
ErrorMessage = FText::FromString("Invalid Node Connection!");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UComboActionGraphNode::ValidateNode(TArray<FText> &ValidationsMessages, const bool RichFormat)
|
||||
{
|
||||
bool bResult = true;
|
||||
|
||||
if (this->ParentNodes.Num() == 0 && this->ChildNodes.Num() == 0)
|
||||
{
|
||||
bResult = false;
|
||||
|
||||
const FString RichTextReturn =
|
||||
FString("* ")
|
||||
.Append("<RichTextBlock.Bold>")
|
||||
.Append(this->NodeTitle.ToString())
|
||||
.Append("</>")
|
||||
.Append(": This Node has no Connections!");
|
||||
|
||||
const FString TextReturn =
|
||||
FString(this->NodeTitle.ToString())
|
||||
.Append(": This Node has no Connections!");
|
||||
|
||||
ValidationsMessages.Add(FText::FromString(RichFormat ? RichTextReturn : TextReturn));
|
||||
}
|
||||
|
||||
if (this->bAllowInputNodes && this->ParentNodes.Num() == 0)
|
||||
{
|
||||
bResult = false;
|
||||
|
||||
const FString RichTextReturn =
|
||||
FString("* ")
|
||||
.Append("<RichTextBlock.Bold>")
|
||||
.Append(this->NodeTitle.ToString())
|
||||
.Append("</>")
|
||||
.Append(": This node requires inputs, however none are found!");
|
||||
|
||||
const FString TextReturn =
|
||||
FString(this->NodeTitle.ToString())
|
||||
.Append(": This node requires inputs, however none are found!");
|
||||
|
||||
ValidationsMessages.Add(FText::FromString(RichFormat ? RichTextReturn : TextReturn));
|
||||
}
|
||||
|
||||
return bResult;
|
||||
}
|
||||
|
||||
void UComboActionGraphNode::OnPasted()
|
||||
{
|
||||
this->NodeGUID = FGuid::NewGuid();
|
||||
|
||||
this->ParentNodes.Empty();
|
||||
this->ChildNodes.Empty();
|
||||
this->Edges.Empty();
|
||||
}
|
||||
|
||||
FText UComboActionGraphNode::GetDefaultTooltipBody() const
|
||||
{
|
||||
//const FText Inherits = FText::Format(LOCTEXT("UComboActionGraphNode_InheritsTooltip", "Inherits Graph Decorators: {0}"), InheritsValue);
|
||||
//const FText Implements = FText::Format(LOCTEXT("UComboActionGraphNode_ImplementsTooltip", "Implements Decorators: {0}"), ImplementsNumber);
|
||||
return FText::Format(LOCTEXT("UComboActionGraphNode_BaseTooltip", "{0}\n\n{1}\n{2}"), this->NodeTypeName, this->NodeTypeName, this->NodeTypeName);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#undef LOCTEXT_NAMESPACE
|
||||
@ -1,49 +0,0 @@
|
||||
// ©2023 Batty Bovine Productions, LLC. All Rights Reserved.
|
||||
|
||||
#include "Nodes/ComboActionGraphNode_ActionNode.h"
|
||||
#include "Nodes/ComboActionGraphNode_StartNode.h"
|
||||
|
||||
#define LOCTEXT_NAMESPACE "ComboActionGraphNode_ActionNode"
|
||||
|
||||
|
||||
UComboActionGraphNode_ActionNode::UComboActionGraphNode_ActionNode()
|
||||
{
|
||||
#if WITH_EDITORONLY_DATA
|
||||
this->NodeTitle = LOCTEXT("ComboActionGraphNode_ActionNodeTitle", "Action Node");
|
||||
this->NodeTypeName = LOCTEXT("ComboActionGraphNode_ActionNodeInternalTitle", "Action Node");
|
||||
this->ContextMenuName = LOCTEXT("ComboActionGraphNode_ActionNodeContextMenuName", "Action Node");
|
||||
|
||||
this->NodeTooltipText = LOCTEXT("ComboActionGraphNode_ActionTooltip", "Action node is a node which contains combo actions based on inputs.");
|
||||
#endif
|
||||
|
||||
this->AllowedInputClasses.Add(UComboActionGraphNode_StartNode::StaticClass());
|
||||
this->AllowedInputClasses.Add(UComboActionGraphNode_ActionNode::StaticClass());
|
||||
|
||||
this->MaxChildNodes = -1;
|
||||
}
|
||||
|
||||
void UComboActionGraphNode_ActionNode::PreProcessNode(const TScriptInterface<IComboActionGraphManagerInterface> &Manager)
|
||||
{
|
||||
Super::PreProcessNode(Manager);
|
||||
}
|
||||
|
||||
void UComboActionGraphNode_ActionNode::ProcessNode(const TScriptInterface<IComboActionGraphManagerInterface> &Manager)
|
||||
{
|
||||
Super::ProcessNode(Manager);
|
||||
}
|
||||
|
||||
#if WITH_EDITOR
|
||||
|
||||
FText UComboActionGraphNode_ActionNode::GetDescription_Implementation() const
|
||||
{
|
||||
return LOCTEXT("ComboActionGraphNode_ActionNodeDescription", "Action node is a node which contains combo actions based on inputs.");
|
||||
}
|
||||
|
||||
FText UComboActionGraphNode_ActionNode::GetNodeCategory_Implementation() const
|
||||
{
|
||||
return LOCTEXT("ComboActionGraphNode_ActionNodeCategory", "Combo Action Branch Nodes");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#undef LOCTEXT_NAMESPACE
|
||||
@ -1,181 +0,0 @@
|
||||
// ©2023 Batty Bovine Productions, LLC. All Rights Reserved.
|
||||
|
||||
#include "Nodes/ComboActionGraphNode_ActionNodeBase.h"
|
||||
|
||||
#include "ComboInputAssets.h"
|
||||
|
||||
#define LOCTEXT_NAMESPACE "ComboActionGraphNode_ActionNodeBase"
|
||||
|
||||
|
||||
UComboActionGraphNode_ActionNodeBase::UComboActionGraphNode_ActionNodeBase()
|
||||
{
|
||||
#if WITH_EDITORONLY_DATA
|
||||
this->NodeTitle = LOCTEXT("ComboActionGraphNode_ActionNodeBaseTitle", "Action Node Base");
|
||||
this->NodeTypeName = LOCTEXT("ComboActionGraphNode_ActionNodeBaseInternalTitle", "Action Node Base");
|
||||
this->ContextMenuName = LOCTEXT("ComboActionGraphNode_ActionNodeBaseContextMenu", "Action Node");
|
||||
|
||||
this->NodeTooltipText = LOCTEXT("ComboActionGraphNode_BaseTooltip", "* Abstract class, should not appear in graph editor.\n* Enhances 'ComboActionGraphNode' Base class with action data.");
|
||||
#endif
|
||||
}
|
||||
|
||||
void UComboActionGraphNode_ActionNodeBase::ProcessNode(const TScriptInterface<IComboActionGraphManagerInterface> &Manager)
|
||||
{
|
||||
Super::ProcessNode(Manager);
|
||||
}
|
||||
|
||||
void UComboActionGraphNode_ActionNodeBase::PreProcessNode(const TScriptInterface<IComboActionGraphManagerInterface> &Manager)
|
||||
{
|
||||
Super::PreProcessNode(Manager);
|
||||
}
|
||||
|
||||
bool UComboActionGraphNode_ActionNodeBase::ValidateNodeRuntime_Implementation() const
|
||||
{
|
||||
if (!this->ComboInput)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this->TriggerEvent == EComboActionTriggerEvent::None)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!this->ComboAction)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this->MaxChildNodes > -1 && this->ChildNodes.Num() > this->MaxChildNodes)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#if WITH_EDITOR
|
||||
|
||||
bool UComboActionGraphNode_ActionNodeBase::ValidateNode(TArray<FText> &ValidationsMessages, const bool RichFormat)
|
||||
{
|
||||
bool bResult = Super::ValidateNode(ValidationsMessages, RichFormat);
|
||||
|
||||
if (!this->ComboInput)
|
||||
{
|
||||
bResult = false;
|
||||
|
||||
const FString RichTextReturn =
|
||||
FString("* ").
|
||||
Append("<RichTextBlock.Bold>").
|
||||
Append(NodeTitle.ToString()).
|
||||
Append("</>").
|
||||
Append(": Does not reference a valid combo input!");
|
||||
|
||||
const FString TextReturn =
|
||||
FString(NodeTitle.ToString()).
|
||||
Append(": Does not reference a valid combo input!");
|
||||
|
||||
ValidationsMessages.Add(FText::FromString(RichFormat ? RichTextReturn : TextReturn));
|
||||
}
|
||||
|
||||
if (this->TriggerEvent == EComboActionTriggerEvent::None)
|
||||
{
|
||||
bResult = false;
|
||||
|
||||
const FString RichTextReturn =
|
||||
FString("* ").
|
||||
Append("<RichTextBlock.Bold>").
|
||||
Append(NodeTitle.ToString()).
|
||||
Append("</>").
|
||||
Append(": Does not reference a valid trigger event!");
|
||||
|
||||
const FString TextReturn =
|
||||
FString(NodeTitle.ToString()).
|
||||
Append(": Does not reference a valid trigger event!");
|
||||
|
||||
ValidationsMessages.Add(FText::FromString(RichFormat ? RichTextReturn : TextReturn));
|
||||
}
|
||||
|
||||
if (!this->ComboAction)
|
||||
{
|
||||
bResult = false;
|
||||
|
||||
const FString RichTextReturn =
|
||||
FString("* ").
|
||||
Append("<RichTextBlock.Bold>").
|
||||
Append(NodeTitle.ToString()).
|
||||
Append("</>").
|
||||
Append(": Does not reference a valid combo action!");
|
||||
|
||||
const FString TextReturn =
|
||||
FString(NodeTitle.ToString()).
|
||||
Append(": Does not reference a valid combo action!");
|
||||
|
||||
ValidationsMessages.Add(FText::FromString(RichFormat ? RichTextReturn : TextReturn));
|
||||
}
|
||||
|
||||
if (this->MaxChildNodes > -1 && this->ChildNodes.Num() > this->MaxChildNodes)
|
||||
{
|
||||
const FString RichTextReturn = FString("* ")
|
||||
.Append("<RichTextBlock.Bold>")
|
||||
.Append(this->NodeTitle.ToString())
|
||||
.Append("</>")
|
||||
.Append(": Has more than ")
|
||||
.Append("<RichTextBlock.Bold>")
|
||||
.Append(FString::FromInt(this->MaxChildNodes))
|
||||
.Append("</>")
|
||||
.Append(" child nodes!");
|
||||
|
||||
const FString TextReturn = FString(this->NodeTitle.ToString())
|
||||
.Append(": Has more than ").Append(FString::FromInt(this->MaxChildNodes)).Append(" child nodes!");
|
||||
|
||||
ValidationsMessages.Add(FText::FromString(RichFormat ? RichTextReturn : TextReturn));
|
||||
}
|
||||
|
||||
return bResult;
|
||||
}
|
||||
|
||||
void UComboActionGraphNode_ActionNodeBase::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent)
|
||||
{
|
||||
Super::PostEditChangeProperty(PropertyChangedEvent);
|
||||
|
||||
if (PropertyChangedEvent.GetPropertyName() == GET_MEMBER_NAME_CHECKED(UComboActionGraphNode_ActionNodeBase, ComboInput))
|
||||
{
|
||||
this->Preview.Empty();
|
||||
this->PreviewsUpdated.ExecuteIfBound();
|
||||
}
|
||||
|
||||
if (PropertyChangedEvent.GetPropertyName() == GET_MEMBER_NAME_CHECKED(UComboActionGraphNode_ActionNodeBase, TriggerEvent))
|
||||
{
|
||||
this->UpdatePreviews();
|
||||
this->PreviewsUpdated.ExecuteIfBound();
|
||||
}
|
||||
}
|
||||
|
||||
#if WITH_EDITOR
|
||||
FLinearColor UComboActionGraphNode_ActionNodeBase::GetBackgroundColour() const
|
||||
{
|
||||
if (this->ComboAction && this->ComboAction->NodeColor != FLinearColor())
|
||||
{
|
||||
return this->ComboAction->NodeColor;
|
||||
}
|
||||
else if (this->ComboInput)
|
||||
{
|
||||
return this->ComboInput->NodeColor;
|
||||
}
|
||||
return Super::GetBackgroundColour();
|
||||
}
|
||||
#endif
|
||||
|
||||
FText UComboActionGraphNode_ActionNodeBase::GetDescription_Implementation() const
|
||||
{
|
||||
return LOCTEXT("ComboActionGraphNode_BaseDescription", "Action base node has no logic tied to itself.");
|
||||
}
|
||||
|
||||
TArray<FText> UComboActionGraphNode_ActionNodeBase::GetPreviews() const
|
||||
{
|
||||
return TArray<FText>();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#undef LOCTEXT_NAMESPACE
|
||||
@ -1,63 +0,0 @@
|
||||
// ©2023 Batty Bovine Productions, LLC. All Rights Reserved.
|
||||
|
||||
#include "Nodes/ComboActionGraphNode_StartNode.h"
|
||||
|
||||
#define LOCTEXT_NAMESPACE "ComboActionGraphNode_StartNode"
|
||||
|
||||
|
||||
UComboActionGraphNode_StartNode::UComboActionGraphNode_StartNode()
|
||||
{
|
||||
#if WITH_EDITORONLY_DATA
|
||||
this->bAllowInputNodes = false;
|
||||
this->NodeTitle = LOCTEXT("ComboActionGraphNode_StartNodeTitle", "Start Action");
|
||||
this->NodeTypeName = LOCTEXT("ComboActionGraphNode_StartNodeInternalTitle", "Start Action");
|
||||
this->ContextMenuName = LOCTEXT("ComboActionGraphNode_StartNodeContextMenuName", "Start Action");
|
||||
this->BackgroundColor = FLinearColor(0.0f, 1.0f, 0.0f, 1.0f);
|
||||
|
||||
this->bAllowCopy = false;
|
||||
this->bAllowCut = false;
|
||||
this->bAllowPaste = false;
|
||||
this->bAllowDelete = false;
|
||||
this->bAllowManualCreate = false;
|
||||
|
||||
this->NodeTooltipText = LOCTEXT("ComboActionGraphNode_CompleteTooltip", "* This Node will be added to the graph automatically.\n* This Node cannot be created manually.\n* This Node cannot be deleted.\n* Does not implement any logic.");
|
||||
#endif
|
||||
|
||||
this->MaxChildNodes = -1;
|
||||
}
|
||||
|
||||
#if WITH_EDITOR
|
||||
|
||||
FText UComboActionGraphNode_StartNode::GetDescription_Implementation() const
|
||||
{
|
||||
return LOCTEXT("ComboActionGraphNode_StartNodeDescription", "Start node is automatically placed and cannot be deleted.");
|
||||
}
|
||||
|
||||
bool UComboActionGraphNode_StartNode::ValidateNode(TArray<FText>& ValidationsMessages, const bool RichFormat)
|
||||
{
|
||||
bool bResult = Super::ValidateNode(ValidationsMessages, RichFormat);
|
||||
|
||||
if (this->ChildNodes.Num() == 0)
|
||||
{
|
||||
bResult = false;
|
||||
|
||||
const FString RichTextReturn =
|
||||
FString("* ")
|
||||
.Append("<RichTextBlock.Bold>")
|
||||
.Append(this->NodeTitle.ToString())
|
||||
.Append("</>")
|
||||
.Append(": Does not have any child nodes!");
|
||||
|
||||
const FString TextReturn =
|
||||
FString(this->NodeTitle.ToString())
|
||||
.Append(": Does not have any child nodes!");
|
||||
|
||||
ValidationsMessages.Add(FText::FromString(RichFormat ? RichTextReturn : TextReturn));
|
||||
}
|
||||
|
||||
return bResult;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#undef LOCTEXT_NAMESPACE
|
||||
@ -1,144 +0,0 @@
|
||||
// ©2023 Batty Bovine Productions, LLC. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
|
||||
#include "Nodes/ComboActionGraphEdge.h"
|
||||
|
||||
#include "ComboActionGraph.generated.h"
|
||||
|
||||
DECLARE_LOG_CATEGORY_EXTERN(LogComboActionGraph, Log, All);
|
||||
|
||||
|
||||
/**
|
||||
* Combo Action graph.
|
||||
*
|
||||
* Can be manually created from Content Browser, using Combo Action category.
|
||||
* Comes with a node editor, which provides easy to follow visual way to create combo strings.
|
||||
*/
|
||||
UCLASS(BlueprintType, ClassGroup=("Combo Input|Action"), DisplayName="Combo Action Tree", HideCategories=("Hidden", "Private", "Base"), AutoExpandCategories=("Combo Input", "Action"))
|
||||
class COMBOINPUT_API UComboActionGraph : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
|
||||
UComboActionGraph();
|
||||
|
||||
#pragma region Variables
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Unique GUID for this graph.
|
||||
* Can be used for debugging and tracing purposes.
|
||||
*/
|
||||
UPROPERTY(BlueprintReadOnly, Category="Combo Input")
|
||||
FGuid GraphGUID;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Pointer to the starting node of the dialogue graph.
|
||||
*/
|
||||
UPROPERTY(BlueprintReadOnly, Category="Combo Input|Action")
|
||||
class UComboActionGraphNode *StartNode = nullptr;
|
||||
/**
|
||||
* The class of the action node represented by this instance.
|
||||
*/
|
||||
UPROPERTY(BlueprintReadOnly, Category="Combo Input|Action")
|
||||
TSubclassOf<UComboActionGraphNode> NodeType;
|
||||
/**
|
||||
* The class of the action edge represented by this instance.
|
||||
*/
|
||||
UPROPERTY(BlueprintReadOnly, Category="Combo Input|Action")
|
||||
TSubclassOf<UComboActionGraphEdge> EdgeType;
|
||||
/**
|
||||
* An array of root nodes in the action graph. These are the nodes that do not have any incoming connections.
|
||||
*/
|
||||
UPROPERTY(BlueprintReadOnly, Category="Combo Input|Action")
|
||||
TArray<UComboActionGraphNode*> RootNodes;
|
||||
/**
|
||||
* Array containing all the nodes in the graph, including both root nodes and child nodes.
|
||||
*/
|
||||
UPROPERTY(BlueprintReadOnly, Category="Combo Input|Action")
|
||||
TArray<UComboActionGraphNode*> AllNodes;
|
||||
|
||||
/**
|
||||
* Set containing actions to be unlocked if their associated nodes are currently locked.
|
||||
*/
|
||||
UPROPERTY(BlueprintReadWrite, Category="Combo Input|Action")
|
||||
TSet<const class UComboAction*> UnlockedActions;
|
||||
|
||||
// Flag indicating whether an edge is enabled
|
||||
UPROPERTY(BlueprintReadOnly, Category="Combo Input|Action")
|
||||
bool bEdgeEnabled;
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Functions
|
||||
|
||||
public:
|
||||
/**
|
||||
* Returns the GUID of the graph.
|
||||
*
|
||||
* @return The GUID of the graph.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category="Combo Input|Action")
|
||||
FGuid GetGraphGUID() const { return this->GraphGUID; }
|
||||
/**
|
||||
* Returns an array containing all nodes in the dialogue graph.
|
||||
* @return An array of all nodes in the dialogue graph.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category="Combo Input|Action")
|
||||
TArray<UComboActionGraphNode*> GetAllNodes() const { return this->AllNodes; }
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category="Combo Input|Action")
|
||||
TArray<UComboActionGraphNode*> GetRootNodes() const { return this->RootNodes; }
|
||||
/**
|
||||
* Returns the first node in the graph.
|
||||
*
|
||||
* @return The start node of this graph.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category="Combo Input|Action")
|
||||
UComboActionGraphNode *GetStartNode() const { return this->StartNode; }
|
||||
|
||||
public:
|
||||
void CreateGraph();
|
||||
void ClearGraph();
|
||||
|
||||
FORCEINLINE bool IsEdgeEnabled() const { return bEdgeEnabled; }
|
||||
|
||||
virtual void PostInitProperties() override;
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#if WITH_EDITORONLY_DATA
|
||||
|
||||
public:
|
||||
UPROPERTY()
|
||||
TObjectPtr<class UEdGraph> EdGraph;
|
||||
|
||||
UPROPERTY(BlueprintReadOnly, Category="Combo Input|Action|Editor")
|
||||
bool bCanRenameNode;
|
||||
|
||||
#endif
|
||||
|
||||
#if WITH_EDITOR
|
||||
|
||||
virtual bool ValidateGraph(TArray<FText> &ValidationErrors, bool RichTextFormat);
|
||||
virtual EDataValidationResult IsDataValid(TArray<FText> &ValidationErrors) override;
|
||||
|
||||
public:
|
||||
|
||||
// Construct and initialize a node within this Dialogue.
|
||||
template<class T>
|
||||
T* ConstructActionNode(TSubclassOf<class UComboActionGraphNode> DialogueNodeClass = T::StaticClass())
|
||||
{
|
||||
// Set flag to be transactional so it registers with undo system
|
||||
T *ActionNode = NewObject<T>(this, DialogueNodeClass, NAME_None, EObjectFlags::RF_Transactional);
|
||||
ActionNode->OnCreatedInEditor();
|
||||
return ActionNode;
|
||||
}
|
||||
|
||||
#endif
|
||||
};
|
||||
@ -4,11 +4,30 @@
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
|
||||
#include "InputAction.h"
|
||||
#include "Engine/DataAsset.h"
|
||||
|
||||
#include "ComboInputAssets.generated.h"
|
||||
|
||||
|
||||
/**
|
||||
* Struct that is used as the value for a combo branch. ComboAction is the action to be
|
||||
* executed, and NextNode is the node that will be activated next in the sequence.
|
||||
*/
|
||||
USTRUCT(BlueprintType)
|
||||
struct COMBOINPUT_API FComboSequenceAction
|
||||
{
|
||||
GENERATED_BODY()
|
||||
public:
|
||||
// Action to perform when the associated combo sequence node is activated.
|
||||
UPROPERTY(BlueprintReadOnly, EditAnywhere)
|
||||
TObjectPtr<const class UComboAction> ComboAction;
|
||||
|
||||
// Sequence node to switch to once this action is complete.
|
||||
UPROPERTY(BlueprintReadOnly, EditAnywhere)
|
||||
TObjectPtr<const class UComboSequenceNode> NextNode;
|
||||
};
|
||||
|
||||
/**
|
||||
* An action that can be executed as part of a combo sequence. This is essentially a
|
||||
* representation of an attack, and can be sent to the Animation Graph to play an
|
||||
@ -23,10 +42,21 @@ public:
|
||||
// Human-readable name of this combo action.
|
||||
UPROPERTY(BlueprintReadOnly, EditAnywhere)
|
||||
FName ActionName;
|
||||
};
|
||||
|
||||
// Sets the colour of the node this action is tied to. Will override any other colours.
|
||||
/**
|
||||
* This represents a node in the combo graph, with each key in the ComboBranch being
|
||||
* an input this node can react to, and each value containing the action to be executed
|
||||
* next, and the node to activate after the action is complete.
|
||||
*/
|
||||
UCLASS(BlueprintType)
|
||||
class COMBOINPUT_API UComboSequenceNode : public UDataAsset
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
UPROPERTY(BlueprintReadOnly, EditAnywhere)
|
||||
FLinearColor NodeColor;
|
||||
TMap<const class UInputAction *, struct FComboSequenceAction> ComboBranch;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -36,7 +66,7 @@ public:
|
||||
* in the current ComboSequenceNode.
|
||||
*/
|
||||
UCLASS(BlueprintType)
|
||||
class COMBOINPUT_API UComboInputAsset : public UDataAsset
|
||||
class COMBOINPUT_API UComboInputGroup : public UInputAction
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
@ -83,16 +113,19 @@ public:
|
||||
}
|
||||
|
||||
// Human-readable name of this combo input.
|
||||
UPROPERTY(BlueprintReadWrite, EditAnywhere)
|
||||
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="Combo Input Group")
|
||||
FName ComboInputName;
|
||||
|
||||
// Combined actions that add up to this combo input when activated
|
||||
// within a short time of one another. If only one is present, then
|
||||
// this combo input asset will simply represent that action.
|
||||
UPROPERTY(BlueprintReadWrite, EditAnywhere)
|
||||
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="Combo Input Group")
|
||||
TSet<const class UInputAction*> ActionGroup;
|
||||
|
||||
// Sets the colour of the node this action is tied to. Can be overridden by UComboAction.
|
||||
UPROPERTY(BlueprintReadOnly, EditAnywhere)
|
||||
FLinearColor NodeColor;
|
||||
// Combo inputs that should be prevented from occurring during this
|
||||
// action. These will be locked when the action is broadcast, and
|
||||
// should be unlocked by the receiving actor by sending an unlock
|
||||
// event.
|
||||
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="Combo Input Group")
|
||||
TSet<TObjectPtr<const class UComboInputAsset>> LockedComboInputs;
|
||||
};
|
||||
|
||||
@ -31,8 +31,8 @@ struct COMBOINPUT_API FComboOffsetMap
|
||||
{
|
||||
GENERATED_BODY()
|
||||
public:
|
||||
UPROPERTY(BlueprintReadOnly, EditAnywhere) TObjectPtr<const class UComboInputAsset> ComboInput;
|
||||
UPROPERTY(BlueprintReadOnly, EditAnywhere) TObjectPtr<const class UComboAction> ComboAction;
|
||||
UPROPERTY(BlueprintReadOnly, EditAnywhere) TObjectPtr<const class UInputAction> ComboInput;
|
||||
UPROPERTY(BlueprintReadOnly, EditAnywhere) TObjectPtr<const class UComboAction> ComboAction;
|
||||
};
|
||||
|
||||
UCLASS(BlueprintType, ClassGroup=(Input), meta=(BlueprintSpawnableComponent))
|
||||
@ -42,13 +42,10 @@ class COMBOINPUT_API UComboManagerComponent : public UActorComponent
|
||||
|
||||
public:
|
||||
UComboManagerComponent();
|
||||
virtual void InitializeComponent() override;
|
||||
virtual void BeginPlay() override;
|
||||
|
||||
UFUNCTION(BlueprintCallable)
|
||||
void SetComboGraph(const class UComboActionGraph *Graph);
|
||||
|
||||
UFUNCTION(BlueprintCallable)
|
||||
void HandleComboInput(const class UComboInputAsset *Input, const EComboActionTriggerEvent &TriggerEvent);
|
||||
void HandleComboInput(const class UInputAction *Input, const EComboActionTriggerEvent &TriggerEvent);
|
||||
|
||||
void BindAction(UObject *ObjectToBindTo, FName FunctionName, const class UComboAction *ComboAction, const EComboActionTriggerEvent &TriggerEvent)
|
||||
{
|
||||
@ -58,12 +55,9 @@ public:
|
||||
this->ComboActionEventBindings.Emplace(Key.Key, MoveTemp(Delegate));
|
||||
}
|
||||
|
||||
// Recursively search the graph for all inputs used by the graph.
|
||||
TSet<const UComboInputAsset *> &FindAllUsedInputs();
|
||||
|
||||
protected:
|
||||
UPROPERTY(BlueprintReadOnly, EditDefaultsOnly)
|
||||
TObjectPtr<const class UComboActionGraph> ComboGraph;
|
||||
TObjectPtr<const class UComboSequenceNode> DefaultStartNode;
|
||||
|
||||
// This input will be recognised as an offset input, which cancels a node transition
|
||||
// if activated early enough in the transition. This locks the current place in the
|
||||
@ -75,43 +69,37 @@ protected:
|
||||
// A list of default input->action mappings. If you wish for an action to be handled
|
||||
// outside the scope of a combo sequence node, it should go here.
|
||||
UPROPERTY(BlueprintReadOnly, EditDefaultsOnly)
|
||||
TMap<TObjectPtr<const class UComboInputAsset>, TObjectPtr<const class UComboAction>> FallbackActions;
|
||||
TMap<TObjectPtr<const class UInputAction>, TObjectPtr<const class UComboAction>> FallbackActions;
|
||||
|
||||
UPROPERTY(BlueprintReadOnly, EditDefaultsOnly)
|
||||
TMap<TObjectPtr<const class UComboInputAsset>, float> DEBUG__UnlockTimers;
|
||||
TMap<TObjectPtr<const class UInputAction>, float> DEBUG__UnlockTimers;
|
||||
|
||||
UPROPERTY(BlueprintReadWrite, BlueprintAssignable)
|
||||
FComboActionHandlerDelegate OnUnhandledAction;
|
||||
|
||||
private:
|
||||
void ActivateComboAction(const class UComboInputAsset *Input);
|
||||
void ReleaseComboAction(const class UComboInputAsset *Input);
|
||||
void ActivateComboAction(const class UInputAction *Input);
|
||||
void ReleaseComboAction(const class UInputAction *Input);
|
||||
|
||||
void BeginNodeTransition(const class UComboActionGraphNode *NextNode);
|
||||
void BeginNodeTransition(const class UComboSequenceNode *NextNode);
|
||||
void FinishTransition();
|
||||
void ResetCombo();
|
||||
|
||||
const UComboActionGraphNode *FindActiveNodeData(const UComboActionGraphNode *CurrentNode, const UComboInputAsset *Input, const EComboActionTriggerEvent TriggerEvent, const UComboAction *&ComboAction);
|
||||
void FindAllUsedInputs_RecurseGraph(const UComboActionGraphNode *CurrentNode, TSet<const UComboInputAsset *> &FoundInputs);
|
||||
|
||||
void BroadcastDelegates(const class UComboAction *ComboAction, const EComboActionTriggerEvent &TriggerEvent);
|
||||
|
||||
void DEBUG__UnlockAction(TObjectPtr<const class UComboInputAsset> Unlock);
|
||||
void DEBUG__UnlockAction(TObjectPtr<const class UInputAction> Unlock);
|
||||
|
||||
TObjectPtr<const class UComboActionGraphNode> ActiveNode = nullptr;
|
||||
TObjectPtr<const class UComboActionGraphNode> PreviousNode = nullptr;
|
||||
TObjectPtr<const class UComboSequenceNode> ActiveNode = nullptr;
|
||||
TObjectPtr<const class UComboSequenceNode> PreviousNode = nullptr;
|
||||
|
||||
TObjectPtr<const class UComboAction> LastComboAction = nullptr;
|
||||
|
||||
TMap<FName, FComboActionHandlerDynamicSignature> ComboActionEventBindings;
|
||||
|
||||
TObjectPtr<class UInputBufferComponent> AttachedInputBuffer;
|
||||
|
||||
// Cache of combo inputs found in the current graph.
|
||||
TSet<const UComboInputAsset *> FoundInputsCache;
|
||||
|
||||
FTimerHandle FinishTransitionTimer;
|
||||
FTimerHandle DEBUG__ResetComboTimer;
|
||||
|
||||
TMap<TObjectPtr<const class UComboInputAsset>, FTimerHandle> DEBUG__TimerHandles;
|
||||
TMap<TObjectPtr<const class UInputAction>, FTimerHandle> DEBUG__TimerHandles;
|
||||
};
|
||||
|
||||
@ -1,65 +0,0 @@
|
||||
// ©2022 Batty Bovine Productions, LLC. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "EnhancedInputComponent.h"
|
||||
|
||||
#include "InputBufferComponent.generated.h"
|
||||
|
||||
DECLARE_LOG_CATEGORY_EXTERN(LogInputBufferComponent, Log, All);
|
||||
|
||||
DECLARE_DELEGATE_TwoParams(FNewComboInput, const class UComboInputAsset*, const EComboActionTriggerEvent &);
|
||||
|
||||
|
||||
/**
|
||||
* Subsystem that handles input buffering, and passing the resulting actions to the player's ComboManagerComponent.
|
||||
*/
|
||||
UCLASS()
|
||||
class COMBOINPUT_API UInputBufferComponent : public UEnhancedInputComponent
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
UInputBufferComponent();
|
||||
virtual void InitializeComponent() override;
|
||||
|
||||
UFUNCTION(BlueprintCallable)
|
||||
void LockComboInput(const class UComboInputAsset *Input);
|
||||
UFUNCTION(BlueprintCallable)
|
||||
void UnlockComboInput(const class UComboInputAsset *Unlocked);
|
||||
|
||||
private:
|
||||
void AddActionToBuffer(const FInputActionValue &Value, const class UInputAction *Action);
|
||||
void ExpireAction(const FInputActionValue &Value, const class UInputAction *Action);
|
||||
|
||||
void ActivateComboInput(const class UComboInputAsset *ComboInput);
|
||||
void HoldComboInput(const class UComboInputAsset *ComboInput);
|
||||
|
||||
void ClearMultiPresses();
|
||||
void ExpireBufferedActions();
|
||||
|
||||
TObjectPtr<class UEnhancedInputComponent> EnhancedInputComponent;
|
||||
|
||||
// Currently active combo input.
|
||||
TObjectPtr<const class UComboInputAsset> InputBufferActive;
|
||||
|
||||
// Combo input held until the current input has expired.
|
||||
TObjectPtr<const class UComboInputAsset> InputBufferHold;
|
||||
|
||||
// Set of currently locked actions; will not be activated until an unlock signal is received.
|
||||
TSet<TObjectPtr<const class UComboInputAsset>> LockedComboInputs;
|
||||
|
||||
// A local backup of the global setting containing the list of combo inputs to respond to.
|
||||
TSet<TObjectPtr<const UComboInputAsset>> ComboInputList;
|
||||
|
||||
TSet<const class UInputAction*> MultiPressActions;
|
||||
TSet<const class UInputAction*> UnhandledActions;
|
||||
TSet<const class UInputAction*> ExpiringActions;
|
||||
|
||||
FNewComboInput OnNewComboInput;
|
||||
|
||||
FTimerHandle MultiPressTimerHandle;
|
||||
FTimerHandle InputReleaseExpirationTimerHandle;
|
||||
FTimerHandle ForceUnlockTimerHandle;
|
||||
};
|
||||
@ -4,18 +4,24 @@
|
||||
|
||||
#include "Engine/DeveloperSettingsBackedByCVars.h"
|
||||
|
||||
#include "InputBufferGlobalSettings.generated.h"
|
||||
#include "InputBufferSubsystemGlobalSettings.generated.h"
|
||||
|
||||
|
||||
/**
|
||||
* Global settings for the input buffer
|
||||
* Global settings for the input buffer subsystem
|
||||
*/
|
||||
UCLASS(Config=Game, defaultconfig, meta=(DisplayName="Input Buffer"))
|
||||
class COMBOINPUT_API UInputBufferGlobalSettings : public UDeveloperSettingsBackedByCVars
|
||||
UCLASS(Config=Game, defaultconfig, meta=(DisplayName="Input Buffer Subsystem"))
|
||||
class COMBOINPUT_API UInputBufferSubsystemGlobalSettings : public UDeveloperSettingsBackedByCVars
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
// List of possible combo inputs that can be taken. A combo input is selected from this list
|
||||
// either if an action is made while the current combo is inactive, or when the previous
|
||||
// action expires.
|
||||
UPROPERTY(Config, BlueprintReadOnly, EditDefaultsOnly)
|
||||
TSet<TSoftObjectPtr<const class UComboInputGroup>> ComboActions;
|
||||
|
||||
// Length of time after releasing an input to keep the associated combo action buffered before clearing it.
|
||||
UPROPERTY(Config, BlueprintReadOnly, EditDefaultsOnly, meta=(UIMin="0.0", UIMax="0.5", ClampMin="0.0", ClampMax="0.5"))
|
||||
float InputReleaseExpirationTimerLength = 0.15f;
|
||||
60
Source/ComboInput/Public/InputBufferLocalPlayerSubsystem.h
Normal file
@ -0,0 +1,60 @@
|
||||
// ©2022 Batty Bovine Productions, LLC. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "EnhancedInputSubsystems.h"
|
||||
|
||||
#include "InputBufferLocalPlayerSubsystem.generated.h"
|
||||
|
||||
DECLARE_LOG_CATEGORY_EXTERN(LogInputBufferLocalPlayerSubsystem, Log, All);
|
||||
|
||||
DECLARE_DELEGATE_TwoParams(FNewComboInput, const class UInputAction*, const EComboActionTriggerEvent &);
|
||||
|
||||
|
||||
/**
|
||||
* Subsystem that handles input buffering, and passing the resulting actions to the player's ComboManagerComponent.
|
||||
*/
|
||||
UCLASS()
|
||||
class COMBOINPUT_API UInputBufferLocalPlayerSubsystem : public UEnhancedInputLocalPlayerSubsystem
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
virtual void Initialize(FSubsystemCollectionBase &Collection) override;
|
||||
|
||||
void AttachComboManager(class UComboManagerComponent *ComboManager, class UEnhancedInputComponent *InputComponent);
|
||||
|
||||
UFUNCTION(BlueprintCallable)
|
||||
void UnlockComboInput(const class UInputAction *Unlocked);
|
||||
|
||||
private:
|
||||
void AddActionToBuffer(const FInputActionValue &Value, const class UInputAction *Action);
|
||||
void ExpireAction(const FInputActionValue &Value, const class UInputAction *Action);
|
||||
|
||||
void ActivateComboInput(const class UInputAction *ComboInput);
|
||||
void HoldComboInput(const class UInputAction *ComboInput);
|
||||
|
||||
void ClearMultiPresses();
|
||||
void ExpireBufferedActions();
|
||||
|
||||
TObjectPtr<class UEnhancedInputComponent> EnhancedInputComponent;
|
||||
|
||||
// Currently active combo input.
|
||||
TObjectPtr<const class UInputAction> InputBufferActive;
|
||||
|
||||
// Combo input held until the current input has expired.
|
||||
TObjectPtr<const class UInputAction> InputBufferHold;
|
||||
|
||||
// Set of currently locked actions; will not be activated until an unlock signal is received.
|
||||
TSet<TObjectPtr<const class UInputAction>> LockedComboInputs;
|
||||
|
||||
TSet<const class UInputAction*> MostRecentActions;
|
||||
TSet<const class UInputAction*> ExpiringActions;
|
||||
|
||||
FNewComboInput OnNewComboInput;
|
||||
|
||||
FTimerHandle MultiPressTimerHandle;
|
||||
FTimerHandle InputReleaseExpirationTimerHandle;
|
||||
FTimerHandle ForceUnlockTimerHandle;
|
||||
};
|
||||
@ -1,42 +0,0 @@
|
||||
// ©2023 Batty Bovine Productions, LLC. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
|
||||
#include "ComboActionGraphEdge.generated.h"
|
||||
|
||||
|
||||
/**
|
||||
* Combo Action edges.
|
||||
*
|
||||
* Currently those edges are just connecting objects with no advanced logic.
|
||||
*/
|
||||
UCLASS(ClassGroup=("Combo Input|Action"), NotBlueprintType)
|
||||
class COMBOINPUT_API UComboActionGraphEdge : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
UFUNCTION(BlueprintCallable, Category="Combo Input|Action")
|
||||
void SetGraph(class UComboActionGraph *InGraph) { this->Graph = InGraph; }
|
||||
UFUNCTION(BlueprintCallable, Category="Combo Input|Action")
|
||||
void SetStartNode(class UComboActionGraphNode *InNode) { this->StartNode = InNode; }
|
||||
UFUNCTION(BlueprintCallable, Category="Combo Input|Action")
|
||||
void SetEndNode(class UComboActionGraphNode *InNode) { this->EndNode = InNode; }
|
||||
|
||||
UFUNCTION(BlueprintPure, Category="Combo Input|Action")
|
||||
class UComboActionGraph *GetGraph() const { return this->Graph; }
|
||||
UFUNCTION(BlueprintPure, Category="Combo Input|Action")
|
||||
class UComboActionGraphNode *GetStartNode() const { return this->StartNode; }
|
||||
UFUNCTION(BlueprintPure, Category="Combo Input|Action")
|
||||
class UComboActionGraphNode *GetEndNode() const { return this->EndNode; }
|
||||
|
||||
private:
|
||||
UPROPERTY(VisibleAnywhere, Category="Combo Input|Action")
|
||||
class UComboActionGraph *Graph = nullptr;
|
||||
UPROPERTY(BlueprintReadOnly, Category="Combo Input|Action", meta=(AllowPrivateAccess="true"))
|
||||
class UComboActionGraphNode *StartNode = nullptr;
|
||||
UPROPERTY(BlueprintReadOnly, Category="Combo Input|Action", meta=(AllowPrivateAccess="true"))
|
||||
class UComboActionGraphNode *EndNode = nullptr;
|
||||
};
|
||||
@ -1,337 +0,0 @@
|
||||
// ©2023 Batty Bovine Productions, LLC. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
|
||||
#include "ComboActionGraphNode.generated.h"
|
||||
|
||||
DECLARE_LOG_CATEGORY_EXTERN(LogComboActionGraphNode, Log, All);
|
||||
|
||||
|
||||
/**
|
||||
* Combo Action graph Node abstract base class.
|
||||
*
|
||||
* Provides generic functionality to be enhanced or overriden by Child Classes.
|
||||
* Does come with ability to define Colours, Name, Description and Title.
|
||||
* Contains information about Parent and Children Nodes.
|
||||
*/
|
||||
UCLASS(Abstract, BlueprintType, ClassGroup=("Combo Input|Action"), AutoExpandCategories=("Combo Input", "Action", "Combo Input|Action"), HideCategories=("Private"))
|
||||
class COMBOINPUT_API UComboActionGraphNode : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
UComboActionGraphNode();
|
||||
|
||||
#pragma region Variables
|
||||
|
||||
#pragma region ReadOnly
|
||||
public:
|
||||
/**
|
||||
* Array of parent nodes for the current active node in the combo string.
|
||||
*❗ Parent nodes are nodes that have a directed edge pointing to the current active node.
|
||||
*/
|
||||
UPROPERTY(BlueprintReadOnly, Category = "Private")
|
||||
TArray<class UComboActionGraphNode *> ParentNodes;
|
||||
/**
|
||||
* The array of child nodes of the current dialogue node.
|
||||
*/
|
||||
UPROPERTY(BlueprintReadOnly, Category = "Private")
|
||||
TArray<class UComboActionGraphNode *> ChildNodes;
|
||||
/**
|
||||
* Map of edges connecting this Node in the Combo Action graph.
|
||||
*❗ The key of the map is the source node, and the value is the edge connecting it to its target node.
|
||||
*❔ Can be used to traverse the graph, get information about node connections...
|
||||
*/
|
||||
UPROPERTY(BlueprintReadOnly, Category="Private")
|
||||
TMap<class UComboActionGraphNode*, class UComboActionGraphEdge*> Edges;
|
||||
/**
|
||||
* Pointer to the parent dialogue graph of this node.
|
||||
*/
|
||||
UPROPERTY(BlueprintReadOnly, Category="Private", meta=(DisplayThumbnail=false))
|
||||
TObjectPtr<class UComboActionGraph> Graph;
|
||||
/**
|
||||
* Temporary NodeIndex.
|
||||
* This variable will be deleted.
|
||||
*/
|
||||
UPROPERTY(BlueprintReadOnly, Category="Private")
|
||||
int32 NodeIndex = INDEX_NONE;
|
||||
|
||||
|
||||
protected:
|
||||
/**
|
||||
* The unique identifier for this Dialogue Graph Node.
|
||||
*❗ This is used to differentiate between nodes, and must be unique within the graph.
|
||||
*❔ Can be used for debugging and tracing purposes.
|
||||
*/
|
||||
UPROPERTY(BlueprintReadOnly, Category="Private")
|
||||
FGuid NodeGUID;
|
||||
|
||||
/**
|
||||
* The world that owns this Dialogue Graph Node.
|
||||
*❗ This is the world in which this Dialogue Graph Node is currently running.
|
||||
*❔ Can be used for accessing world-related functionality.
|
||||
*/
|
||||
UPROPERTY(BlueprintReadOnly, Category="Private")
|
||||
TObjectPtr<UWorld> OwningWorld;
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Editable
|
||||
public:
|
||||
/**
|
||||
* Whether the node is enabled by default. Disabled nodes will be ignored by the
|
||||
* combo manager until they are enabled again programmatically. This allows actions
|
||||
* to be unlockable during gameplay.
|
||||
*/
|
||||
UPROPERTY(BlueprintReadOnly, EditDefaultsOnly, Category="Combo Input|Action")
|
||||
uint8 bEnabled : 1;
|
||||
|
||||
/**
|
||||
* The maximum number of children nodes that this node can have.
|
||||
* If this value is -1, then there is no limit on the number of children nodes.
|
||||
* Can be used to enforce a maximum number of connections for certain types of nodes.
|
||||
*/
|
||||
UPROPERTY(BlueprintReadOnly, EditDefaultsOnly, Category="Combo Input|Action")
|
||||
int32 MaxChildNodes = -1;
|
||||
|
||||
/**
|
||||
* The array of allowed input classes for this Dialogue Node.
|
||||
* Only nodes with classes from this array can be connected as inputs to this node.
|
||||
* Can be used to restrict the types of inputs this node can accept.
|
||||
*/
|
||||
UPROPERTY(BlueprintReadOnly, Category="Combo Input|Action")
|
||||
TArray<TSubclassOf<class UComboActionGraphNode>> AllowedInputClasses;
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Functions
|
||||
|
||||
public:
|
||||
/**
|
||||
* Initializes the node with the given world.
|
||||
*
|
||||
* @param InWorld The world to use for initialization.
|
||||
*/
|
||||
UFUNCTION(BlueprintNativeEvent, Category = "Combo Input|Action")
|
||||
void InitializeNode(UWorld *InWorld);
|
||||
virtual void InitializeNode_Implementation(UWorld *InWorld);
|
||||
|
||||
virtual void PreProcessNode(const TScriptInterface<class IComboActionGraphManagerInterface> &Manager){}
|
||||
virtual void ProcessNode(const TScriptInterface<class IComboActionGraphManagerInterface> &Manager);
|
||||
/**
|
||||
* Returns how many Children Nodes this Node allows to have.
|
||||
*❔ -1 means no limits.
|
||||
*
|
||||
* @return Max child nodes
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category="Combo Input|Action")
|
||||
int32 GetMaxChildNodes() const { return this->MaxChildNodes; }
|
||||
|
||||
|
||||
/**
|
||||
* Gets the index of the node within the dialogue graph.
|
||||
*
|
||||
* @return The index of the node.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category="Combo Input|Action")
|
||||
FORCEINLINE int32 GetNodeIndex() const { return NodeIndex; }
|
||||
/**
|
||||
* Sets the index of this dialogue node in the dialogue graph.
|
||||
*
|
||||
* @param NewIndex The new index to set.
|
||||
*/
|
||||
void SetNodeIndex(const int32 NewIndex);
|
||||
|
||||
/**
|
||||
* Gets the GUID of the node.
|
||||
*
|
||||
* @return The GUID of the node.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category="Combo Input|Action")
|
||||
FORCEINLINE FGuid GetNodeGUID() const { return NodeGUID; }
|
||||
|
||||
/**
|
||||
* Gets the owning Graph of the node.
|
||||
*❗ Might be null
|
||||
*
|
||||
* @return The owning Graph of the node.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "Combo Input|Action")
|
||||
class UComboActionGraph *GetGraph() const { return this->Graph; }
|
||||
|
||||
|
||||
/**
|
||||
* Serves purpose of validating Node before Dialogue gets Started.
|
||||
* Any broken Node results in non-starting Dialogue to avoid crashes.
|
||||
*/
|
||||
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category="Combo Input|Action")
|
||||
bool ValidateNodeRuntime() const;
|
||||
virtual bool ValidateNodeRuntime_Implementation() const { return true; }
|
||||
|
||||
public:
|
||||
|
||||
FORCEINLINE ULevel* GetLevel() const { return GetTypedOuter<ULevel>(); }
|
||||
|
||||
/**
|
||||
* Provides a way to update Node's owning World.
|
||||
* Useful for Loading sub-levels.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category="Combo Input|Action")
|
||||
virtual void SetNewWorld(UWorld* NewWorld);
|
||||
virtual UWorld* GetWorld() const override
|
||||
{
|
||||
if (OwningWorld) return OwningWorld;
|
||||
|
||||
// CDO objects do not belong to a world
|
||||
// If the actors outer is destroyed or unreachable we are shutting down and the world should be nullptr
|
||||
if (
|
||||
!HasAnyFlags(RF_ClassDefaultObject) && ensureMsgf(GetOuter(), TEXT("Actor: %s has a null OuterPrivate in AActor::GetWorld()"), *GetFullName())
|
||||
&& !GetOuter()->HasAnyFlags(RF_BeginDestroyed) && !GetOuter()->IsUnreachable()
|
||||
)
|
||||
{
|
||||
if (ULevel* Level = GetLevel())
|
||||
{
|
||||
return Level->OwningWorld;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
|
||||
#if WITH_EDITORONLY_DATA
|
||||
|
||||
// Defines whether this Node type allows inputs
|
||||
UPROPERTY(BlueprintReadOnly, Category = "Editor")
|
||||
bool bAllowInputNodes;
|
||||
|
||||
// Defines whether this Node type allows outputs
|
||||
UPROPERTY(BlueprintReadOnly, Category = "Editor")
|
||||
bool bAllowOutputNodes;
|
||||
|
||||
// Defines whether this Node can be copied
|
||||
UPROPERTY(BlueprintReadOnly, Category = "Editor")
|
||||
bool bAllowCopy;
|
||||
|
||||
// Defines whether this Node can be cut
|
||||
UPROPERTY(BlueprintReadOnly, Category = "Editor")
|
||||
bool bAllowCut;
|
||||
|
||||
// Defines whether this Node can be pasted
|
||||
UPROPERTY(BlueprintReadOnly, Category = "Editor")
|
||||
bool bAllowPaste;
|
||||
|
||||
// Defines whether this Node can be deleted
|
||||
UPROPERTY(BlueprintReadOnly, Category = "Editor")
|
||||
bool bAllowDelete;
|
||||
|
||||
// Defines whether this Node can be manually created
|
||||
UPROPERTY(BlueprintReadOnly, Category = "Editor")
|
||||
bool bAllowManualCreate;
|
||||
|
||||
// Display title of the Node
|
||||
UPROPERTY(BlueprintReadOnly, Category = "Editor")
|
||||
FText NodeTitle;
|
||||
|
||||
// Display name of the Node menu category
|
||||
UPROPERTY(BlueprintReadOnly, Category = "Editor")
|
||||
FText ContextMenuName;
|
||||
|
||||
// List of compatible graph types
|
||||
UPROPERTY(BlueprintReadOnly, Category = "Editor")
|
||||
TSubclassOf<UObject> CompatibleGraphType;
|
||||
|
||||
// Defines background colour of this Node
|
||||
UPROPERTY(BlueprintReadOnly, EditDefaultsOnly, Category = "Editor")
|
||||
FLinearColor BackgroundColor;
|
||||
|
||||
// Contains Node Tooltip text
|
||||
UPROPERTY(BlueprintReadOnly, Category = "Editor")
|
||||
FText NodeTooltipText;
|
||||
|
||||
// User friendly node type name
|
||||
UPROPERTY(BlueprintReadOnly, Category = "Editor")
|
||||
FText NodeTypeName;
|
||||
|
||||
#endif
|
||||
|
||||
#if WITH_EDITOR
|
||||
|
||||
/**
|
||||
* Returns the tooltip text for this graph node.
|
||||
*
|
||||
* @return The tooltip text for this node.
|
||||
*/
|
||||
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "Combo Input|Action", meta=(DevelopmentOnly=true))
|
||||
FText GetNodeTooltipText() const;
|
||||
virtual FText GetNodeTooltipText_Implementation() const;
|
||||
|
||||
/**
|
||||
* Returns the Title text for this graph node.
|
||||
*
|
||||
* @return The Title text for this node.
|
||||
*/
|
||||
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "Combo Input|Action", meta=(DevelopmentOnly=true))
|
||||
FText GetNodeTitle() const;
|
||||
virtual FText GetNodeTitle_Implementation() const { return this->NodeTitle; }
|
||||
|
||||
/**
|
||||
* Returns the Description text for this graph node.
|
||||
*
|
||||
* @return The Description text for this node.
|
||||
*/
|
||||
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "Combo Input|Action", meta=(DevelopmentOnly=true))
|
||||
FText GetDescription() const;
|
||||
virtual FText GetDescription_Implementation() const;
|
||||
|
||||
/**
|
||||
* Returns the Node Category text for this graph node.
|
||||
*
|
||||
* @return The Node Category text for this node.
|
||||
*/
|
||||
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "Combo Input|Action", meta=(DevelopmentOnly=true))
|
||||
FText GetNodeCategory() const;
|
||||
virtual FText GetNodeCategory_Implementation() const;
|
||||
|
||||
/**
|
||||
* Returns the Documentation Link for this graph node.
|
||||
*
|
||||
* @return The Documentation Link for this node.
|
||||
*/
|
||||
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "Combo Input|Action", meta=(DevelopmentOnly=true))
|
||||
FString GetNodeDocumentationLink() const;
|
||||
virtual FString GetNodeDocumentationLink_Implementation() const;
|
||||
|
||||
/**
|
||||
* Returns the background colour for this graph node.
|
||||
*
|
||||
* @return The background colour for this node.
|
||||
*/
|
||||
virtual FLinearColor GetBackgroundColour() const { return this->BackgroundColor; }
|
||||
FText GetInternalName() const { return this->NodeTypeName; }
|
||||
|
||||
// Allows setting up the Node Title
|
||||
virtual void SetNodeTitle(const FText &NewTitle) { this->NodeTitle = NewTitle; }
|
||||
|
||||
// Allows advanced filtering if Node can be connected from other Node
|
||||
virtual bool CanCreateConnection(UComboActionGraphNode *Other, enum EEdGraphPinDirection Direction, FText& ErrorMessage);
|
||||
|
||||
// Validation function responsible for generating user friendly validation messages
|
||||
virtual bool ValidateNode(TArray<FText> &ValidationsMessages, const bool RichFormat);
|
||||
|
||||
// Once Node is pasted, this function is called
|
||||
virtual void OnPasted();
|
||||
|
||||
// Generates default Tooltip body text used for all Nodes
|
||||
UFUNCTION(BlueprintPure, Category="Combo Input|Action", meta=(DevelopmentOnly=true))
|
||||
FText GetDefaultTooltipBody() const;
|
||||
virtual void OnCreatedInEditor() {};
|
||||
|
||||
#endif
|
||||
|
||||
};
|
||||
@ -1,33 +0,0 @@
|
||||
// ©2023 Batty Bovine Productions, LLC. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Nodes/ComboActionGraphNode_ActionNodeBase.h"
|
||||
#include "UObject/Object.h"
|
||||
|
||||
#include "ComboActionGraphNode_ActionNode.generated.h"
|
||||
|
||||
|
||||
/**
|
||||
* Combo Action node.
|
||||
*
|
||||
* This Node represents Player's combo actions.
|
||||
*/
|
||||
UCLASS(ClassGroup=("Combo Input|Action"), DisplayName="Action Node", meta=(ToolTip="Combo Action Tree: Action Node"))
|
||||
class COMBOINPUT_API UComboActionGraphNode_ActionNode : public UComboActionGraphNode_ActionNodeBase
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UComboActionGraphNode_ActionNode();
|
||||
|
||||
public:
|
||||
|
||||
virtual void PreProcessNode(const TScriptInterface<class IComboActionGraphManagerInterface> &Manager) override;
|
||||
virtual void ProcessNode(const TScriptInterface<class IComboActionGraphManagerInterface> &Manager) override;
|
||||
|
||||
#if WITH_EDITOR
|
||||
virtual FText GetDescription_Implementation() const override;
|
||||
virtual FText GetNodeCategory_Implementation() const override;
|
||||
#endif
|
||||
};
|
||||
@ -1,87 +0,0 @@
|
||||
// ©2023 Batty Bovine Productions, LLC. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
|
||||
#include "ComboInputTriggers.h"
|
||||
#include "Engine/DataTable.h"
|
||||
#include "Nodes/ComboActionGraphNode.h"
|
||||
#include "UObject/Object.h"
|
||||
|
||||
#include "ComboActionGraphNode_ActionNodeBase.generated.h"
|
||||
|
||||
|
||||
/**
|
||||
* Combo Action Graph Node abstract Base class.
|
||||
*
|
||||
* Enhances 'ComboActionGraphNode' Base class with action data.
|
||||
*/
|
||||
UCLASS(Abstract, ClassGroup=("Combo Input|Action"), AutoExpandCategories=("Combo Input", "Action", "Combo Input|Action"))
|
||||
class COMBOINPUT_API UComboActionGraphNode_ActionNodeBase : public UComboActionGraphNode
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
UComboActionGraphNode_ActionNodeBase();
|
||||
|
||||
virtual void ProcessNode(const TScriptInterface<class IComboActionGraphManagerInterface> &Manager) override;
|
||||
virtual void PreProcessNode(const TScriptInterface<class IComboActionGraphManagerInterface> &Manager) override;
|
||||
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category="Combo Input|Action")
|
||||
class UComboInputAsset *GetComboInput() const { return this->ComboInput; }
|
||||
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category="Combo Input|Action")
|
||||
enum EComboActionTriggerEvent GetTriggerEvent() const { return this->TriggerEvent; }
|
||||
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category="Combo Input|Action")
|
||||
class UComboAction *GetComboAction() const { return this->ComboAction; }
|
||||
|
||||
virtual bool ValidateNodeRuntime_Implementation() const override;
|
||||
|
||||
#if WITH_EDITOR
|
||||
virtual FLinearColor GetBackgroundColour() const override;
|
||||
#endif
|
||||
|
||||
#if WITH_EDITORONLY_DATA
|
||||
|
||||
/**
|
||||
* Shows read-only Texts with localization of selected row.
|
||||
*/
|
||||
UPROPERTY(Transient, VisibleAnywhere, Category="Base", meta=(MultiLine=true, ShowOnlyInnerProperties))
|
||||
TArray<FText> Preview;
|
||||
|
||||
FSimpleDelegate PreviewsUpdated;
|
||||
|
||||
#endif
|
||||
|
||||
protected:
|
||||
// Combo input to respond to in order to reach this action.
|
||||
UPROPERTY(BlueprintReadOnly, EditAnywhere, Category="Combo Input|Action")
|
||||
TObjectPtr<class UComboInputAsset> ComboInput;
|
||||
|
||||
// Trigger event to respond to in order to reach this action.
|
||||
UPROPERTY(BlueprintReadOnly, EditAnywhere, Category="Combo Input|Action")
|
||||
EComboActionTriggerEvent TriggerEvent = EComboActionTriggerEvent::Activated;
|
||||
|
||||
// Combo action to fire upon this node's activation.
|
||||
UPROPERTY(BlueprintReadOnly, EditAnywhere, Category = "Combo Input|Action")
|
||||
TObjectPtr<class UComboAction> ComboAction;
|
||||
|
||||
|
||||
|
||||
#if WITH_EDITOR
|
||||
protected:
|
||||
virtual bool ValidateNode(TArray<FText> &ValidationMessages, const bool RichFormat) override;
|
||||
virtual void PostEditChangeProperty(FPropertyChangedEvent &PropertyChangedEvent) override;
|
||||
virtual FText GetDescription_Implementation() const override;
|
||||
|
||||
public:
|
||||
TArray<FText> GetPreviews() const;
|
||||
#endif
|
||||
|
||||
#if WITH_EDITORONLY_DATA
|
||||
public:
|
||||
virtual void UpdatePreviews() { this->Preview = this->GetPreviews(); }
|
||||
#endif
|
||||
};
|
||||
@ -1,35 +0,0 @@
|
||||
// ©2023 Batty Bovine Productions, LLC. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
|
||||
#include "Nodes/ComboActionGraphNode.h"
|
||||
#include "UObject/Object.h"
|
||||
|
||||
#include "ComboActionGraphNode_StartNode.generated.h"
|
||||
|
||||
|
||||
/**
|
||||
* Combo Action Start Node.
|
||||
*
|
||||
* This Node will be added to the graph automatically when created.
|
||||
* This node cannot be created manually.
|
||||
* This node cannot be deleted.
|
||||
* Does not implement any logic.
|
||||
*/
|
||||
UCLASS(ClassGroup=("Combo Input|Action"), DisplayName="Start Node", meta=(ToolTip="Combo Action Tree: Start Node"))
|
||||
class COMBOINPUT_API UComboActionGraphNode_StartNode : public UComboActionGraphNode
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
|
||||
UComboActionGraphNode_StartNode();
|
||||
|
||||
#if WITH_EDITOR
|
||||
virtual FText GetDescription_Implementation() const override;
|
||||
|
||||
virtual bool ValidateNode(TArray<FText>& ValidationsMessages, const bool RichFormat);
|
||||
#endif
|
||||
};
|
||||
@ -25,19 +25,9 @@ public class ComboInputEditor : ModuleRules
|
||||
{
|
||||
"Core",
|
||||
"CoreUObject",
|
||||
"Engine",
|
||||
"UnrealEd",
|
||||
|
||||
"ApplicationCore",
|
||||
"AssetTools",
|
||||
"BlueprintGraph",
|
||||
"DeveloperSettings",
|
||||
"GraphEditor",
|
||||
"InputCore",
|
||||
"Projects",
|
||||
"Slate",
|
||||
"SlateCore",
|
||||
"ToolMenus",
|
||||
"Projects"
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
@ -1,437 +0,0 @@
|
||||
// ©2023 Batty Bovine Productions, LLC. All Rights Reserved.
|
||||
|
||||
#include "ComboActionGraphSchema.h"
|
||||
|
||||
#include "ComboActionGraph.h"
|
||||
//#include "FConnectionDrawingPolicy_ComboActionGraph.h"
|
||||
#include "GraphEditorActions.h"
|
||||
|
||||
#include "Ed/EdComboActionGraphEdge.h"
|
||||
#include "Ed/EdComboActionGraphNode.h"
|
||||
#include "Framework/Commands/GenericCommands.h"
|
||||
#include "Nodes/ComboActionGraphEdge.h"
|
||||
#include "Nodes/ComboActionGraphNode.h"
|
||||
|
||||
#define LOCTEXT_NAMESPACE "ComboActionGraph"
|
||||
|
||||
int32 UComboActionGraphSchema::CurrentCacheRefreshID = 0;
|
||||
|
||||
|
||||
UEdGraphNode *FAssetSchemaAction_ComboActionGraphSchema_NewNode::PerformAction(UEdGraph *ParentGraph, UEdGraphPin *FromPin, const FVector2D Location, bool bSelectNewNode)
|
||||
{
|
||||
UEdGraphNode *ResultNode = nullptr;
|
||||
|
||||
if (this->NodeTemplate != nullptr)
|
||||
{
|
||||
const FScopedTransaction Transaction(LOCTEXT("ComboActionGraphEditorNewNode", "Combo Action Graph Editor: New Node"));
|
||||
ParentGraph->Modify();
|
||||
if (FromPin != nullptr)
|
||||
FromPin->Modify();
|
||||
|
||||
this->NodeTemplate->Rename(nullptr, ParentGraph);
|
||||
ParentGraph->AddNode(this->NodeTemplate, true, bSelectNewNode);
|
||||
|
||||
this->NodeTemplate->CreateNewGuid();
|
||||
this->NodeTemplate->PostPlacedNewNode();
|
||||
this->NodeTemplate->AllocateDefaultPins();
|
||||
this->NodeTemplate->AutowireNewNode(FromPin);
|
||||
|
||||
this->NodeTemplate->NodePosX = Location.X;
|
||||
this->NodeTemplate->NodePosY = Location.Y;
|
||||
|
||||
this->NodeTemplate->ComboActionGraphNode->SetFlags(EObjectFlags::RF_Transactional);
|
||||
this->NodeTemplate->SetFlags(EObjectFlags::RF_Transactional);
|
||||
|
||||
ResultNode = this->NodeTemplate;
|
||||
}
|
||||
|
||||
return ResultNode;
|
||||
}
|
||||
|
||||
void FAssetSchemaAction_ComboActionGraphSchema_NewNode::AddReferencedObjects(FReferenceCollector &Collector)
|
||||
{
|
||||
FEdGraphSchemaAction::AddReferencedObjects(Collector);
|
||||
Collector.AddReferencedObject(this->NodeTemplate);
|
||||
}
|
||||
|
||||
UEdGraphNode *FAssetSchemaAction_ComboActionGraphSchema_NewEdge::PerformAction(UEdGraph *ParentGraph, UEdGraphPin *FromPin, const FVector2D Location, bool bSelectNewNode)
|
||||
{
|
||||
UEdGraphNode *ResultNode = nullptr;
|
||||
|
||||
if (this->NodeTemplate != nullptr)
|
||||
{
|
||||
const FScopedTransaction Transaction(LOCTEXT("ComboActionGraphEditorNewEdge", "Combo Action Graph Editor: New Edge"));
|
||||
ParentGraph->Modify();
|
||||
if (FromPin != nullptr)
|
||||
FromPin->Modify();
|
||||
|
||||
this->NodeTemplate->Rename(nullptr, ParentGraph);
|
||||
ParentGraph->AddNode(this->NodeTemplate, true, bSelectNewNode);
|
||||
|
||||
this->NodeTemplate->CreateNewGuid();
|
||||
this->NodeTemplate->PostPlacedNewNode();
|
||||
this->NodeTemplate->AllocateDefaultPins();
|
||||
this->NodeTemplate->AutowireNewNode(FromPin);
|
||||
|
||||
this->NodeTemplate->NodePosX = Location.X;
|
||||
this->NodeTemplate->NodePosY = Location.Y;
|
||||
|
||||
this->NodeTemplate->ComboActionGraphEdge->SetFlags(EObjectFlags::RF_Transactional);
|
||||
this->NodeTemplate->SetFlags(EObjectFlags::RF_Transactional);
|
||||
|
||||
ResultNode = this->NodeTemplate;
|
||||
}
|
||||
|
||||
return ResultNode;
|
||||
}
|
||||
|
||||
void FAssetSchemaAction_ComboActionGraphSchema_NewEdge::AddReferencedObjects(FReferenceCollector &Collector)
|
||||
{
|
||||
FEdGraphSchemaAction::AddReferencedObjects(Collector);
|
||||
Collector.AddReferencedObject(this->NodeTemplate);
|
||||
}
|
||||
|
||||
|
||||
void UComboActionGraphSchema::GetBreakLinkToSubMenuActions(UToolMenu *Menu, UEdGraphPin *InGraphPin)
|
||||
{
|
||||
// Make sure we have a unique name for every entry in the list
|
||||
TMap<FString, uint32> LinkTitleCount;
|
||||
|
||||
FToolMenuSection &Section = Menu->FindOrAddSection("ComboActionGraphAssetGraphSchemaPinActions");
|
||||
|
||||
// Add all the links we could break from
|
||||
for (TArray<class UEdGraphPin*>::TConstIterator Links(InGraphPin->LinkedTo); Links; ++Links)
|
||||
{
|
||||
UEdGraphPin* Pin = *Links;
|
||||
FString TitleString = Pin->GetOwningNode()->GetNodeTitle(ENodeTitleType::ListView).ToString();
|
||||
FText Title = FText::FromString(TitleString);
|
||||
if (Pin->PinName != TEXT(""))
|
||||
{
|
||||
TitleString = FString::Printf(TEXT("%s (%s)"), *TitleString, *Pin->PinName.ToString());
|
||||
|
||||
// Add name of connection if possible
|
||||
FFormatNamedArguments Args;
|
||||
Args.Add(TEXT("NodeTitle"), Title);
|
||||
Args.Add(TEXT("PinName"), Pin->GetDisplayName());
|
||||
Title = FText::Format(LOCTEXT("BreakDescPin", "{NodeTitle} ({PinName})"), Args);
|
||||
}
|
||||
|
||||
uint32& Count = LinkTitleCount.FindOrAdd(TitleString);
|
||||
|
||||
FText Description;
|
||||
FFormatNamedArguments Args;
|
||||
Args.Add(TEXT("NodeTitle"), Title);
|
||||
Args.Add(TEXT("NumberOfNodes"), Count);
|
||||
|
||||
if (Count == 0)
|
||||
{
|
||||
Description = FText::Format(LOCTEXT("BreakDesc", "Break link to {NodeTitle}"), Args);
|
||||
}
|
||||
else
|
||||
{
|
||||
Description = FText::Format(LOCTEXT("BreakDescMulti", "Break link to {NodeTitle} ({NumberOfNodes})"), Args);
|
||||
}
|
||||
++Count;
|
||||
|
||||
Section.AddMenuEntry(NAME_None, Description, Description, FSlateIcon(), FUIAction(
|
||||
FExecuteAction::CreateUObject(this, &UComboActionGraphSchema::BreakSinglePinLink, const_cast<UEdGraphPin*>(InGraphPin), *Links)));
|
||||
}
|
||||
}
|
||||
|
||||
void UComboActionGraphSchema::GetGraphContextActions(FGraphContextMenuBuilder &ContextMenuBuilder) const
|
||||
{
|
||||
UComboActionGraph *Graph = CastChecked<UComboActionGraph>(ContextMenuBuilder.CurrentGraph->GetOuter());
|
||||
|
||||
if (Graph->NodeType == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const bool bNoParent = (ContextMenuBuilder.FromPin == NULL);
|
||||
|
||||
FText AddToolTip = LOCTEXT("NewMoutneaDialogueGraphNodeTooltip", "Add Dialogue Node here");
|
||||
|
||||
TSet<TSubclassOf<UComboActionGraphNode>> Visited;
|
||||
|
||||
FText Desc = Graph->NodeType.GetDefaultObject()->ContextMenuName;
|
||||
FText NodeCategory = Graph->NodeType.GetDefaultObject()->GetNodeCategory();
|
||||
|
||||
if (Desc.IsEmpty())
|
||||
{
|
||||
FString Title = Graph->NodeType->GetName();
|
||||
Title.RemoveFromEnd("_C");
|
||||
Desc = FText::FromString(Title);
|
||||
}
|
||||
|
||||
if (!Graph->NodeType->HasAnyClassFlags(CLASS_Abstract))
|
||||
{
|
||||
TSharedPtr<FAssetSchemaAction_ComboActionGraphSchema_NewNode> NewNodeAction(new FAssetSchemaAction_ComboActionGraphSchema_NewNode(NodeCategory, Desc, AddToolTip, 0));
|
||||
NewNodeAction->NodeTemplate = NewObject<UEdComboActionGraphNode>(ContextMenuBuilder.OwnerOfTemporaries);
|
||||
NewNodeAction->NodeTemplate->ComboActionGraphNode = NewObject<UComboActionGraphNode>(NewNodeAction->NodeTemplate, Graph->NodeType);
|
||||
NewNodeAction->NodeTemplate->ComboActionGraphNode->Graph = Graph;
|
||||
ContextMenuBuilder.AddAction(NewNodeAction);
|
||||
|
||||
Visited.Add(Graph->NodeType);
|
||||
}
|
||||
|
||||
for (TObjectIterator<UClass> It; It; ++It)
|
||||
{
|
||||
if (It->IsChildOf(Graph->NodeType) && !It->HasAnyClassFlags(CLASS_Abstract) && !Visited.Contains(*It))
|
||||
{
|
||||
TSubclassOf<UComboActionGraphNode> NodeType = *It;
|
||||
|
||||
if (It->GetName().StartsWith("REINST") || It->GetName().StartsWith("SKEL"))
|
||||
continue;
|
||||
|
||||
if (!Graph->GetClass()->IsChildOf(NodeType.GetDefaultObject()->CompatibleGraphType))
|
||||
continue;
|
||||
|
||||
if (!NodeType.GetDefaultObject()->bAllowManualCreate)
|
||||
continue;
|
||||
|
||||
Desc = NodeType.GetDefaultObject()->ContextMenuName;
|
||||
AddToolTip = NodeType.GetDefaultObject()->GetDescription();
|
||||
|
||||
NodeCategory = NodeType.GetDefaultObject()->GetNodeCategory();
|
||||
|
||||
if (Desc.IsEmpty())
|
||||
{
|
||||
FString Title = NodeType->GetName();
|
||||
Title.RemoveFromEnd("_C");
|
||||
Desc = FText::FromString(Title);
|
||||
}
|
||||
|
||||
TSharedPtr<FAssetSchemaAction_ComboActionGraphSchema_NewNode> Action(new FAssetSchemaAction_ComboActionGraphSchema_NewNode(NodeCategory, Desc, AddToolTip, 0));
|
||||
Action->NodeTemplate = NewObject<UEdComboActionGraphNode>(ContextMenuBuilder.OwnerOfTemporaries);
|
||||
Action->NodeTemplate->ComboActionGraphNode = NewObject<UComboActionGraphNode>(Action->NodeTemplate, NodeType);
|
||||
Action->NodeTemplate->ComboActionGraphNode->Graph = Graph;
|
||||
ContextMenuBuilder.AddAction(Action);
|
||||
|
||||
Visited.Add(NodeType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UComboActionGraphSchema::GetContextMenuActions(UToolMenu *Menu, UGraphNodeContextMenuContext *Context) const
|
||||
{
|
||||
if (Context->Pin)
|
||||
{
|
||||
{
|
||||
FToolMenuSection& Section = Menu->AddSection("ComboActionGraphAssetGraphSchemaNodeActions", LOCTEXT("PinActionsMenuHeader", "Pin Actions"));
|
||||
// Only display the 'Break Links' option if there is a link to break!
|
||||
if (Context->Pin->LinkedTo.Num() > 0)
|
||||
{
|
||||
Section.AddMenuEntry(FGraphEditorCommands::Get().BreakPinLinks);
|
||||
|
||||
// add sub menu for break link to
|
||||
if (Context->Pin->LinkedTo.Num() > 1)
|
||||
{
|
||||
Section.AddSubMenu(
|
||||
"BreakLinkTo",
|
||||
LOCTEXT("BreakLinkTo", "Break Link To..."),
|
||||
LOCTEXT("BreakSpecificLinks", "Break a specific link..."),
|
||||
FNewToolMenuDelegate::CreateUObject((UComboActionGraphSchema *const)this, &UComboActionGraphSchema::GetBreakLinkToSubMenuActions, const_cast<UEdGraphPin*>(Context->Pin)));
|
||||
}
|
||||
else
|
||||
{
|
||||
((UComboActionGraphSchema *const)this)->GetBreakLinkToSubMenuActions(Menu, const_cast<UEdGraphPin*>(Context->Pin));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (Context->Node)
|
||||
{
|
||||
{
|
||||
FToolMenuSection& Section = Menu->AddSection("ComboActionGraphAssetGraphSchemaNodeActions", LOCTEXT("ClassActionsMenuHeader", "Node Actions"));
|
||||
Section.AddSeparator(FName(TEXT("Main Options")));
|
||||
Section.AddMenuEntry(FGenericCommands::Get().Rename);
|
||||
Section.AddSeparator(FName(TEXT("Other Options")));
|
||||
Section.AddMenuEntry(FGenericCommands::Get().Delete);
|
||||
Section.AddMenuEntry(FGenericCommands::Get().Cut);
|
||||
Section.AddMenuEntry(FGenericCommands::Get().Copy);
|
||||
Section.AddMenuEntry(FGenericCommands::Get().Duplicate);
|
||||
|
||||
Section.AddMenuEntry(FGraphEditorCommands::Get().BreakNodeLinks);
|
||||
}
|
||||
}
|
||||
|
||||
Super::GetContextMenuActions(Menu, Context);
|
||||
}
|
||||
|
||||
const FPinConnectionResponse UComboActionGraphSchema::CanCreateConnection(const UEdGraphPin *A, const UEdGraphPin *B) const
|
||||
{
|
||||
// Make sure the pins are not on the same node
|
||||
if (A->GetOwningNode() == B->GetOwningNode())
|
||||
{
|
||||
return FPinConnectionResponse(CONNECT_RESPONSE_DISALLOW, LOCTEXT("PinErrorSameNode", "Both are on the same node"));
|
||||
}
|
||||
|
||||
// Compare the directions
|
||||
if ((A->Direction == EGPD_Input) && (B->Direction == EGPD_Input))
|
||||
{
|
||||
return FPinConnectionResponse(CONNECT_RESPONSE_DISALLOW, LOCTEXT("PinErrorInput", "Can't connect input node to input node"));
|
||||
}
|
||||
else if ((A->Direction == EGPD_Output) && (B->Direction == EGPD_Output))
|
||||
{
|
||||
return FPinConnectionResponse(CONNECT_RESPONSE_DISALLOW, LOCTEXT("PinErrorOutput", "Can't connect output node to output node"));
|
||||
}
|
||||
|
||||
// check for cycles
|
||||
FComboActionNodeVisitorCycleChecker CycleChecker;
|
||||
if (!CycleChecker.CheckForLoop(A->GetOwningNode(), B->GetOwningNode()))
|
||||
{
|
||||
return FPinConnectionResponse(CONNECT_RESPONSE_DISALLOW, LOCTEXT("PinErrorCycle", "Can't create a graph cycle"));
|
||||
}
|
||||
if (!CycleChecker.CheckForLoop(B->GetOwningNode(), A->GetOwningNode()))
|
||||
{
|
||||
return FPinConnectionResponse(CONNECT_RESPONSE_DISALLOW, LOCTEXT("PinErrorCycle", "Can't create a graph cycle"));
|
||||
}
|
||||
|
||||
UEdComboActionGraphNode* EdNode_A = Cast<UEdComboActionGraphNode>(A->GetOwningNode());
|
||||
UEdComboActionGraphNode* EdNode_B = Cast<UEdComboActionGraphNode>(B->GetOwningNode());
|
||||
|
||||
if (EdNode_A == nullptr || EdNode_B == nullptr)
|
||||
{
|
||||
return FPinConnectionResponse(CONNECT_RESPONSE_DISALLOW, LOCTEXT("PinError", "Not a valid UComboActionGraphEdNode"));
|
||||
}
|
||||
|
||||
FText ErrorMessage;
|
||||
if (A->Direction == EGPD_Input)
|
||||
{
|
||||
if (!EdNode_A->ComboActionGraphNode->CanCreateConnection(EdNode_B->ComboActionGraphNode, EGPD_Input, ErrorMessage))
|
||||
{
|
||||
return FPinConnectionResponse(CONNECT_RESPONSE_DISALLOW, ErrorMessage);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!EdNode_B->ComboActionGraphNode->CanCreateConnection(EdNode_A->ComboActionGraphNode, EGPD_Output, ErrorMessage))
|
||||
{
|
||||
return FPinConnectionResponse(CONNECT_RESPONSE_DISALLOW, ErrorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
if (EdNode_A->ComboActionGraphNode->GetGraph()->bEdgeEnabled)
|
||||
{
|
||||
return FPinConnectionResponse(CONNECT_RESPONSE_MAKE_WITH_CONVERSION_NODE, LOCTEXT("PinConnect", "Connect nodes with edge"));
|
||||
}
|
||||
else
|
||||
{
|
||||
return FPinConnectionResponse(CONNECT_RESPONSE_MAKE, LOCTEXT("PinConnect", "Connect nodes"));
|
||||
}
|
||||
}
|
||||
|
||||
bool UComboActionGraphSchema::CreateAutomaticConversionNodeAndConnections(UEdGraphPin *A, UEdGraphPin *B) const
|
||||
{
|
||||
UEdComboActionGraphNode *NodeA = Cast<UEdComboActionGraphNode>(A->GetOwningNode());
|
||||
UEdComboActionGraphNode *NodeB = Cast<UEdComboActionGraphNode>(B->GetOwningNode());
|
||||
|
||||
if (NodeA == nullptr || NodeB == nullptr)
|
||||
return false;
|
||||
|
||||
if (NodeA->GetInputPin() == nullptr || NodeA->GetOutputPin() == nullptr || NodeB->GetInputPin() == nullptr || NodeB->GetOutputPin() == nullptr)
|
||||
return false;
|
||||
|
||||
UComboActionGraph* Graph = NodeA->ComboActionGraphNode->GetGraph();
|
||||
|
||||
FVector2D InitPos((NodeA->NodePosX + NodeB->NodePosX) / 2, (NodeA->NodePosY + NodeB->NodePosY) / 2);
|
||||
|
||||
FAssetSchemaAction_ComboActionGraphSchema_NewEdge Action;
|
||||
Action.NodeTemplate = NewObject<UEdComboActionGraphEdge>(NodeA->GetGraph());
|
||||
Action.NodeTemplate->SetEdge(NewObject<UComboActionGraphEdge>(Action.NodeTemplate, Graph->EdgeType));
|
||||
UEdComboActionGraphEdge *EdgeNode = Cast<UEdComboActionGraphEdge>(Action.PerformAction(NodeA->GetGraph(), nullptr, InitPos, false));
|
||||
|
||||
if (A->Direction == EEdGraphPinDirection::EGPD_Output)
|
||||
{
|
||||
EdgeNode->CreateConnections(NodeA, NodeB);
|
||||
}
|
||||
else
|
||||
{
|
||||
EdgeNode->CreateConnections(NodeB, NodeA);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
FConnectionDrawingPolicy *UComboActionGraphSchema::CreateConnectionDrawingPolicy(int32 InBackLayerID, int32 InFrontLayerID, float InZoomFactor, const FSlateRect& InClippingRect, FSlateWindowElementList& InDrawElements, UEdGraph* InGraphObj) const
|
||||
{
|
||||
/*
|
||||
if (const UMounteaDialogueGraphEditorSettings* MounteaDialogueGraphEditorSettings = GetMutableDefault<UMounteaDialogueGraphEditorSettings>())
|
||||
{
|
||||
if (MounteaDialogueGraphEditorSettings->AllowAdvancedWiring())
|
||||
{
|
||||
return new FConnectionDrawingPolicy_AdvancedMounteaDialogueGraph(InBackLayerID, InFrontLayerID, InZoomFactor, InClippingRect, InDrawElements, InGraphObj);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
//return new FConnectionDrawingPolicy_ComboActionGraph(InBackLayerID, InFrontLayerID, InZoomFactor, InClippingRect, InDrawElements, InGraphObj);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FLinearColor UComboActionGraphSchema::GetPinTypeColor(const FEdGraphPinType &PinType) const
|
||||
{
|
||||
return FColor::White;
|
||||
}
|
||||
|
||||
void UComboActionGraphSchema::BreakNodeLinks(UEdGraphNode &TargetNode) const
|
||||
{
|
||||
const FScopedTransaction Transaction(NSLOCTEXT("UnrealEd", "GraphEd_BreakNodeLinks", "Break Node Links"));
|
||||
|
||||
Super::BreakNodeLinks(TargetNode);
|
||||
}
|
||||
|
||||
void UComboActionGraphSchema::BreakPinLinks(UEdGraphPin &TargetPin, bool bSendsNodeNotifcation) const
|
||||
{
|
||||
const FScopedTransaction Transaction(NSLOCTEXT("UnrealEd", "GraphEd_BreakPinLinks", "Break Pin Links"));
|
||||
|
||||
Super::BreakPinLinks(TargetPin, bSendsNodeNotifcation);
|
||||
}
|
||||
|
||||
void UComboActionGraphSchema::BreakSinglePinLink(UEdGraphPin *SourcePin, UEdGraphPin *TargetPin) const
|
||||
{
|
||||
const FScopedTransaction Transaction(NSLOCTEXT("UnrealEd", "GraphEd_BreakSinglePinLink", "Break Pin Link"));
|
||||
|
||||
Super::BreakSinglePinLink(SourcePin, TargetPin);
|
||||
}
|
||||
|
||||
UEdGraphPin *UComboActionGraphSchema::DropPinOnNode(UEdGraphNode *InTargetNode, const FName &InSourcePinName, const FEdGraphPinType &InSourcePinType, EEdGraphPinDirection InSourcePinDirection) const
|
||||
{
|
||||
UEdComboActionGraphNode *EdNode = Cast<UEdComboActionGraphNode>(InTargetNode);
|
||||
switch (InSourcePinDirection)
|
||||
{
|
||||
case EEdGraphPinDirection::EGPD_Input:
|
||||
return EdNode->GetOutputPin();
|
||||
case EEdGraphPinDirection::EGPD_Output:
|
||||
return EdNode->GetInputPin();
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool UComboActionGraphSchema::SupportsDropPinOnNode(UEdGraphNode *InTargetNode, const FEdGraphPinType &InSourcePinType, EEdGraphPinDirection InSourcePinDirection, FText &OutErrorMessage) const
|
||||
{
|
||||
return Cast<UEdComboActionGraphNode>(InTargetNode) != nullptr;
|
||||
}
|
||||
|
||||
bool UComboActionGraphSchema::IsCacheVisualizationOutOfDate(int32 InVisualizationCacheID) const
|
||||
{
|
||||
return CurrentCacheRefreshID != InVisualizationCacheID;
|
||||
}
|
||||
|
||||
int32 UComboActionGraphSchema::GetCurrentVisualizationCacheID() const
|
||||
{
|
||||
return CurrentCacheRefreshID;
|
||||
}
|
||||
|
||||
void UComboActionGraphSchema::ForceVisualizationCacheClear() const
|
||||
{
|
||||
CurrentCacheRefreshID++;
|
||||
}
|
||||
|
||||
void UComboActionGraphSchema::CreateDefaultNodesForGraph(UEdGraph &Graph) const
|
||||
{
|
||||
Super::CreateDefaultNodesForGraph(Graph);
|
||||
}
|
||||
|
||||
#undef LOCTEXT_NAMESPACE
|
||||
@ -1,164 +0,0 @@
|
||||
// ©2023 Batty Bovine Productions, LLC. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
|
||||
#include "ComboActionGraphSchema.generated.h"
|
||||
|
||||
|
||||
class FComboActionNodeVisitorCycleChecker
|
||||
{
|
||||
public:
|
||||
/** Check whether a loop in the graph would be caused by linking the passed-in nodes */
|
||||
bool CheckForLoop(UEdGraphNode *StartNode, UEdGraphNode *EndNode)
|
||||
{
|
||||
VisitedNodes.Add(StartNode);
|
||||
|
||||
if (!QuiCheckDirectConnections(StartNode, EndNode))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return TraverseInputNodesToRoot(EndNode);
|
||||
}
|
||||
|
||||
private:
|
||||
bool TraverseInputNodesToRoot(UEdGraphNode *Node)
|
||||
{
|
||||
VisitedNodes.Add(Node);
|
||||
|
||||
for (int32 PinIndex = 0; PinIndex < Node->Pins.Num(); ++PinIndex)
|
||||
{
|
||||
UEdGraphPin *MyPin = Node->Pins[PinIndex];
|
||||
|
||||
if (MyPin->Direction == EGPD_Output)
|
||||
{
|
||||
for (int32 LinkedPinIndex = 0; LinkedPinIndex < MyPin->LinkedTo.Num(); ++LinkedPinIndex)
|
||||
{
|
||||
UEdGraphPin *OtherPin = MyPin->LinkedTo[LinkedPinIndex];
|
||||
if (OtherPin)
|
||||
{
|
||||
UEdGraphNode *OtherNode = OtherPin->GetOwningNode();
|
||||
if (VisitedNodes.Contains(OtherNode))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return TraverseInputNodesToRoot(OtherNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QuiCheckDirectConnections(UEdGraphNode *A, UEdGraphNode *B)
|
||||
{
|
||||
for (auto Itr : B->Pins)
|
||||
{
|
||||
if (A->Pins.Contains(Itr))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto Itr : A->Pins)
|
||||
{
|
||||
if (B->Pins.Contains(Itr))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
TSet<UEdGraphNode *> VisitedNodes;
|
||||
};
|
||||
|
||||
/** Action to add a node to the graph */
|
||||
USTRUCT()
|
||||
struct FAssetSchemaAction_ComboActionGraphSchema_NewNode : public FEdGraphSchemaAction
|
||||
{
|
||||
GENERATED_BODY();
|
||||
|
||||
public:
|
||||
FAssetSchemaAction_ComboActionGraphSchema_NewNode() : NodeTemplate(nullptr){}
|
||||
|
||||
FAssetSchemaAction_ComboActionGraphSchema_NewNode(const FText &InNodeCategory, const FText &InMenuDesc, const FText &InToolTip, const int32 InGrouping)
|
||||
: FEdGraphSchemaAction(InNodeCategory, InMenuDesc, InToolTip, InGrouping), NodeTemplate(nullptr){}
|
||||
|
||||
virtual UEdGraphNode *PerformAction(class UEdGraph *ParentGraph, UEdGraphPin *FromPin, const FVector2D Location, bool bSelectNewNode = true) override;
|
||||
virtual void AddReferencedObjects(FReferenceCollector &Collector) override;
|
||||
|
||||
TObjectPtr<class UEdComboActionGraphNode> NodeTemplate;
|
||||
};
|
||||
|
||||
USTRUCT()
|
||||
struct FAssetSchemaAction_ComboActionGraphSchema_NewEdge : public FEdGraphSchemaAction
|
||||
{
|
||||
GENERATED_BODY();
|
||||
|
||||
public:
|
||||
FAssetSchemaAction_ComboActionGraphSchema_NewEdge() : NodeTemplate(nullptr)
|
||||
{}
|
||||
|
||||
FAssetSchemaAction_ComboActionGraphSchema_NewEdge(const FText &InNodeCategory, const FText &InMenuDesc, const FText &InToolTip, const int32 InGrouping)
|
||||
: FEdGraphSchemaAction(InNodeCategory, InMenuDesc, InToolTip, InGrouping), NodeTemplate(nullptr)
|
||||
{}
|
||||
|
||||
virtual UEdGraphNode *PerformAction(class UEdGraph *ParentGraph, UEdGraphPin *FromPin, const FVector2D Location, bool bSelectNewNode = true) override;
|
||||
virtual void AddReferencedObjects(FReferenceCollector &Collector) override;
|
||||
|
||||
TObjectPtr<class UEdComboActionGraphEdge> NodeTemplate;
|
||||
};
|
||||
|
||||
|
||||
UCLASS(MinimalAPI)
|
||||
class UComboActionGraphSchema : public UEdGraphSchema
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
void GetBreakLinkToSubMenuActions(class UToolMenu* Menu, class UEdGraphPin* InGraphPin);
|
||||
|
||||
virtual EGraphType GetGraphType(const UEdGraph* TestEdGraph) const override { return EGraphType::GT_StateMachine; }
|
||||
|
||||
virtual void GetGraphContextActions(FGraphContextMenuBuilder& ContextMenuBuilder) const override;
|
||||
|
||||
virtual void GetContextMenuActions(class UToolMenu* Menu, class UGraphNodeContextMenuContext* Context) const override;
|
||||
|
||||
virtual const FPinConnectionResponse CanCreateConnection(const UEdGraphPin* A, const UEdGraphPin* B) const override;
|
||||
|
||||
virtual bool CreateAutomaticConversionNodeAndConnections(UEdGraphPin* A, UEdGraphPin* B) const override;
|
||||
|
||||
virtual class FConnectionDrawingPolicy* CreateConnectionDrawingPolicy(int32 InBackLayerID, int32 InFrontLayerID, float InZoomFactor, const FSlateRect& InClippingRect, class FSlateWindowElementList& InDrawElements, class UEdGraph* InGraphObj) const override;
|
||||
|
||||
virtual FLinearColor GetPinTypeColor(const FEdGraphPinType& PinType) const override;
|
||||
|
||||
virtual void BreakNodeLinks(UEdGraphNode& TargetNode) const override;
|
||||
|
||||
virtual void BreakPinLinks(UEdGraphPin& TargetPin, bool bSendsNodeNotifcation) const override;
|
||||
|
||||
virtual void BreakSinglePinLink(UEdGraphPin* SourcePin, UEdGraphPin* TargetPin) const override;
|
||||
|
||||
virtual UEdGraphPin* DropPinOnNode(UEdGraphNode* InTargetNode, const FName& InSourcePinName, const FEdGraphPinType& InSourcePinType, EEdGraphPinDirection InSourcePinDirection) const override;
|
||||
|
||||
virtual bool SupportsDropPinOnNode(UEdGraphNode* InTargetNode, const FEdGraphPinType& InSourcePinType, EEdGraphPinDirection InSourcePinDirection, FText& OutErrorMessage) const override;
|
||||
|
||||
virtual bool IsCacheVisualizationOutOfDate(int32 InVisualizationCacheID) const override;
|
||||
|
||||
virtual int32 GetCurrentVisualizationCacheID() const override;
|
||||
|
||||
virtual void ForceVisualizationCacheClear() const override;
|
||||
|
||||
virtual void CreateDefaultNodesForGraph(UEdGraph& Graph) const override;
|
||||
|
||||
private:
|
||||
|
||||
static int32 CurrentCacheRefreshID;
|
||||
};
|
||||
@ -2,17 +2,10 @@
|
||||
|
||||
#include "ComboInputEditor.h"
|
||||
|
||||
#include "ComboActionGraph.h"
|
||||
#include "ComboInputAssets.h"
|
||||
#include "ToolMenuSection.h"
|
||||
|
||||
#include "AssetTypeActions/AssetTypeActions_DataAsset.h"
|
||||
#include "Ed/AssetEditor_ComboActionGraph.h"
|
||||
#include "Ed/EdComboActionGraphEdge.h"
|
||||
#include "Ed/EdComboActionGraphNode.h"
|
||||
#include "Ed/FComboActionGraphEditorCommands.h"
|
||||
#include "Ed/SEdComboActionGraphEdge.h"
|
||||
#include "Ed/SEdComboActionGraphNode.h"
|
||||
#include "Interfaces/IPluginManager.h"
|
||||
#include "Styling/SlateStyle.h"
|
||||
#include "Styling/SlateStyleMacros.h"
|
||||
@ -23,7 +16,6 @@
|
||||
#define LOCTEXT_NAMESPACE "FComboInputEditorModule"
|
||||
|
||||
EAssetTypeCategories::Type FComboInputEditorModule::ComboAssetsCategory;
|
||||
EAssetTypeCategories::Type FComboInputEditorModule::ComboActionGraphCategory;
|
||||
|
||||
|
||||
class FAssetTypeActions_ComboAction : public FAssetTypeActions_DataAsset
|
||||
@ -36,276 +28,145 @@ public:
|
||||
virtual UClass *GetSupportedClass() const override { return UComboAction::StaticClass(); }
|
||||
};
|
||||
|
||||
class FAssetTypeActions_ComboInputAsset : public FAssetTypeActions_DataAsset
|
||||
class FAssetTypeActions_ComboSequenceNode : public FAssetTypeActions_DataAsset
|
||||
{
|
||||
public:
|
||||
virtual FText GetName() const override { return NSLOCTEXT("AssetTypeActions", "AssetTypeActions_ComboInputAsset", "Combo Input Asset"); }
|
||||
virtual FText GetName() const override { return NSLOCTEXT("AssetTypeActions", "AssetTypeActions_ComboSequenceNode", "Combo Sequence Node"); }
|
||||
virtual uint32 GetCategories() override { return FComboInputEditorModule::GetInputAssetsCategory(); }
|
||||
virtual FColor GetTypeColor() const override { return FColor(255, 127, 255); }
|
||||
virtual FText GetAssetDescription(const FAssetData &AssetData) const override { return NSLOCTEXT("AssetTypeActions", "AssetTypeActions_ComboInputAssetDesc", "This maps a sequence of button inputs from EnhancedInput to a combo action that can be used to execute a sequence of moves. This gets sent from the input buffer subsystem to the player controller's ComboManagerComponent, which executes the associated action in the current ComboActionGraph."); }
|
||||
virtual UClass *GetSupportedClass() const override { return UComboInputAsset::StaticClass(); }
|
||||
virtual FText GetAssetDescription(const FAssetData &AssetData) const override { return NSLOCTEXT("AssetTypeActions", "AssetTypeActions_ComboSequenceNodeDesc", "This represents a node in the combo graph, with each key in the ComboBranch being an input this node can react to, and each value containing the action to be executed next, and the node to activate after the action is complete."); }
|
||||
virtual UClass *GetSupportedClass() const override { return UComboSequenceNode::StaticClass(); }
|
||||
};
|
||||
|
||||
class FAssetTypeActions_ComboActionGraph : public FAssetTypeActions_Base
|
||||
class FAssetTypeActions_ComboInputGroup : public FAssetTypeActions_DataAsset
|
||||
{
|
||||
public:
|
||||
virtual FText GetName() const override { return NSLOCTEXT("AssetTypeActions", "AssetTypeActions_ComboActionGraph", "Combo Action Graph"); }
|
||||
virtual FText GetName() const override { return NSLOCTEXT("AssetTypeActions", "AssetTypeActions_ComboInputGroup", "Combo Input Asset"); }
|
||||
virtual uint32 GetCategories() override { return FComboInputEditorModule::GetInputAssetsCategory(); }
|
||||
virtual FColor GetTypeColor() const override { return FColor(255, 127, 255); }
|
||||
virtual FText GetAssetDescription(const FAssetData &AssetData) const override { return NSLOCTEXT("AssetTypeActions", "AssetTypeActions_ComboActionGraphDesc", "A node graph containing a sequence of combo actions. Each node can respond to any number of combo inputs, and when activated will execute the associated event."); }
|
||||
virtual UClass *GetSupportedClass() const override { return UComboActionGraph::StaticClass(); }
|
||||
|
||||
virtual void OpenAssetEditor(const TArray<UObject*> &InObjects, TSharedPtr<class IToolkitHost> EditWithinLevelEditor = TSharedPtr<IToolkitHost>()) override
|
||||
{
|
||||
const EToolkitMode::Type Mode = EditWithinLevelEditor.IsValid() ? EToolkitMode::WorldCentric : EToolkitMode::Standalone;
|
||||
for (auto ObjIt = InObjects.CreateConstIterator(); ObjIt; ObjIt++)
|
||||
{
|
||||
if (UComboActionGraph *Graph = Cast<UComboActionGraph>(*ObjIt))
|
||||
{
|
||||
TSharedRef<FAssetEditor_ComboActionGraph> NewGraphEditor(new FAssetEditor_ComboActionGraph());
|
||||
NewGraphEditor->InitComboActionGraphAssetEditor(Mode, EditWithinLevelEditor, Graph);
|
||||
}
|
||||
}
|
||||
}
|
||||
virtual FText GetAssetDescription(const FAssetData &AssetData) const override { return NSLOCTEXT("AssetTypeActions", "AssetTypeActions_ComboInputGroupDesc", "This maps a sequence of button inputs from EnhancedInput to a combo action that can be used to execute a sequence of moves.This gets sent from the input buffer subsystem to the player controller's ComboManagerComponent, which executes the associated action in the current ComboSequenceNode."); }
|
||||
virtual UClass *GetSupportedClass() const override { return UComboInputGroup::StaticClass(); }
|
||||
};
|
||||
|
||||
class FComboActionGraphPanelNodeFactory : public FGraphPanelNodeFactory
|
||||
{
|
||||
public:
|
||||
virtual TSharedPtr<class SGraphNode> CreateNode(UEdGraphNode *Node) const override
|
||||
{
|
||||
|
||||
if (UEdComboActionGraphNode *EdGraphNode = Cast<UEdComboActionGraphNode>(Node))
|
||||
{
|
||||
return SNew(SEdComboActionGraphNode, EdGraphNode);
|
||||
}
|
||||
else if (UEdComboActionGraphEdge *EdGraphEdge = Cast<UEdComboActionGraphEdge>(Node))
|
||||
{
|
||||
return SNew(SEdComboActionGraphEdge, EdGraphEdge);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
UComboAction_Factory::UComboAction_Factory(const FObjectInitializer &ObjectInitializer)
|
||||
: Super(ObjectInitializer)
|
||||
{
|
||||
this->SupportedClass = UComboAction::StaticClass();
|
||||
this->bEditAfterNew = true;
|
||||
this->bCreateNew = true;
|
||||
SupportedClass = UComboAction::StaticClass();
|
||||
bEditAfterNew = true;
|
||||
bCreateNew = true;
|
||||
}
|
||||
|
||||
UObject *UComboAction_Factory::FactoryCreateNew(UClass *Class, UObject *InParent, FName Name, EObjectFlags Flags, UObject *Context, FFeedbackContext *Warn)
|
||||
{
|
||||
if (this->ComboActionClass != nullptr)
|
||||
{
|
||||
return NewObject<UComboAction>(InParent, this->ComboActionClass, Name, Flags | EObjectFlags::RF_Transactional, Context);
|
||||
return NewObject<UComboAction>(InParent, this->ComboActionClass, Name, Flags | RF_Transactional, Context);
|
||||
}
|
||||
else
|
||||
{
|
||||
check(Class->IsChildOf(UComboAction::StaticClass()));
|
||||
return NewObject<UComboAction>(InParent, Class, Name, Flags | EObjectFlags::RF_Transactional, Context);
|
||||
return NewObject<UComboAction>(InParent, Class, Name, Flags | RF_Transactional, Context);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
UComboInputAsset_Factory::UComboInputAsset_Factory(const FObjectInitializer &ObjectInitializer)
|
||||
UComboSequenceNode_Factory::UComboSequenceNode_Factory(const FObjectInitializer &ObjectInitializer)
|
||||
: Super(ObjectInitializer)
|
||||
{
|
||||
this->SupportedClass = UComboInputAsset::StaticClass();
|
||||
this->bEditAfterNew = true;
|
||||
this->bCreateNew = true;
|
||||
SupportedClass = UComboSequenceNode::StaticClass();
|
||||
bEditAfterNew = true;
|
||||
bCreateNew = true;
|
||||
}
|
||||
|
||||
UObject *UComboInputAsset_Factory::FactoryCreateNew(UClass *Class, UObject *InParent, FName Name, EObjectFlags Flags, UObject *Context, FFeedbackContext *Warn)
|
||||
UObject *UComboSequenceNode_Factory::FactoryCreateNew(UClass *Class, UObject *InParent, FName Name, EObjectFlags Flags, UObject *Context, FFeedbackContext *Warn)
|
||||
{
|
||||
if (this->ComboInputAssetClass != nullptr)
|
||||
if (this->ComboSequenceNodeClass != nullptr)
|
||||
{
|
||||
return NewObject<UComboInputAsset>(InParent, this->ComboInputAssetClass, Name, Flags | EObjectFlags::RF_Transactional, Context);
|
||||
return NewObject<UComboSequenceNode>(InParent, this->ComboSequenceNodeClass, Name, Flags | RF_Transactional, Context);
|
||||
}
|
||||
else
|
||||
{
|
||||
check(Class->IsChildOf(UComboInputAsset::StaticClass()));
|
||||
return NewObject<UComboInputAsset>(InParent, Class, Name, Flags | EObjectFlags::RF_Transactional, Context);
|
||||
check(Class->IsChildOf(UComboSequenceNode::StaticClass()));
|
||||
return NewObject<UComboSequenceNode>(InParent, Class, Name, Flags | RF_Transactional, Context);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
UComboActionGraph_Factory::UComboActionGraph_Factory(const FObjectInitializer &ObjectInitializer)
|
||||
UComboInputGroup_Factory::UComboInputGroup_Factory(const FObjectInitializer &ObjectInitializer)
|
||||
: Super(ObjectInitializer)
|
||||
{
|
||||
this->SupportedClass = UComboActionGraph::StaticClass();
|
||||
this->bEditAfterNew = true;
|
||||
this->bCreateNew = true;
|
||||
SupportedClass = UComboInputGroup::StaticClass();
|
||||
bEditAfterNew = true;
|
||||
bCreateNew = true;
|
||||
}
|
||||
|
||||
UObject *UComboActionGraph_Factory::FactoryCreateNew(UClass *Class, UObject *InParent, FName Name, EObjectFlags Flags, UObject *Context, FFeedbackContext *Warn)
|
||||
UObject *UComboInputGroup_Factory::FactoryCreateNew(UClass *Class, UObject *InParent, FName Name, EObjectFlags Flags, UObject *Context, FFeedbackContext *Warn)
|
||||
{
|
||||
if (this->ComboActionGraphClass != nullptr)
|
||||
if (this->ComboInputGroupClass != nullptr)
|
||||
{
|
||||
return NewObject<UComboActionGraph>(InParent, this->ComboActionGraphClass, Name, Flags | EObjectFlags::RF_Transactional, Context);
|
||||
return NewObject<UComboInputGroup>(InParent, this->ComboInputGroupClass, Name, Flags | RF_Transactional, Context);
|
||||
}
|
||||
else
|
||||
{
|
||||
check(Class->IsChildOf(UComboActionGraph::StaticClass()));
|
||||
return NewObject<UComboActionGraph>(InParent, Class, Name, Flags | EObjectFlags::RF_Transactional, Context);
|
||||
check(Class->IsChildOf(UComboInputGroup::StaticClass()));
|
||||
return NewObject<UComboInputGroup>(InParent, Class, Name, Flags | RF_Transactional, Context);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FComboInputSlateStyle::FComboInputSlateStyle() : FSlateStyleSet("ComboInputEditor")
|
||||
|
||||
class FComboInputSlateStyle final : public FSlateStyleSet
|
||||
{
|
||||
this->SetParentStyleName(FAppStyle::GetAppStyleSetName());
|
||||
|
||||
const FString &PluginSlateDir = IPluginManager::Get().FindPlugin("ComboInput")->GetBaseDir();
|
||||
|
||||
this->SetContentRoot(PluginSlateDir / TEXT("Resources/Slate"));
|
||||
this->SetCoreContentRoot(FPaths::EngineContentDir() / TEXT("Slate"));
|
||||
|
||||
// Combo Input Editor icons
|
||||
static const FVector2D Icon12(12.0f, 12.0f);
|
||||
static const FVector2D Icon16(16.0f, 16.0f);
|
||||
static const FVector2D Icon40(40.0f, 40.0f);
|
||||
static const FVector2D Icon64(64.0f, 64.0f);
|
||||
|
||||
this->Set("ComboInputIcon_Small", new IMAGE_BRUSH_SVG("Icons/ComboInput_16", Icon16));
|
||||
this->Set("ComboInputIcon_Large", new IMAGE_BRUSH_SVG("Icons/ComboInput_64", Icon64));
|
||||
|
||||
this->Set("ClassIcon.ComboAction", new IMAGE_BRUSH_SVG("Icons/ComboAction_16", Icon16));
|
||||
this->Set("ClassThumbnail.ComboAction", new IMAGE_BRUSH_SVG("Icons/ComboAction_64", Icon64));
|
||||
|
||||
this->Set("ClassIcon.ComboSequenceNode", new IMAGE_BRUSH_SVG("Icons/ComboSequenceNode_16", Icon16));
|
||||
this->Set("ClassThumbnail.ComboSequenceNode", new IMAGE_BRUSH_SVG("Icons/ComboSequenceNode_64", Icon64));
|
||||
|
||||
this->Set("ClassIcon.ComboInputAsset", new IMAGE_BRUSH_SVG("Icons/ComboInputAsset_16", Icon16));
|
||||
this->Set("ClassThumbnail.ComboInputAsset", new IMAGE_BRUSH_SVG("Icons/ComboInputAsset_64", Icon64));
|
||||
|
||||
this->Set("ClassIcon.ComboActionGraph", new IMAGE_BRUSH_SVG("Icons/ComboSequenceNode_16", Icon16));
|
||||
this->Set("ClassThumbnail.ComboActionGraph", new IMAGE_BRUSH_SVG("Icons/ComboSequenceNode_64", Icon64));
|
||||
|
||||
// Combo Action Graph editor brushes
|
||||
public:
|
||||
FComboInputSlateStyle() : FSlateStyleSet("ComboInputEditor")
|
||||
{
|
||||
this->SetContentRoot(PluginSlateDir / TEXT("Resources/Slate/Editor"));
|
||||
this->SetCoreContentRoot(FPaths::EngineContentDir() / TEXT("Slate/Editor"));
|
||||
this->SetParentStyleName(FAppStyle::GetAppStyleSetName());
|
||||
|
||||
this->Set("MDSStyleSet.AutoArrange.small", new IMAGE_BRUSH(TEXT("AutoArrangeIcon"), Icon16));
|
||||
this->Set("MDSStyleSet.AutoArrange", new IMAGE_BRUSH(TEXT("AutoArrangeIcon"), Icon40));
|
||||
this->Set("MDSStyleSet.AutoArrange.large", new IMAGE_BRUSH(TEXT("AutoArrangeIcon"), Icon64));
|
||||
const FString &PluginSlateDir = IPluginManager::Get().FindPlugin("ComboInput")->GetBaseDir();
|
||||
|
||||
this->Set("MDSStyleSet.GraphSettings.small", new IMAGE_BRUSH(TEXT("GraphSettings"), Icon16));
|
||||
this->Set("MDSStyleSet.GraphSettings", new IMAGE_BRUSH(TEXT("GraphSettings"), Icon40));
|
||||
this->Set("MDSStyleSet.GraphSettings.large", new IMAGE_BRUSH(TEXT("GraphSettings"), Icon64));
|
||||
this->SetContentRoot(PluginSlateDir / TEXT("Resources/Slate"));
|
||||
this->SetCoreContentRoot(FPaths::EngineContentDir() / TEXT("Slate"));
|
||||
|
||||
this->Set("MDSStyleSet.ValidateGraph.small", new IMAGE_BRUSH(TEXT("ValidateGraph"), Icon16));
|
||||
this->Set("MDSStyleSet.ValidateGraph", new IMAGE_BRUSH(TEXT("ValidateGraph"), Icon40));
|
||||
this->Set("MDSStyleSet.ValidateGraph.large", new IMAGE_BRUSH(TEXT("ValidateGraph"), Icon64));
|
||||
// Combo Input Editor icons
|
||||
static const FVector2D Icon16 = FVector2D(16.0f, 16.0f);
|
||||
static const FVector2D Icon64 = FVector2D(64.0f, 64.0f);
|
||||
|
||||
this->Set("MDSStyleSet.Graph.NodeOverlay", new BOX_BRUSH(TEXT("NodeOverlay"), FMargin(8.0f / 64.0f, 3.0f / 32.0f, 0, 0)));
|
||||
this->Set("MDSStyleSet.Graph.PinDocksOverlay", new BOX_BRUSH(TEXT("PinDocksOverlay"), FMargin(8.0f / 64.0f, 3.0f / 32.0f, 0, 0)));
|
||||
this->Set("ComboInputIcon_Small", new IMAGE_BRUSH_SVG("Icons/ComboInput_16", Icon16));
|
||||
this->Set("ComboInputIcon_Large", new IMAGE_BRUSH_SVG("Icons/ComboInput_64", Icon64));
|
||||
|
||||
this->Set("MDSStyleSet.Graph.SimpleArrow", new IMAGE_BRUSH(TEXT("SimpleArrow"), Icon16));
|
||||
this->Set("MDSStyleSet.Graph.HollowArrow", new IMAGE_BRUSH(TEXT("HollowArrow"), Icon16));
|
||||
this->Set("MDSStyleSet.Graph.FancyArrow", new IMAGE_BRUSH(TEXT("FancyArrow"), Icon16));
|
||||
this->Set("MDSStyleSet.Graph.Bubble", new IMAGE_BRUSH(TEXT("Bubble"), Icon16));
|
||||
this->Set("ClassIcon.ComboAction", new IMAGE_BRUSH_SVG("Icons/ComboAction_16", Icon16));
|
||||
this->Set("ClassThumbnail.ComboAction", new IMAGE_BRUSH_SVG("Icons/ComboAction_64", Icon64));
|
||||
|
||||
this->Set("MDSStyleSet.Node.SoftEdges", new BOX_BRUSH(TEXT("NodeSoftCorners"), FMargin(16.f / 64.f, 25.f / 64.f, 16.f / 64.f, 16.f / 64.f)));
|
||||
this->Set("MDSStyleSet.Node.HardEdges", new BOX_BRUSH(TEXT("NodeHardCorners"), FMargin(16.f / 64.f, 25.f / 64.f, 16.f / 64.f, 16.f / 64.f)));
|
||||
this->Set("ClassIcon.ComboSequenceNode", new IMAGE_BRUSH_SVG("Icons/ComboSequenceNode_16", Icon16));
|
||||
this->Set("ClassThumbnail.ComboSequenceNode", new IMAGE_BRUSH_SVG("Icons/ComboSequenceNode_64", Icon64));
|
||||
|
||||
this->Set("MDSStyleSet.Node.TextSoftEdges", new BOX_BRUSH(TEXT("TextSoftCorners"), FMargin(16.f / 64.f, 25.f / 64.f, 16.f / 64.f, 16.f / 64.f)));
|
||||
this->Set("MDSStyleSet.Node.TextHardEdges", new BOX_BRUSH(TEXT("TextHardCorners"), FMargin(16.f / 64.f, 25.f / 64.f, 16.f / 64.f, 16.f / 64.f)));
|
||||
|
||||
this->Set("MDSStyleSet.Node.IndexCircle", new IMAGE_BRUSH(TEXT("IndexIcon"), Icon16));
|
||||
|
||||
this->Set("MDSStyleSet.Icon.OK", new IMAGE_BRUSH(TEXT("OKIcon"), Icon16));
|
||||
this->Set("MDSStyleSet.Icon.Error", new IMAGE_BRUSH(TEXT("ErroIcon"), Icon16));
|
||||
this->Set("MDSStyleSet.Icon.BulletPoint", new IMAGE_BRUSH(TEXT("CircleBox"), Icon16));
|
||||
|
||||
this->Set("MDSStyleSet.Graph.CornerImage", new IMAGE_BRUSH(TEXT("Icon128"), FVector2D(128.0f, 128.0f)));
|
||||
|
||||
this->Set("MDSStyleSet.Icon.Browse", new IMAGE_BRUSH(TEXT("BrowseIcon"), Icon12));
|
||||
this->Set("MDSStyleSet.Icon.Edit", new IMAGE_BRUSH(TEXT("EditIcon"), Icon12));
|
||||
|
||||
this->Set("MDSStyleSet.Buttons.Documentation", new IMAGE_BRUSH(TEXT("Documentation"), FVector2D(200.0f, 70.0f)));
|
||||
this->Set("MDSStyleSet.Buttons.Documentation.small", new IMAGE_BRUSH(TEXT("DocumentationIcon"), Icon12));
|
||||
|
||||
this->Set("MDSStyleSet.Node.Icon.large", new IMAGE_BRUSH(TEXT("DialogueNodeIcon"), Icon64));
|
||||
this->Set("MDSStyleSet.Node.Icon", new IMAGE_BRUSH(TEXT("DialogueNodeIcon"), Icon16));
|
||||
this->Set("MDSStyleSet.Node.Icon.small", new IMAGE_BRUSH(TEXT("DialogueNodeIcon"), Icon12));
|
||||
|
||||
this->Set("MDSStyleSet.Icon.Close", new IMAGE_BRUSH(TEXT("CloseIcon"), Icon12));
|
||||
this->Set("MDSStyleSet.Icon.HeartIcon", new IMAGE_BRUSH(TEXT("HeartIcon"), Icon12));
|
||||
this->Set("MDSStyleSet.Icon.UBIcon", new IMAGE_BRUSH(TEXT("UnrealBucketIcon"), Icon12));
|
||||
this->Set("MDSStyleSet.Icon.MoneyIcon", new IMAGE_BRUSH(TEXT("MoneyIcon"), Icon12));
|
||||
|
||||
this->Set("MDSStyleSet.Buttons.Style", FButtonStyle()
|
||||
.SetNormal(BOX_BRUSH("RoundedSelection_16x", 4.0f / 16.0f, FLinearColor(1, 1, 1, 0.1f)))
|
||||
.SetHovered(BOX_BRUSH("RoundedSelection_16x", 4.0f / 16.0f, FLinearColor(1, .55f, 0, 0.2f)))
|
||||
.SetPressed(BOX_BRUSH("RoundedSelection_16x", 4.0f / 16.0f, FLinearColor(1, .55f, 0, 0.4f))));
|
||||
const FScrollBarStyle ScrollBar = GetWidgetStyle<FScrollBarStyle>("ScrollBar");
|
||||
|
||||
FTextBlockStyle NormalText = FTextBlockStyle()
|
||||
.SetFont(DEFAULT_FONT("Regular", FCoreStyle::RegularTextSize))
|
||||
.SetColorAndOpacity(FSlateColor::UseForeground())
|
||||
.SetShadowOffset(FVector2D::ZeroVector)
|
||||
.SetShadowColorAndOpacity(FLinearColor::Black)
|
||||
.SetHighlightColor(FLinearColor(0.02f, 0.3f, 0.0f))
|
||||
.SetHighlightShape(BOX_BRUSH("TextBlockHighlightShape", FMargin(3.f / 8.f)));
|
||||
|
||||
FTextBlockStyle NodeTitle = FTextBlockStyle(NormalText)
|
||||
.SetFont(DEFAULT_FONT("Bold", 14))
|
||||
.SetColorAndOpacity(FLinearColor(230.0f / 255.0f, 230.0f / 255.0f, 230.0f / 255.0f))
|
||||
.SetShadowOffset(FVector2D(2, 2))
|
||||
.SetShadowColorAndOpacity(FLinearColor(0.f, 0.f, 0.f, 0.7f));
|
||||
this->Set("MDSStyleSet.NodeTitle", NodeTitle);
|
||||
|
||||
FEditableTextBoxStyle NodeTitleEditableText = FEditableTextBoxStyle()
|
||||
.SetFont(NormalText.Font)
|
||||
.SetBackgroundImageNormal(BOX_BRUSH("TextBox", FMargin(4.0f / 16.0f)))
|
||||
.SetBackgroundImageHovered(BOX_BRUSH("TextBox_Hovered", FMargin(4.0f / 16.0f)))
|
||||
.SetBackgroundImageFocused(BOX_BRUSH("TextBox_Hovered", FMargin(4.0f / 16.0f)))
|
||||
.SetBackgroundImageReadOnly(BOX_BRUSH("TextBox_ReadOnly", FMargin(4.0f / 16.0f)))
|
||||
.SetScrollBarStyle(ScrollBar);
|
||||
this->Set("MDSStyleSet.NodeTitleEditableText", NodeTitleEditableText);
|
||||
|
||||
this->Set("MDSStyleSet.NodeTitleInlineEditableText", FInlineEditableTextBlockStyle()
|
||||
.SetTextStyle(NodeTitle)
|
||||
.SetEditableTextBoxStyle(NodeTitleEditableText)
|
||||
);
|
||||
this->Set("ClassIcon.ComboInputGroup", new IMAGE_BRUSH_SVG("Icons/ComboInputGroup_16", Icon16));
|
||||
this->Set("ClassThumbnail.ComboInputGroup", new IMAGE_BRUSH_SVG("Icons/ComboInputGroup_64", Icon64));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
void FComboInputEditorModule::StartupModule()
|
||||
{
|
||||
// Register combo action asset
|
||||
IAssetTools &AssetTools = FModuleManager::LoadModuleChecked<FAssetToolsModule>("AssetTools").Get();
|
||||
FComboInputEditorModule::ComboAssetsCategory = AssetTools.RegisterAdvancedAssetCategory(FName(TEXT("Combo Input")), LOCTEXT("ComboInputAssetsCategory", "Combo Input"));
|
||||
FComboInputEditorModule::ComboAssetsCategory = AssetTools.RegisterAdvancedAssetCategory(FName(TEXT("Input")), LOCTEXT("InputAssetsCategory", "Input"));
|
||||
this->RegisterAssetTypeActions(AssetTools, MakeShareable(new FAssetTypeActions_ComboAction));
|
||||
this->RegisterAssetTypeActions(AssetTools, MakeShareable(new FAssetTypeActions_ComboInputAsset));
|
||||
this->RegisterAssetTypeActions(AssetTools, MakeShareable(new FAssetTypeActions_ComboSequenceNode));
|
||||
this->RegisterAssetTypeActions(AssetTools, MakeShareable(new FAssetTypeActions_ComboInputGroup));
|
||||
|
||||
// Make a new style set for Combo Input, which will register any custom icons for the types in this plugin
|
||||
this->ComboInputEditorStyleSet = MakeShared<FComboInputSlateStyle>();
|
||||
FSlateStyleRegistry::RegisterSlateStyle(*this->ComboInputEditorStyleSet.Get());
|
||||
|
||||
// Combo Action Graph
|
||||
{
|
||||
this->ComboActionGraphPanelNodeFactory = MakeShareable(new FComboActionGraphPanelNodeFactory());
|
||||
FEdGraphUtilities::RegisterVisualNodeFactory(this->ComboActionGraphPanelNodeFactory);
|
||||
|
||||
// Register asset actions
|
||||
this->ComboActionGraphAssetActions = MakeShared<FAssetTypeActions_ComboActionGraph>();
|
||||
this->RegisterAssetTypeActions(AssetTools, this->ComboActionGraphAssetActions.ToSharedRef());
|
||||
}
|
||||
|
||||
FComboActionGraphEditorCommands::Register();
|
||||
StyleSet = MakeShared<FComboInputSlateStyle>();
|
||||
FSlateStyleRegistry::RegisterSlateStyle(*StyleSet.Get());
|
||||
}
|
||||
|
||||
void FComboInputEditorModule::ShutdownModule()
|
||||
{
|
||||
FComboActionGraphEditorCommands::Unregister();
|
||||
}
|
||||
|
||||
#undef LOCTEXT_NAMESPACE
|
||||
|
||||
IMPLEMENT_MODULE(FComboInputEditorModule, ComboInputEditorModule)
|
||||
IMPLEMENT_MODULE(FComboInputEditorModule, ComboInputEditorModule)
|
||||
@ -1,922 +0,0 @@
|
||||
// ©2023 Batty Bovine Productions, LLC. All Rights Reserved.
|
||||
|
||||
#include "AssetEditor_ComboActionGraph.h"
|
||||
|
||||
#include "ComboActionGraph.h"
|
||||
#include "ComboActionGraphSchema.h"
|
||||
#include "ComboInputEditor.h"
|
||||
#include "EdGraphUtilities.h"
|
||||
#include "GraphEditorActions.h"
|
||||
|
||||
#include "Ed/EdComboActionGraph.h"
|
||||
#include "Ed/EdComboActionGraphEdge.h"
|
||||
#include "Ed/EdComboActionGraphNode.h"
|
||||
#include "Ed/FAssetEditorToolbarComboActionGraph.h"
|
||||
#include "Ed/FComboActionGraphEditorCommands.h"
|
||||
#include "Framework/Commands/GenericCommands.h"
|
||||
#include "HAL/PlatformApplicationMisc.h"
|
||||
#include "Kismet2/BlueprintEditorUtils.h"
|
||||
#include "Layout/AssetEditorTabs.h"
|
||||
#include "Layout/ComboActionGraphLayoutStrategy.h"
|
||||
#include "Layout/ComboActionForceDirectedSolveLayoutStrategy.h"
|
||||
#include "Layout/ComboActionTreeSolveLayoutStrategy.h"
|
||||
#include "Nodes/ComboActionGraphNode.h"
|
||||
#include "Popups/ComboInputPopup_GraphValidation.h"
|
||||
#include "Search/ComboActionSearchUtils.h"
|
||||
#include "Search/SComboActionSearch.h"
|
||||
#include "Settings/ComboActionGraphEditorSettings.h"
|
||||
#include "UObject/ObjectSaveContext.h"
|
||||
|
||||
#define LOCTEXT_NAMESPACE "AssetEditor_ComboActionGraph"
|
||||
|
||||
DEFINE_LOG_CATEGORY(LogAssetEditorComboActionGraph);
|
||||
|
||||
#pragma region ConstantNames
|
||||
|
||||
const FName ComboActionGraphEditorAppName = FName(TEXT("ComboActionGraphEditorApp"));
|
||||
const FName FAssetEditorTabs_ComboActionGraph::ComboActionGraphPropertyID(TEXT("ComboActionGraphProperty"));
|
||||
const FName FAssetEditorTabs_ComboActionGraph::ViewportID(TEXT("Viewport"));
|
||||
const FName FAssetEditorTabs_ComboActionGraph::SearchToolbarID(TEXT("Search"));
|
||||
|
||||
#pragma endregion
|
||||
|
||||
|
||||
FAssetEditor_ComboActionGraph::FAssetEditor_ComboActionGraph()
|
||||
{
|
||||
this->EditingGraph = nullptr;
|
||||
this->ComboActionGraphEditorSettings = GetMutableDefault<UComboActionGraphEditorSettings>();
|
||||
this->OnPackageSavedDelegateHandle = UPackage::PackageSavedWithContextEvent.AddRaw(this, &FAssetEditor_ComboActionGraph::OnPackageSaved);
|
||||
}
|
||||
|
||||
FAssetEditor_ComboActionGraph::~FAssetEditor_ComboActionGraph()
|
||||
{
|
||||
this->EditingGraph = nullptr;
|
||||
UPackage::PackageSavedWithContextEvent.Remove(this->OnPackageSavedDelegateHandle);
|
||||
|
||||
this->ToolbarBuilder.Reset();
|
||||
}
|
||||
|
||||
void FAssetEditor_ComboActionGraph::OnPackageSaved(const FString &String, UPackage *Package, FObjectPostSaveContext ObjectPostSaveContext)
|
||||
{
|
||||
this->RebuildComboActionGraph();
|
||||
}
|
||||
|
||||
void FAssetEditor_ComboActionGraph::InitComboActionGraphAssetEditor(const EToolkitMode::Type Mode, const TSharedPtr<IToolkitHost>& InitToolkitHost, UComboActionGraph *Graph)
|
||||
{
|
||||
this->EditingGraph = Graph;
|
||||
this->CreateEdGraph();
|
||||
|
||||
if (!this->ToolbarBuilder.IsValid())
|
||||
{
|
||||
this->ToolbarBuilder = MakeShareable(new FAssetEditorToolbarComboActionGraph(SharedThis(this)));
|
||||
}
|
||||
|
||||
this->BindCommands();
|
||||
|
||||
this->CreateInternalWidgets();
|
||||
|
||||
TSharedPtr<FExtender> ToolbarExtender = MakeShareable(new FExtender);
|
||||
this->ToolbarBuilder->AddComboActionGraphToolbar(ToolbarExtender);
|
||||
|
||||
// Layout
|
||||
const TSharedRef<FTabManager::FLayout> StandaloneDefaultLayout = FTabManager::NewLayout("Standalone_ComboActionGraphEditor_LayoutV0.3")
|
||||
->AddArea
|
||||
(
|
||||
FTabManager::NewPrimaryArea()->SetOrientation(EOrientation::Orient_Vertical)
|
||||
->Split
|
||||
(
|
||||
FTabManager::NewSplitter()->SetOrientation(EOrientation::Orient_Horizontal)->SetSizeCoefficient(0.9f)
|
||||
->Split
|
||||
(
|
||||
FTabManager::NewStack()
|
||||
->SetSizeCoefficient(3.f)
|
||||
->AddTab(FAssetEditorTabs_ComboActionGraph::ViewportID, ETabState::OpenedTab)->SetHideTabWell(true)
|
||||
)
|
||||
->Split
|
||||
(
|
||||
FTabManager::NewSplitter()->SetOrientation(EOrientation::Orient_Vertical)
|
||||
->Split
|
||||
(
|
||||
FTabManager::NewSplitter()->SetOrientation(EOrientation::Orient_Vertical)
|
||||
->Split
|
||||
(
|
||||
FTabManager::NewStack()
|
||||
->SetSizeCoefficient(0.9f)
|
||||
->AddTab(FAssetEditorTabs_ComboActionGraph::ComboActionGraphPropertyID, ETabState::OpenedTab)->SetHideTabWell(true)
|
||||
)
|
||||
|
||||
->Split
|
||||
(
|
||||
FTabManager::NewStack()
|
||||
->SetSizeCoefficient(0.3f)
|
||||
->AddTab(FAssetEditorTabs_ComboActionGraph::SearchToolbarID, ETabState::OpenedTab)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
const bool bCreateDefaultStandaloneMenu = true;
|
||||
const bool bCreateDefaultToolbar = true;
|
||||
FAssetEditorToolkit::InitAssetEditor
|
||||
(
|
||||
Mode,
|
||||
InitToolkitHost,
|
||||
ComboActionGraphEditorAppName,
|
||||
StandaloneDefaultLayout,
|
||||
bCreateDefaultStandaloneMenu,
|
||||
bCreateDefaultToolbar,
|
||||
EditingGraph,
|
||||
false
|
||||
);
|
||||
|
||||
this->RegenerateMenusAndToolbars();
|
||||
}
|
||||
|
||||
UComboActionGraphEditorSettings *FAssetEditor_ComboActionGraph::GetSettings() const
|
||||
{
|
||||
return this->ComboActionGraphEditorSettings;
|
||||
}
|
||||
|
||||
void FAssetEditor_ComboActionGraph::RegisterTabSpawners(const TSharedRef<FTabManager> &InTabManager)
|
||||
{
|
||||
this->WorkspaceMenuCategory = InTabManager->AddLocalWorkspaceMenuCategory(LOCTEXT("WorkspaceMenu_ComboActionTreeEditor", "Combo Action Tree Editor"));
|
||||
auto WorkspaceMenuCategoryRef = this->WorkspaceMenuCategory.ToSharedRef();
|
||||
|
||||
FAssetEditorToolkit::RegisterTabSpawners(InTabManager);
|
||||
|
||||
InTabManager->RegisterTabSpawner(FAssetEditorTabs_ComboActionGraph::ViewportID, FOnSpawnTab::CreateSP(this, &FAssetEditor_ComboActionGraph::SpawnTab_Viewport))
|
||||
.SetDisplayName(LOCTEXT("GraphCanvasTab", "Viewport"))
|
||||
.SetGroup(WorkspaceMenuCategoryRef)
|
||||
.SetIcon(FSlateIcon(FAppStyle::GetAppStyleSetName(), "GraphEditor.EventGraph_16x"));
|
||||
|
||||
InTabManager->RegisterTabSpawner(FAssetEditorTabs_ComboActionGraph::ComboActionGraphPropertyID, FOnSpawnTab::CreateSP(this, &FAssetEditor_ComboActionGraph::SpawnTab_Details))
|
||||
.SetDisplayName(LOCTEXT("DetailsTab", "Property"))
|
||||
.SetGroup(WorkspaceMenuCategoryRef)
|
||||
.SetIcon(FSlateIcon(FAppStyle::GetAppStyleSetName(), "LevelEditor.Tabs.Details"));
|
||||
|
||||
InTabManager->RegisterTabSpawner(FAssetEditorTabs_ComboActionGraph::SearchToolbarID, FOnSpawnTab::CreateSP(this, &FAssetEditor_ComboActionGraph::SpawnTab_Search))
|
||||
.SetDisplayName(LOCTEXT("SearchTab", "Search"))
|
||||
.SetGroup(WorkspaceMenuCategoryRef)
|
||||
.SetIcon(FSlateIcon(FAppStyle::GetAppStyleSetName(), "Kismet.Tabs.FindResults"));
|
||||
}
|
||||
|
||||
void FAssetEditor_ComboActionGraph::UnregisterTabSpawners(const TSharedRef<FTabManager> &InTabManager)
|
||||
{
|
||||
FAssetEditorToolkit::UnregisterTabSpawners(InTabManager);
|
||||
|
||||
InTabManager->UnregisterTabSpawner(FAssetEditorTabs_ComboActionGraph::ViewportID);
|
||||
InTabManager->UnregisterTabSpawner(FAssetEditorTabs_ComboActionGraph::ComboActionGraphPropertyID);
|
||||
InTabManager->UnregisterTabSpawner(FAssetEditorTabs_ComboActionGraph::SearchToolbarID);
|
||||
}
|
||||
|
||||
bool FAssetEditor_ComboActionGraph::CloseWindow(EAssetEditorCloseReason InCloseReason)
|
||||
{
|
||||
const bool bSatisfied = FAssetEditorToolkit::CloseWindow(InCloseReason);
|
||||
|
||||
if (this->EditingGraph)
|
||||
{
|
||||
if (this->EditingGraph->EdGraph)
|
||||
{
|
||||
UEdComboActionGraph *EdGraph = Cast<UEdComboActionGraph>(this->EditingGraph->EdGraph);
|
||||
if (EdGraph->GetComboActionEditorPtr().HasSameObject(this)) EdGraph->ResetDialogueEditorPtr();
|
||||
}
|
||||
}
|
||||
|
||||
return bSatisfied;
|
||||
}
|
||||
|
||||
FName FAssetEditor_ComboActionGraph::GetToolkitFName() const
|
||||
{
|
||||
return FName("FComboActionGraphEditor");
|
||||
}
|
||||
|
||||
FText FAssetEditor_ComboActionGraph::GetBaseToolkitName() const
|
||||
{
|
||||
return LOCTEXT("ComboActionGraphEditorAppLabel", "Combo Action Graph Editor");
|
||||
}
|
||||
|
||||
FText FAssetEditor_ComboActionGraph::GetToolkitName() const
|
||||
{
|
||||
const bool bDirtyState = this->EditingGraph->GetOutermost()->IsDirty();
|
||||
|
||||
FFormatNamedArguments Args;
|
||||
Args.Add(TEXT("ComboActionGraphName"), FText::FromString(this->EditingGraph->GetName()));
|
||||
Args.Add(TEXT("DirtyState"), bDirtyState ? FText::FromString(TEXT("*")) : FText::GetEmpty());
|
||||
return FText::Format(LOCTEXT("ComboActionGraphEditorToolkitName", "{ComboActionGraphName}{DirtyState}"), Args);
|
||||
}
|
||||
|
||||
FText FAssetEditor_ComboActionGraph::GetToolkitToolTipText() const
|
||||
{
|
||||
return FAssetEditorToolkit::GetToolTipTextForObject(EditingGraph);
|
||||
}
|
||||
|
||||
FLinearColor FAssetEditor_ComboActionGraph::GetWorldCentricTabColorScale() const
|
||||
{
|
||||
return FLinearColor::Gray;
|
||||
}
|
||||
|
||||
FString FAssetEditor_ComboActionGraph::GetWorldCentricTabPrefix() const
|
||||
{
|
||||
return TEXT("ComboActionGraphEditor");
|
||||
}
|
||||
|
||||
FString FAssetEditor_ComboActionGraph::GetDocumentationLink() const
|
||||
{
|
||||
return TEXT("There should be a link to the documentation here someday.");
|
||||
}
|
||||
|
||||
void FAssetEditor_ComboActionGraph::SaveAsset_Execute()
|
||||
{
|
||||
if (this->EditingGraph != nullptr)
|
||||
{
|
||||
this->RebuildComboActionGraph();
|
||||
}
|
||||
|
||||
FAssetEditorToolkit::SaveAsset_Execute();
|
||||
}
|
||||
|
||||
void FAssetEditor_ComboActionGraph::UpdateToolbar()
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
void FAssetEditor_ComboActionGraph::RegisterToolbarTab(const TSharedRef<FTabManager> &InTabManager)
|
||||
{
|
||||
FAssetEditorToolkit::RegisterTabSpawners(InTabManager);
|
||||
}
|
||||
|
||||
void FAssetEditor_ComboActionGraph::AddReferencedObjects(FReferenceCollector &Collector)
|
||||
{
|
||||
Collector.AddReferencedObject(this->EditingGraph);
|
||||
Collector.AddReferencedObject(this->EditingGraph->EdGraph);
|
||||
}
|
||||
|
||||
FString FAssetEditor_ComboActionGraph::GetReferencerName() const
|
||||
{
|
||||
return TEXT("FAssetEditor_ComboActionGraph");
|
||||
}
|
||||
|
||||
void FAssetEditor_ComboActionGraph::SetDialogueBeingEdited(UComboActionGraph *NewDialogue)
|
||||
{
|
||||
if (NewDialogue == nullptr || NewDialogue == this->EditingGraph)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
UComboActionGraph *Previous = this->EditingGraph;
|
||||
this->EditingGraph = NewDialogue;
|
||||
|
||||
this->RemoveEditingObject(Previous);
|
||||
this->AddEditingObject(NewDialogue);
|
||||
}
|
||||
|
||||
void FAssetEditor_ComboActionGraph::CreateInternalWidgets()
|
||||
{
|
||||
this->ViewportWidget = this->CreateViewportWidget();
|
||||
|
||||
FDetailsViewArgs Args;
|
||||
Args.bUpdatesFromSelection = false;
|
||||
Args.bLockable = false;
|
||||
Args.bAllowSearch = true;
|
||||
Args.NameAreaSettings = FDetailsViewArgs::HideNameArea;
|
||||
Args.bHideSelectionTip = false;
|
||||
Args.bShowObjectLabel = false;
|
||||
|
||||
FPropertyEditorModule &PropertyModule = FModuleManager::LoadModuleChecked<FPropertyEditorModule>("PropertyEditor");
|
||||
this->PropertyWidget = PropertyModule.CreateDetailView(Args);
|
||||
this->PropertyWidget->SetObject(this->EditingGraph);
|
||||
|
||||
this->PropertyWidget->OnFinishedChangingProperties().AddSP(this, &FAssetEditor_ComboActionGraph::OnFinishedChangingProperties);
|
||||
|
||||
this->FindResultsView = SNew(SComboActionSearch, SharedThis(this));
|
||||
}
|
||||
|
||||
TSharedRef<SGraphEditor> FAssetEditor_ComboActionGraph::CreateViewportWidget()
|
||||
{
|
||||
const FComboInputEditorModule &Module = FModuleManager::GetModuleChecked<FComboInputEditorModule>("ComboInputEditor");
|
||||
FGraphAppearanceInfo AppearanceInfo;
|
||||
AppearanceInfo.CornerText = LOCTEXT("AppearanceCornerText_ComboActionGraph", "Combo Action Tree");
|
||||
AppearanceInfo.CornerImage = Module.Get().GetComboInputEditorStyleSet()->GetBrush(TEXT("MDSStyleSet.Graph.CornerImage"));
|
||||
AppearanceInfo.InstructionText = LOCTEXT("InstructionText_ComboActionGraph", "Place action nodes by right clicking.");
|
||||
|
||||
this->CreateCommandList();
|
||||
|
||||
SGraphEditor::FGraphEditorEvents InEvents;
|
||||
InEvents.OnSelectionChanged = SGraphEditor::FOnSelectionChanged::CreateSP(this, &FAssetEditor_ComboActionGraph::OnSelectedNodesChanged);
|
||||
InEvents.OnNodeDoubleClicked = FSingleNodeEvent::CreateSP(this, &FAssetEditor_ComboActionGraph::OnNodeDoubleClicked);
|
||||
|
||||
return SNew(SGraphEditor)
|
||||
.AdditionalCommands(GraphEditorCommands)
|
||||
.IsEditable(true)
|
||||
.Appearance(AppearanceInfo)
|
||||
.GraphToEdit(EditingGraph->EdGraph)
|
||||
.GraphEvents(InEvents)
|
||||
.AutoExpandActionMenu(true)
|
||||
.ShowGraphStateOverlay(false);
|
||||
}
|
||||
|
||||
void FAssetEditor_ComboActionGraph::BindCommands()
|
||||
{
|
||||
this->ToolkitCommands->MapAction
|
||||
(
|
||||
FComboActionGraphEditorCommands::Get().AutoArrange,
|
||||
FExecuteAction::CreateSP(this, &FAssetEditor_ComboActionGraph::AutoArrange),
|
||||
FCanExecuteAction::CreateSP(this, &FAssetEditor_ComboActionGraph::CanAutoArrange)
|
||||
);
|
||||
|
||||
this->ToolkitCommands->MapAction
|
||||
(
|
||||
FComboActionGraphEditorCommands::Get().ValidateGraph,
|
||||
FExecuteAction::CreateSP(this, &FAssetEditor_ComboActionGraph::ValidateGraph),
|
||||
FCanExecuteAction::CreateSP(this, &FAssetEditor_ComboActionGraph::CanValidateGraph)
|
||||
);
|
||||
}
|
||||
|
||||
void FAssetEditor_ComboActionGraph::CreateEdGraph()
|
||||
{
|
||||
if (this->EditingGraph->EdGraph == nullptr)
|
||||
{
|
||||
this->EditingGraph->EdGraph = CastChecked<UEdComboActionGraph>(FBlueprintEditorUtils::CreateNewGraph(EditingGraph, NAME_None, UEdComboActionGraph::StaticClass(), UComboActionGraphSchema::StaticClass()));
|
||||
this->EditingGraph->EdGraph->bAllowDeletion = false;
|
||||
|
||||
// Give the schema a chance to fill out any required nodes (like the results node)
|
||||
const UEdGraphSchema *Schema = this->EditingGraph->EdGraph->GetSchema();
|
||||
Schema->CreateDefaultNodesForGraph(*this->EditingGraph->EdGraph);
|
||||
|
||||
UEdComboActionGraph *ComboActionGraph = Cast<UEdComboActionGraph>(this->EditingGraph->EdGraph);
|
||||
UEdComboActionGraphNode *NewNode = ComboActionGraph->CreateIntermediateNode<UEdComboActionGraphNode>();
|
||||
|
||||
NewNode->SetComboActionGraphNode(this->EditingGraph->StartNode);
|
||||
NewNode->CreateNewGuid();
|
||||
NewNode->PostPlacedNewNode();
|
||||
NewNode->AllocateDefaultPins();
|
||||
NewNode->AutowireNewNode(nullptr);
|
||||
|
||||
NewNode->NodePosX = 0;
|
||||
NewNode->NodePosY = 0;
|
||||
|
||||
NewNode->ComboActionGraphNode->SetFlags(EObjectFlags::RF_Transactional);
|
||||
NewNode->SetFlags(EObjectFlags::RF_Transactional);
|
||||
|
||||
ComboActionGraph->RebuildComboActionGraph();
|
||||
}
|
||||
|
||||
if (UEdComboActionGraph *EdComboActionGraph = Cast<UEdComboActionGraph>(this->EditingGraph->EdGraph))
|
||||
{
|
||||
EdComboActionGraph->SetDialogueEditorPtr(SharedThis(this));
|
||||
EdComboActionGraph->RebuildComboActionGraph();
|
||||
}
|
||||
}
|
||||
|
||||
void FAssetEditor_ComboActionGraph::CreateCommandList()
|
||||
{
|
||||
if (this->GraphEditorCommands.IsValid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this->GraphEditorCommands = MakeShareable(new FUICommandList);
|
||||
|
||||
this->GraphEditorCommands->MapAction(FComboActionGraphEditorCommands::Get().AutoArrange,
|
||||
FExecuteAction::CreateRaw(this, &FAssetEditor_ComboActionGraph::AutoArrange),
|
||||
FCanExecuteAction::CreateRaw(this, &FAssetEditor_ComboActionGraph::CanAutoArrange));
|
||||
|
||||
this->GraphEditorCommands->MapAction(FComboActionGraphEditorCommands::Get().ValidateGraph,
|
||||
FExecuteAction::CreateRaw(this, &FAssetEditor_ComboActionGraph::ValidateGraph),
|
||||
FCanExecuteAction::CreateRaw(this, &FAssetEditor_ComboActionGraph::CanValidateGraph));
|
||||
|
||||
this->GraphEditorCommands->MapAction(FGenericCommands::Get().SelectAll,
|
||||
FExecuteAction::CreateRaw(this, &FAssetEditor_ComboActionGraph::SelectAllNodes),
|
||||
FCanExecuteAction::CreateRaw(this, &FAssetEditor_ComboActionGraph::CanSelectAllNodes)
|
||||
);
|
||||
|
||||
this->GraphEditorCommands->MapAction(FGenericCommands::Get().Delete,
|
||||
FExecuteAction::CreateRaw(this, &FAssetEditor_ComboActionGraph::DeleteSelectedNodes),
|
||||
FCanExecuteAction::CreateRaw(this, &FAssetEditor_ComboActionGraph::CanDeleteNodes)
|
||||
);
|
||||
|
||||
this->GraphEditorCommands->MapAction(FGenericCommands::Get().Copy,
|
||||
FExecuteAction::CreateRaw(this, &FAssetEditor_ComboActionGraph::CopySelectedNodes),
|
||||
FCanExecuteAction::CreateRaw(this, &FAssetEditor_ComboActionGraph::CanCopyNodes)
|
||||
);
|
||||
|
||||
this->GraphEditorCommands->MapAction(FGenericCommands::Get().Cut,
|
||||
FExecuteAction::CreateRaw(this, &FAssetEditor_ComboActionGraph::CutSelectedNodes),
|
||||
FCanExecuteAction::CreateRaw(this, &FAssetEditor_ComboActionGraph::CanCutNodes)
|
||||
);
|
||||
|
||||
this->GraphEditorCommands->MapAction(FGenericCommands::Get().Paste,
|
||||
FExecuteAction::CreateRaw(this, &FAssetEditor_ComboActionGraph::PasteNodes),
|
||||
FCanExecuteAction::CreateRaw(this, &FAssetEditor_ComboActionGraph::CanPasteNodes)
|
||||
);
|
||||
|
||||
this->GraphEditorCommands->MapAction(FGenericCommands::Get().Duplicate,
|
||||
FExecuteAction::CreateRaw(this, &FAssetEditor_ComboActionGraph::DuplicateNodes),
|
||||
FCanExecuteAction::CreateRaw(this, &FAssetEditor_ComboActionGraph::CanDuplicateNodes)
|
||||
);
|
||||
|
||||
this->GraphEditorCommands->MapAction(FGenericCommands::Get().Rename,
|
||||
FExecuteAction::CreateSP(this, &FAssetEditor_ComboActionGraph::OnRenameNode),
|
||||
FCanExecuteAction::CreateSP(this, &FAssetEditor_ComboActionGraph::CanRenameNodes)
|
||||
);
|
||||
}
|
||||
|
||||
TSharedPtr<SGraphEditor> FAssetEditor_ComboActionGraph::GetCurrentGraphEditor() const
|
||||
{
|
||||
return this->ViewportWidget;
|
||||
}
|
||||
|
||||
FGraphPanelSelectionSet FAssetEditor_ComboActionGraph::GetSelectedNodes() const
|
||||
{
|
||||
FGraphPanelSelectionSet CurrentSelection;
|
||||
TSharedPtr<SGraphEditor> FocusedGraphEd = this->GetCurrentGraphEditor();
|
||||
if (FocusedGraphEd.IsValid())
|
||||
{
|
||||
CurrentSelection = FocusedGraphEd->GetSelectedNodes();
|
||||
}
|
||||
|
||||
return CurrentSelection;
|
||||
}
|
||||
|
||||
void FAssetEditor_ComboActionGraph::RebuildComboActionGraph()
|
||||
{
|
||||
if (this->EditingGraph == nullptr)
|
||||
{
|
||||
UE_LOG(LogAssetEditorComboActionGraph, Warning, TEXT("[RebuildComboActionGraph] EditingGraph is nullptr"));
|
||||
return;
|
||||
}
|
||||
|
||||
UEdComboActionGraph *EdGraph = Cast<UEdComboActionGraph>(this->EditingGraph->EdGraph);
|
||||
check(EdGraph != nullptr);
|
||||
|
||||
EdGraph->RebuildComboActionGraph();
|
||||
}
|
||||
|
||||
void FAssetEditor_ComboActionGraph::SelectAllNodes()
|
||||
{
|
||||
TSharedPtr<SGraphEditor> CurrentGraphEditor = this->GetCurrentGraphEditor();
|
||||
if (CurrentGraphEditor.IsValid())
|
||||
{
|
||||
CurrentGraphEditor->SelectAllNodes();
|
||||
}
|
||||
}
|
||||
|
||||
void FAssetEditor_ComboActionGraph::DeleteSelectedNodes()
|
||||
{
|
||||
TSharedPtr<SGraphEditor> CurrentGraphEditor = this->GetCurrentGraphEditor();
|
||||
if (!CurrentGraphEditor.IsValid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const FScopedTransaction Transaction(FGenericCommands::Get().Delete->GetDescription());
|
||||
|
||||
CurrentGraphEditor->GetCurrentGraph()->Modify();
|
||||
|
||||
const FGraphPanelSelectionSet SelectedNodes = CurrentGraphEditor->GetSelectedNodes();
|
||||
CurrentGraphEditor->ClearSelectionSet();
|
||||
|
||||
for (FGraphPanelSelectionSet::TConstIterator NodeIt(SelectedNodes); NodeIt; ++NodeIt)
|
||||
{
|
||||
UEdGraphNode* EdNode = Cast<UEdGraphNode>(*NodeIt);
|
||||
if (EdNode == nullptr || !EdNode->CanUserDeleteNode())
|
||||
continue;;
|
||||
|
||||
if (UEdComboActionGraphNode *EdNode_Node = Cast<UEdComboActionGraphNode>(EdNode))
|
||||
{
|
||||
EdNode_Node->Modify();
|
||||
|
||||
const UEdGraphSchema *Schema = EdNode_Node->GetSchema();
|
||||
if (Schema != nullptr)
|
||||
{
|
||||
Schema->BreakNodeLinks(*EdNode_Node);
|
||||
}
|
||||
|
||||
EdNode_Node->DestroyNode();
|
||||
}
|
||||
else
|
||||
{
|
||||
EdNode->Modify();
|
||||
EdNode->DestroyNode();
|
||||
}
|
||||
}
|
||||
|
||||
// Update UI
|
||||
CurrentGraphEditor->NotifyGraphChanged();
|
||||
|
||||
UEdGraph *EdGraph = CurrentGraphEditor->GetCurrentGraph();
|
||||
UObject *GraphOwner = EdGraph->GetOuter();
|
||||
if (GraphOwner)
|
||||
{
|
||||
GraphOwner->PostEditChange();
|
||||
GraphOwner->MarkPackageDirty();
|
||||
}
|
||||
|
||||
this->RebuildComboActionGraph();
|
||||
}
|
||||
|
||||
bool FAssetEditor_ComboActionGraph::CanDeleteNodes() const
|
||||
{
|
||||
// If any of the nodes can be deleted then we should allow deleting
|
||||
const FGraphPanelSelectionSet SelectedNodes = this->GetSelectedNodes();
|
||||
for (FGraphPanelSelectionSet::TConstIterator SelectedIter(SelectedNodes); SelectedIter; ++SelectedIter)
|
||||
{
|
||||
UEdGraphNode* Node = Cast<UEdGraphNode>(*SelectedIter);
|
||||
if (Node != nullptr && Node->CanUserDeleteNode())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void FAssetEditor_ComboActionGraph::DeleteSelectedDuplicatableNodes()
|
||||
{
|
||||
TSharedPtr<SGraphEditor> CurrentGraphEditor = this->GetCurrentGraphEditor();
|
||||
if (!CurrentGraphEditor.IsValid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const FGraphPanelSelectionSet OldSelectedNodes = CurrentGraphEditor->GetSelectedNodes();
|
||||
CurrentGraphEditor->ClearSelectionSet();
|
||||
|
||||
for (FGraphPanelSelectionSet::TConstIterator SelectedIter(OldSelectedNodes); SelectedIter; ++SelectedIter)
|
||||
{
|
||||
UEdGraphNode *Node = Cast<UEdGraphNode>(*SelectedIter);
|
||||
if (Node && Node->CanDuplicateNode())
|
||||
{
|
||||
CurrentGraphEditor->SetNodeSelection(Node, true);
|
||||
}
|
||||
}
|
||||
|
||||
// Delete the duplicatable nodes
|
||||
this->DeleteSelectedNodes();
|
||||
|
||||
CurrentGraphEditor->ClearSelectionSet();
|
||||
|
||||
for (FGraphPanelSelectionSet::TConstIterator SelectedIter(OldSelectedNodes); SelectedIter; ++SelectedIter)
|
||||
{
|
||||
if (UEdGraphNode* Node = Cast<UEdGraphNode>(*SelectedIter))
|
||||
{
|
||||
CurrentGraphEditor->SetNodeSelection(Node, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FAssetEditor_ComboActionGraph::CutSelectedNodes()
|
||||
{
|
||||
this->CopySelectedNodes();
|
||||
this->DeleteSelectedDuplicatableNodes();
|
||||
}
|
||||
|
||||
void FAssetEditor_ComboActionGraph::CopySelectedNodes()
|
||||
{
|
||||
// Export the selected nodes and place the text on the clipboard
|
||||
FGraphPanelSelectionSet SelectedNodes = this->GetSelectedNodes();
|
||||
|
||||
FString ExportedText;
|
||||
|
||||
for (FGraphPanelSelectionSet::TIterator SelectedIter(SelectedNodes); SelectedIter; ++SelectedIter)
|
||||
{
|
||||
UEdGraphNode *Node = Cast<UEdGraphNode>(*SelectedIter);
|
||||
if (Node == nullptr)
|
||||
{
|
||||
SelectedIter.RemoveCurrent();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (UEdComboActionGraphEdge *EdNode_Edge = Cast<UEdComboActionGraphEdge>(*SelectedIter))
|
||||
{
|
||||
UEdComboActionGraphNode *StartNode = EdNode_Edge->GetStartNode();
|
||||
UEdComboActionGraphNode *EndNode = EdNode_Edge->GetEndNode();
|
||||
|
||||
if (!SelectedNodes.Contains(StartNode) || !SelectedNodes.Contains(EndNode))
|
||||
{
|
||||
SelectedIter.RemoveCurrent();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
Node->PrepareForCopying();
|
||||
}
|
||||
|
||||
FEdGraphUtilities::ExportNodesToText(SelectedNodes, ExportedText);
|
||||
FPlatformApplicationMisc::ClipboardCopy(*ExportedText);
|
||||
}
|
||||
|
||||
bool FAssetEditor_ComboActionGraph::CanCopyNodes() const
|
||||
{
|
||||
// If any of the nodes can be duplicated then we should allow copying
|
||||
const FGraphPanelSelectionSet SelectedNodes = this->GetSelectedNodes();
|
||||
for (FGraphPanelSelectionSet::TConstIterator SelectedIter(SelectedNodes); SelectedIter; ++SelectedIter)
|
||||
{
|
||||
UEdGraphNode *Node = Cast<UEdGraphNode>(*SelectedIter);
|
||||
if (Node && Node->CanDuplicateNode() == false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void FAssetEditor_ComboActionGraph::PasteNodes()
|
||||
{
|
||||
TSharedPtr<SGraphEditor> CurrentGraphEditor = this->GetCurrentGraphEditor();
|
||||
if (CurrentGraphEditor.IsValid())
|
||||
{
|
||||
this->PasteNodesHere(CurrentGraphEditor->GetPasteLocation());
|
||||
}
|
||||
}
|
||||
|
||||
void FAssetEditor_ComboActionGraph::PasteNodesHere(const FVector2D &Location)
|
||||
{
|
||||
// Find the graph editor with focus
|
||||
TSharedPtr<SGraphEditor> CurrentGraphEditor = this->GetCurrentGraphEditor();
|
||||
if (!CurrentGraphEditor.IsValid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
// Select the newly pasted stuff
|
||||
UEdGraph *EdGraph = CurrentGraphEditor->GetCurrentGraph();
|
||||
|
||||
{
|
||||
const FScopedTransaction Transaction(FGenericCommands::Get().Paste->GetDescription());
|
||||
EdGraph->Modify();
|
||||
|
||||
// Clear the selection set (newly pasted stuff will be selected)
|
||||
CurrentGraphEditor->ClearSelectionSet();
|
||||
|
||||
// Grab the text to paste from the clipboard.
|
||||
FString TextToImport;
|
||||
FPlatformApplicationMisc::ClipboardPaste(TextToImport);
|
||||
|
||||
// Import the nodes
|
||||
TSet<UEdGraphNode*> PastedNodes;
|
||||
FEdGraphUtilities::ImportNodesFromText(EdGraph, TextToImport, PastedNodes);
|
||||
|
||||
//Average position of nodes so we can move them while still maintaining relative distances to each other
|
||||
FVector2D AvgNodePosition(0.0f, 0.0f);
|
||||
|
||||
for (TSet<UEdGraphNode*>::TIterator It(PastedNodes); It; ++It)
|
||||
{
|
||||
UEdGraphNode* Node = *It;
|
||||
AvgNodePosition.X += Node->NodePosX;
|
||||
AvgNodePosition.Y += Node->NodePosY;
|
||||
}
|
||||
|
||||
float InvNumNodes = 1.0f / float(PastedNodes.Num());
|
||||
AvgNodePosition.X *= InvNumNodes;
|
||||
AvgNodePosition.Y *= InvNumNodes;
|
||||
|
||||
// 0 is always Start Node!
|
||||
int32 SharedIndex = EditingGraph->GetAllNodes().Num();
|
||||
|
||||
for (TSet<UEdGraphNode*>::TIterator It(PastedNodes); It; ++It)
|
||||
{
|
||||
UEdGraphNode* Node = *It;
|
||||
CurrentGraphEditor->SetNodeSelection(Node, true);
|
||||
|
||||
Node->NodePosX = (Node->NodePosX - AvgNodePosition.X) + Location.X;
|
||||
Node->NodePosY = (Node->NodePosY - AvgNodePosition.Y) + Location.Y;
|
||||
|
||||
Node->SnapToGrid(16);
|
||||
|
||||
// Give new node a different Guid from the old one
|
||||
Node->CreateNewGuid();
|
||||
|
||||
if (UEdComboActionGraphNode *MounteaNode = Cast<UEdComboActionGraphNode>(Node))
|
||||
{
|
||||
if (MounteaNode->ComboActionGraphNode)
|
||||
{
|
||||
MounteaNode->ComboActionGraphNode->OnPasted();
|
||||
//MounteaNode->SetDialogueNodeIndex(SharedIndex);
|
||||
}
|
||||
|
||||
SharedIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update UI
|
||||
CurrentGraphEditor->NotifyGraphChanged();
|
||||
|
||||
UObject *GraphOwner = EdGraph->GetOuter();
|
||||
if (GraphOwner)
|
||||
{
|
||||
GraphOwner->PostEditChange();
|
||||
GraphOwner->MarkPackageDirty();
|
||||
}
|
||||
|
||||
this->RebuildComboActionGraph();
|
||||
}
|
||||
|
||||
bool FAssetEditor_ComboActionGraph::CanPasteNodes() const
|
||||
{
|
||||
const FGraphPanelSelectionSet SelectedNodes = this->GetSelectedNodes();
|
||||
for (FGraphPanelSelectionSet::TConstIterator SelectedIter(SelectedNodes); SelectedIter; ++SelectedIter)
|
||||
{
|
||||
const UEdComboActionGraphNode *Node = Cast<UEdComboActionGraphNode>(*SelectedIter);
|
||||
if (Node && Node->CanUserPasteNodes() == false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
TSharedPtr<SGraphEditor> CurrentGraphEditor = this->GetCurrentGraphEditor();
|
||||
if (!CurrentGraphEditor.IsValid())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
FString ClipboardContent;
|
||||
FPlatformApplicationMisc::ClipboardPaste(ClipboardContent);
|
||||
|
||||
return FEdGraphUtilities::CanImportNodesFromText(CurrentGraphEditor->GetCurrentGraph(), ClipboardContent);
|
||||
}
|
||||
|
||||
void FAssetEditor_ComboActionGraph::AutoArrange()
|
||||
{
|
||||
// For now, auto-arrange is broken. Just in case it can be activated by accident,
|
||||
// show a popup saying as much if an auto-arrange is attempted.
|
||||
TArray<FText> ValidationMessages;
|
||||
ValidationMessages.Add(LOCTEXT("AssetEditor_ComboActionGraph_AutoArrangeDisabled", "Auto-arrange is currently broken."));
|
||||
ComboInputPopup_GraphValidation::Open(ValidationMessages);
|
||||
|
||||
//UEdComboActionGraph *EdGraph = Cast<UEdComboActionGraph>(this->EditingGraph->EdGraph);
|
||||
//check(EdGraph != nullptr);
|
||||
|
||||
//const FScopedTransaction Transaction(LOCTEXT("ComboActionGraphEditorAutoArrange", "Combo Action Graph Editor: Auto Arrange all Nodes"));
|
||||
|
||||
//EdGraph->Modify(true);
|
||||
|
||||
//UComboActionGraphLayoutStrategy *LayoutStrategy = nullptr;
|
||||
//switch (this->ComboActionGraphEditorSettings->GetAutoLayoutStrategy())
|
||||
//{
|
||||
// case EComboActionAutoLayoutStrategyType::Tree:
|
||||
// LayoutStrategy = NewObject<UComboActionGraphLayoutStrategy>(EdGraph, UComboActionTreeSolveLayoutStrategy::StaticClass());
|
||||
// break;
|
||||
// case EComboActionAutoLayoutStrategyType::ForceDirected:
|
||||
// LayoutStrategy = NewObject<UComboActionGraphLayoutStrategy>(EdGraph, UComboActionForceDirectedSolveLayoutStrategy::StaticClass());
|
||||
// break;
|
||||
// default:
|
||||
// break;
|
||||
//}
|
||||
|
||||
//if (LayoutStrategy != nullptr)
|
||||
//{
|
||||
// LayoutStrategy->Layout(EdGraph);
|
||||
// LayoutStrategy->ConditionalBeginDestroy();
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// UE_LOG(LogAssetEditorComboActionGraph, Error, TEXT("[AutoArrange] LayoutStrategy is null."));
|
||||
//}
|
||||
}
|
||||
|
||||
bool FAssetEditor_ComboActionGraph::CanAutoArrange() const
|
||||
{
|
||||
return this->EditingGraph != nullptr && Cast<UEdComboActionGraph>(this->EditingGraph->EdGraph) != nullptr;
|
||||
}
|
||||
|
||||
void FAssetEditor_ComboActionGraph::ValidateGraph()
|
||||
{
|
||||
if (this->ValidationWindow.IsValid())
|
||||
{
|
||||
this->ValidationWindow->RequestDestroyWindow();
|
||||
}
|
||||
|
||||
UEdComboActionGraph *EdGraph = Cast<UEdComboActionGraph>(this->EditingGraph->EdGraph);
|
||||
check(EdGraph != nullptr);
|
||||
|
||||
const FScopedTransaction Transaction(LOCTEXT("ComboActionGraphEditorValidateGraph", "Combo Action Graph Editor: Validate Graph."));
|
||||
|
||||
UComboActionGraph *ComboActionGraph = EdGraph->GetComboActionGraph();
|
||||
check(ComboActionGraph != nullptr);
|
||||
|
||||
this->RebuildComboActionGraph();
|
||||
|
||||
TArray<FText> ValidationMessages;
|
||||
if (ComboActionGraph->ValidateGraph(ValidationMessages, true) == false)
|
||||
{
|
||||
this->ValidationWindow = ComboInputPopup_GraphValidation::Open(ValidationMessages);
|
||||
}
|
||||
else
|
||||
{
|
||||
ValidationMessages.Empty();
|
||||
this->ValidationWindow = ComboInputPopup_GraphValidation::Open(ValidationMessages);
|
||||
}
|
||||
}
|
||||
|
||||
void FAssetEditor_ComboActionGraph::OnRenameNode()
|
||||
{
|
||||
TSharedPtr<SGraphEditor> CurrentGraphEditor = this->GetCurrentGraphEditor();
|
||||
if (CurrentGraphEditor.IsValid())
|
||||
{
|
||||
const FGraphPanelSelectionSet SelectedNodes = GetSelectedNodes();
|
||||
for (FGraphPanelSelectionSet::TConstIterator NodeIt(SelectedNodes); NodeIt; ++NodeIt)
|
||||
{
|
||||
UEdGraphNode *SelectedNode = Cast<UEdGraphNode>(*NodeIt);
|
||||
if (SelectedNode != nullptr && SelectedNode->bCanRenameNode)
|
||||
{
|
||||
CurrentGraphEditor->IsNodeTitleVisible(SelectedNode, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool FAssetEditor_ComboActionGraph::CanRenameNodes() const
|
||||
{
|
||||
check(this->GetSettings() != nullptr);
|
||||
return this->GetSettings()->AllowRenameNodes() == true && this->GetSelectedNodes().Num() == 1;
|
||||
}
|
||||
|
||||
void FAssetEditor_ComboActionGraph::OnSelectedNodesChanged(const TSet<UObject*> &NewSelection)
|
||||
{
|
||||
TArray<UObject*> Selection;
|
||||
|
||||
for (UObject* SelectionEntry : NewSelection)
|
||||
{
|
||||
Selection.Add(SelectionEntry);
|
||||
}
|
||||
|
||||
if (Selection.Num() == 1)
|
||||
{
|
||||
// When just one node is selected, add it to PropertyWidget
|
||||
this->PropertyWidget->SetObjects(Selection);
|
||||
this->PropertyWidget->ShowAllAdvancedProperties();
|
||||
|
||||
//UComboActionEditorBFC::TriggerPreviewRefresh(Selection);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->PropertyWidget->SetObject(this->EditingGraph);
|
||||
}
|
||||
|
||||
this->RebuildComboActionGraph();
|
||||
}
|
||||
|
||||
void FAssetEditor_ComboActionGraph::OnNodeDoubleClicked(UEdGraphNode *Node)
|
||||
{
|
||||
this->GraphEditorCommands->TryExecuteAction(FGenericCommands::Get().Rename.ToSharedRef());
|
||||
}
|
||||
|
||||
void FAssetEditor_ComboActionGraph::OnFinishedChangingProperties(const FPropertyChangedEvent& PropertyChangedEvent)
|
||||
{
|
||||
if (this->EditingGraph == nullptr)
|
||||
return;
|
||||
|
||||
this->EditingGraph->EdGraph->GetSchema()->ForceVisualizationCacheClear();
|
||||
|
||||
this->RebuildComboActionGraph();
|
||||
}
|
||||
|
||||
TSharedRef<SDockTab> FAssetEditor_ComboActionGraph::SpawnTab_Viewport(const FSpawnTabArgs &Args)
|
||||
{
|
||||
check(Args.GetTabId() == FAssetEditorTabs_ComboActionGraph::ViewportID);
|
||||
|
||||
TSharedRef<SDockTab> SpawnedTab = SNew(SDockTab)
|
||||
.Label(LOCTEXT("ViewportTab_Title", "Viewport"));
|
||||
|
||||
if (this->ViewportWidget.IsValid())
|
||||
{
|
||||
SpawnedTab->SetContent(this->ViewportWidget.ToSharedRef());
|
||||
}
|
||||
|
||||
return SpawnedTab;
|
||||
}
|
||||
|
||||
TSharedRef<SDockTab> FAssetEditor_ComboActionGraph::SpawnTab_Details(const FSpawnTabArgs& Args)
|
||||
{
|
||||
check(Args.GetTabId() == FAssetEditorTabs_ComboActionGraph::ComboActionGraphPropertyID);
|
||||
|
||||
auto DockTab = SNew(SDockTab)
|
||||
.Label(LOCTEXT("Details_Title", "Property"))
|
||||
[
|
||||
this->PropertyWidget.ToSharedRef()
|
||||
];
|
||||
|
||||
DockTab->SetTabIcon(FAppStyle::GetBrush("LevelEditor.Tabs.Details"));
|
||||
return DockTab;
|
||||
}
|
||||
|
||||
TSharedRef<SDockTab> FAssetEditor_ComboActionGraph::SpawnTab_Search(const FSpawnTabArgs &Args)
|
||||
{
|
||||
check(Args.GetTabId() == FAssetEditorTabs_ComboActionGraph::SearchToolbarID);
|
||||
|
||||
auto DockTab = SNew(SDockTab)
|
||||
.Label(LOCTEXT("Search_Title", "Search"))
|
||||
[
|
||||
this->FindResultsView.ToSharedRef()
|
||||
];
|
||||
|
||||
DockTab->SetTabIcon(FAppStyle::GetBrush("Kismet.Tabs.FindResults"));
|
||||
return DockTab;
|
||||
}
|
||||
|
||||
#undef LOCTEXT_NAMESPACE
|
||||
|
||||
@ -1,167 +0,0 @@
|
||||
// ©2023 Batty Bovine Productions, LLC. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
|
||||
#include "Toolkits/AssetEditorToolkit.h"
|
||||
|
||||
DECLARE_LOG_CATEGORY_EXTERN(LogAssetEditorComboActionGraph, Log, All);
|
||||
|
||||
|
||||
class COMBOINPUTEDITOR_API FAssetEditor_ComboActionGraph : public FAssetEditorToolkit, public FNotifyHook, public FGCObject
|
||||
{
|
||||
|
||||
public:
|
||||
FAssetEditor_ComboActionGraph();
|
||||
virtual ~FAssetEditor_ComboActionGraph() override;
|
||||
|
||||
void OnPackageSaved(const FString &String, UPackage *Package, FObjectPostSaveContext ObjectPostSaveContext);
|
||||
|
||||
void InitComboActionGraphAssetEditor(const EToolkitMode::Type Mode, const TSharedPtr<IToolkitHost> &InitToolkitHost, class UComboActionGraph *Graph);
|
||||
class UComboActionGraphEditorSettings *GetSettings() const;
|
||||
|
||||
#pragma region ToolkitInterface
|
||||
|
||||
public:
|
||||
// IToolkit interface
|
||||
virtual void RegisterTabSpawners(const TSharedRef<FTabManager> &InTabManager) override;
|
||||
virtual void UnregisterTabSpawners(const TSharedRef<FTabManager> &InTabManager) override;
|
||||
|
||||
virtual bool CloseWindow(EAssetEditorCloseReason InCloseReason) override;
|
||||
// End of IToolkit interface
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region AssetEditorToolkit
|
||||
|
||||
virtual FName GetToolkitFName() const override;
|
||||
virtual FText GetBaseToolkitName() const override;
|
||||
virtual FText GetToolkitName() const override;
|
||||
virtual FText GetToolkitToolTipText() const override;
|
||||
virtual FLinearColor GetWorldCentricTabColorScale() const override;
|
||||
virtual FString GetWorldCentricTabPrefix() const override;
|
||||
virtual FString GetDocumentationLink() const override;
|
||||
virtual void SaveAsset_Execute() override;
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Toolbar
|
||||
|
||||
void UpdateToolbar();
|
||||
TSharedPtr<class FAssetEditorToolbarComboActionGraph> GetToolbarBuilder() { return this->ToolbarBuilder; }
|
||||
void RegisterToolbarTab(const TSharedRef<class FTabManager> &InTabManager);
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region SerializableObjectInterface
|
||||
|
||||
virtual void AddReferencedObjects(FReferenceCollector &Collector) override;
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region FGCObject
|
||||
|
||||
virtual FString GetReferencerName() const override;
|
||||
|
||||
#pragma endregion
|
||||
|
||||
// Gets/Sets the dialogue being edited
|
||||
class UComboActionGraph *GetEditingGraphSafe()
|
||||
{
|
||||
check(EditingGraph);
|
||||
return EditingGraph;
|
||||
}
|
||||
void SetDialogueBeingEdited(class UComboActionGraph *NewDialogue);
|
||||
|
||||
virtual void JumpToNode(const class UEdGraphNode *JumpToMe, bool bRequestRename = false, bool bSelectNode = true)
|
||||
{
|
||||
if (this->ViewportWidget.IsValid())
|
||||
{
|
||||
this->ViewportWidget->JumpToNode(JumpToMe, bRequestRename, bSelectNode);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void CreateInternalWidgets();
|
||||
TSharedRef<SGraphEditor> CreateViewportWidget();
|
||||
|
||||
void BindCommands();
|
||||
void CreateEdGraph();
|
||||
void CreateCommandList();
|
||||
|
||||
TSharedPtr<SGraphEditor> GetCurrentGraphEditor() const;
|
||||
|
||||
FGraphPanelSelectionSet GetSelectedNodes() const;
|
||||
|
||||
void RebuildComboActionGraph();
|
||||
|
||||
#pragma region GraphEditorCommands
|
||||
|
||||
void SelectAllNodes();
|
||||
bool CanSelectAllNodes() const { return true; }
|
||||
void DeleteSelectedNodes();
|
||||
bool CanDeleteNodes() const;
|
||||
void DeleteSelectedDuplicatableNodes();
|
||||
void CutSelectedNodes();
|
||||
bool CanCutNodes() const { return this->CanCopyNodes() && this->CanDeleteNodes(); }
|
||||
void CopySelectedNodes();
|
||||
bool CanCopyNodes() const;
|
||||
void PasteNodes();
|
||||
void PasteNodesHere(const FVector2D &Location);
|
||||
bool CanPasteNodes() const;
|
||||
void DuplicateNodes() { this->CopySelectedNodes(); this->PasteNodes(); }
|
||||
bool CanDuplicateNodes() { return this->CanCopyNodes(); }
|
||||
|
||||
void AutoArrange();
|
||||
bool CanAutoArrange() const;
|
||||
|
||||
void ValidateGraph();
|
||||
bool CanValidateGraph() const { return true; }
|
||||
|
||||
void OnRenameNode();
|
||||
bool CanRenameNodes() const;
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region GraphEditorEvents
|
||||
|
||||
void OnSelectedNodesChanged(const TSet<class UObject*> &NewSelection);
|
||||
|
||||
void OnNodeDoubleClicked(UEdGraphNode *Node);
|
||||
|
||||
void OnFinishedChangingProperties(const FPropertyChangedEvent &PropertyChangedEvent);
|
||||
|
||||
void OnPackageSaved(const FString &PackageFileName, UObject *Outer);
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Variables
|
||||
|
||||
private:
|
||||
|
||||
TSharedRef<SDockTab> SpawnTab_Viewport(const FSpawnTabArgs &Args);
|
||||
TSharedRef<SDockTab> SpawnTab_Details(const FSpawnTabArgs &Args);
|
||||
TSharedRef<SDockTab> SpawnTab_Search(const FSpawnTabArgs &Args);
|
||||
|
||||
class UComboActionGraphEditorSettings *ComboActionGraphEditorSettings;
|
||||
|
||||
TObjectPtr<class UComboActionGraph> EditingGraph;
|
||||
|
||||
//Toolbar
|
||||
TSharedPtr<FAssetEditorToolbarComboActionGraph> ToolbarBuilder;
|
||||
|
||||
/** Handle to the registered OnPackageSave delegate */
|
||||
FDelegateHandle OnPackageSavedDelegateHandle;
|
||||
|
||||
TSharedPtr<SGraphEditor> ViewportWidget;
|
||||
TSharedPtr<class IDetailsView> PropertyWidget;
|
||||
TSharedPtr<class SComboActionSearch> FindResultsView;
|
||||
|
||||
/** The command list for this editor */
|
||||
TSharedPtr<FUICommandList> GraphEditorCommands;
|
||||
|
||||
TSharedPtr<SWindow> ValidationWindow;
|
||||
|
||||
#pragma endregion
|
||||
};
|
||||
@ -1,210 +0,0 @@
|
||||
// ©2023 Batty Bovine Productions, LLC. All Rights Reserved.
|
||||
|
||||
#include "Ed/EdComboActionGraph.h"
|
||||
|
||||
#include "ComboActionGraph.h"
|
||||
#include "Ed/AssetEditor_ComboActionGraph.h"
|
||||
#include "Ed/EdComboActionGraphEdge.h"
|
||||
#include "Ed/EdComboActionGraphNode.h"
|
||||
#include "Nodes/ComboActionGraphEdge.h"
|
||||
#include "Nodes/ComboActionGraphNode.h"
|
||||
//#include "Helpers/MounteaDialogueGraphEditorHelpers.h"
|
||||
//#include "Helpers/MounteaDialogueGraphEditorUtilities.h"
|
||||
//#include "Helpers/MounteaDialogueSystemEditorBFC.h"
|
||||
|
||||
DEFINE_LOG_CATEGORY(LogEdComboActionGraph);
|
||||
|
||||
|
||||
void UEdComboActionGraph::RebuildComboActionGraph()
|
||||
{
|
||||
UE_LOG(LogEdComboActionGraph, Warning, TEXT("UEdComboActionGraph::RebuildComboActionGraph has been called"));
|
||||
|
||||
UComboActionGraph *Graph = GetComboActionGraph();
|
||||
|
||||
this->Clear();
|
||||
|
||||
for (const TObjectPtr<UEdGraphNode> &Node : this->Nodes)
|
||||
{
|
||||
if (UEdComboActionGraphNode *EdNode = Cast<UEdComboActionGraphNode>(Node))
|
||||
{
|
||||
if (EdNode->ComboActionGraphNode == nullptr)
|
||||
continue;
|
||||
|
||||
UComboActionGraphNode *ComboActionGraphNode = EdNode->ComboActionGraphNode;
|
||||
|
||||
this->NodeMap.Add(ComboActionGraphNode, EdNode);
|
||||
|
||||
Graph->AllNodes.Add(ComboActionGraphNode);
|
||||
|
||||
//EdNode->SetDialogueNodeIndex( Graph->AllNodes.Find(EdNode->ComboActionGraphNode) );
|
||||
|
||||
for (int PinIdx = 0; PinIdx < EdNode->Pins.Num(); ++PinIdx)
|
||||
{
|
||||
UEdGraphPin* Pin = EdNode->Pins[PinIdx];
|
||||
|
||||
if (Pin->Direction != EEdGraphPinDirection::EGPD_Output)
|
||||
continue;
|
||||
|
||||
for (int LinkToIdx = 0; LinkToIdx < Pin->LinkedTo.Num(); ++LinkToIdx)
|
||||
{
|
||||
UComboActionGraphNode *ChildNode = nullptr;
|
||||
if (UEdComboActionGraphNode *EdNode_Child = Cast<UEdComboActionGraphNode>(Pin->LinkedTo[LinkToIdx]->GetOwningNode()))
|
||||
{
|
||||
ChildNode = EdNode_Child->ComboActionGraphNode;
|
||||
}
|
||||
else if (UEdComboActionGraphEdge *EdNode_Edge = Cast<UEdComboActionGraphEdge>(Pin->LinkedTo[LinkToIdx]->GetOwningNode()))
|
||||
{
|
||||
UEdComboActionGraphNode *Child = EdNode_Edge->GetEndNode();;
|
||||
if (Child != nullptr)
|
||||
{
|
||||
ChildNode = Child->ComboActionGraphNode;
|
||||
}
|
||||
}
|
||||
|
||||
if (ChildNode != nullptr)
|
||||
{
|
||||
ComboActionGraphNode->ChildNodes.Add(ChildNode);
|
||||
|
||||
ChildNode->ParentNodes.Add(ComboActionGraphNode);
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(LogEdComboActionGraph, Error, TEXT("[RebuildComboActionGraph] Can't find child node"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (UEdComboActionGraphEdge *EdgeNode = Cast<UEdComboActionGraphEdge>(Node))
|
||||
{
|
||||
UEdComboActionGraphNode *StartNode = EdgeNode->GetStartNode();
|
||||
UEdComboActionGraphNode *EndNode = EdgeNode->GetEndNode();
|
||||
UComboActionGraphEdge *Edge = EdgeNode->ComboActionGraphEdge;
|
||||
|
||||
if (StartNode == nullptr || EndNode == nullptr || Edge == nullptr)
|
||||
{
|
||||
UE_LOG(LogEdComboActionGraph, Error, TEXT("[RebuildComboActionGraph] Add edge failed."));
|
||||
continue;
|
||||
}
|
||||
|
||||
this->EdgeMap.Add(Edge, EdgeNode);
|
||||
|
||||
Edge->SetGraph(Graph);
|
||||
Edge->Rename(nullptr, Graph, REN_DontCreateRedirectors | REN_DoNotDirty);
|
||||
StartNode->ComboActionGraphNode->Edges.Add(EndNode->ComboActionGraphNode, Edge);
|
||||
Edge->SetStartNode(StartNode->ComboActionGraphNode);
|
||||
Edge->SetEndNode(EndNode->ComboActionGraphNode);
|
||||
}
|
||||
}
|
||||
|
||||
for (UComboActionGraphNode *Node : Graph->AllNodes)
|
||||
{
|
||||
if (Node->ParentNodes.Num() == 0)
|
||||
{
|
||||
Graph->RootNodes.Add(Node);
|
||||
|
||||
SortNodes(Node);
|
||||
}
|
||||
|
||||
Node->Graph = Graph;
|
||||
Node->Rename(nullptr, Graph, REN_DontCreateRedirectors | REN_DoNotDirty);
|
||||
}
|
||||
|
||||
Graph->RootNodes.Sort([&](const UComboActionGraphNode &L, const UComboActionGraphNode &R)
|
||||
{
|
||||
UEdComboActionGraphNode *EdNode_LNode = this->NodeMap[&L];
|
||||
UEdComboActionGraphNode *EdNode_RNode = this->NodeMap[&R];
|
||||
return EdNode_LNode->NodePosX < EdNode_RNode->NodePosX;
|
||||
});
|
||||
}
|
||||
|
||||
UComboActionGraph *UEdComboActionGraph::GetComboActionGraph() const
|
||||
{
|
||||
return CastChecked<UComboActionGraph>(GetOuter());
|
||||
}
|
||||
|
||||
bool UEdComboActionGraph::Modify(bool bAlwaysMarkDirty)
|
||||
{
|
||||
bool Rtn = Super::Modify(bAlwaysMarkDirty);
|
||||
|
||||
this->GetComboActionGraph()->Modify();
|
||||
|
||||
for (TObjectPtr<UEdGraphNode> &Node : this->Nodes)
|
||||
{
|
||||
Node->Modify();
|
||||
}
|
||||
|
||||
return Rtn;
|
||||
}
|
||||
|
||||
void UEdComboActionGraph::PostEditUndo()
|
||||
{
|
||||
this->NotifyGraphChanged();
|
||||
|
||||
Super::PostEditUndo();
|
||||
}
|
||||
|
||||
void UEdComboActionGraph::SetDialogueEditorPtr(TWeakPtr<FAssetEditor_ComboActionGraph> NewPtr)
|
||||
{
|
||||
this->ComboActionEditorPtr = NewPtr;
|
||||
}
|
||||
|
||||
bool UEdComboActionGraph::JumpToNode(const UComboActionGraphNode *Node)
|
||||
{
|
||||
//return FComboActionGraphEditorUtilities::OpenEditorAndJumpToGraphNode(this->ComboActionEditorPtr, *NodeMap.Find(Node));
|
||||
return false;
|
||||
}
|
||||
|
||||
void UEdComboActionGraph::Clear()
|
||||
{
|
||||
UComboActionGraph *Graph = this->GetComboActionGraph();
|
||||
|
||||
Graph->ClearGraph();
|
||||
this->NodeMap.Reset();
|
||||
this->EdgeMap.Reset();
|
||||
|
||||
for (int i = 0; i < this->Nodes.Num(); ++i)
|
||||
{
|
||||
if (UEdComboActionGraphNode *EdNode = Cast<UEdComboActionGraphNode>(Nodes[i]))
|
||||
{
|
||||
UComboActionGraphNode *MounteaDialogueGraphNode = EdNode->ComboActionGraphNode;
|
||||
MounteaDialogueGraphNode->ParentNodes.Reset();
|
||||
MounteaDialogueGraphNode->ChildNodes.Reset();
|
||||
MounteaDialogueGraphNode->Edges.Reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UEdComboActionGraph::SortNodes(UComboActionGraphNode *RootNode)
|
||||
{
|
||||
int Level = 0;
|
||||
TArray<UComboActionGraphNode*> CurrLevelNodes = { RootNode };
|
||||
TArray<UComboActionGraphNode*> NextLevelNodes;
|
||||
|
||||
while (CurrLevelNodes.Num() != 0)
|
||||
{
|
||||
int32 LevelWidth = 0;
|
||||
for (int i = 0; i < CurrLevelNodes.Num(); ++i)
|
||||
{
|
||||
UComboActionGraphNode *Node = CurrLevelNodes[i];
|
||||
|
||||
auto Comp = [&](const UComboActionGraphNode &L, const UComboActionGraphNode &R)
|
||||
{
|
||||
UEdComboActionGraphNode *EdNode_LNode = NodeMap[&L];
|
||||
UEdComboActionGraphNode *EdNode_RNode = NodeMap[&R];
|
||||
return EdNode_LNode->NodePosX < EdNode_RNode->NodePosX;
|
||||
};
|
||||
|
||||
Node->ChildNodes.Sort(Comp);
|
||||
Node->ParentNodes.Sort(Comp);
|
||||
|
||||
for (int j = 0; j < Node->ChildNodes.Num(); ++j)
|
||||
{
|
||||
NextLevelNodes.Add(Node->ChildNodes[j]);
|
||||
}
|
||||
}
|
||||
|
||||
CurrLevelNodes = NextLevelNodes;
|
||||
NextLevelNodes.Reset();
|
||||
++Level;
|
||||
}
|
||||
}
|
||||
@ -1,46 +0,0 @@
|
||||
// ©2023 Batty Bovine Productions, LLC. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "EdGraph/EdGraph.h"
|
||||
|
||||
#include "EdComboActionGraph.generated.h"
|
||||
|
||||
DECLARE_LOG_CATEGORY_EXTERN(LogEdComboActionGraph, Log, All);
|
||||
|
||||
|
||||
UCLASS()
|
||||
class COMBOINPUTEDITOR_API UEdComboActionGraph : public UEdGraph
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
virtual void RebuildComboActionGraph();
|
||||
|
||||
UComboActionGraph *GetComboActionGraph() const;
|
||||
|
||||
virtual bool Modify(bool bAlwaysMarkDirty) override;
|
||||
virtual void PostEditUndo() override;
|
||||
|
||||
TWeakPtr<class FAssetEditor_ComboActionGraph> GetComboActionEditorPtr() const { return this->ComboActionEditorPtr; }
|
||||
void SetDialogueEditorPtr(TWeakPtr<class FAssetEditor_ComboActionGraph> NewPtr);
|
||||
void ResetDialogueEditorPtr() { this->ComboActionEditorPtr.Reset(); }
|
||||
|
||||
bool JumpToNode(const class UComboActionGraphNode *Node);
|
||||
|
||||
public:
|
||||
UPROPERTY(Transient)
|
||||
TMap<class UComboActionGraphNode*, class UEdComboActionGraphNode*> NodeMap;
|
||||
|
||||
UPROPERTY(Transient)
|
||||
TMap<class UComboActionGraphEdge*, class UEdComboActionGraphEdge*> EdgeMap;
|
||||
|
||||
protected:
|
||||
void Clear();
|
||||
void SortNodes(UComboActionGraphNode *RootNode);
|
||||
|
||||
private:
|
||||
/** Pointer back to the combo action editor that owns us */
|
||||
TWeakPtr<FAssetEditor_ComboActionGraph> ComboActionEditorPtr;
|
||||
};
|
||||
@ -1,83 +0,0 @@
|
||||
// ©2023 Batty Bovine Productions, LLC. All Rights Reserved.
|
||||
|
||||
#include "EdComboActionGraphEdge.h"
|
||||
|
||||
#include "EdComboActionGraphNode.h"
|
||||
#include "Nodes/ComboActionGraphEdge.h"
|
||||
|
||||
|
||||
void UEdComboActionGraphEdge::SetEdge(UComboActionGraphEdge *Edge)
|
||||
{
|
||||
this->ComboActionGraphEdge = Edge;
|
||||
}
|
||||
|
||||
void UEdComboActionGraphEdge::AllocateDefaultPins()
|
||||
{
|
||||
UEdGraphPin* Inputs = this->CreatePin(EGPD_Input, TEXT("Edge"), FName(), TEXT("In"));
|
||||
Inputs->bHidden = true;
|
||||
UEdGraphPin* Outputs = this->CreatePin(EGPD_Output, TEXT("Edge"), FName(), TEXT("Out"));
|
||||
Outputs->bHidden = true;
|
||||
}
|
||||
|
||||
FText UEdComboActionGraphEdge::GetNodeTitle(ENodeTitleType::Type TitleType) const
|
||||
{
|
||||
return Super::GetNodeTitle(TitleType);
|
||||
}
|
||||
|
||||
void UEdComboActionGraphEdge::PinConnectionListChanged(UEdGraphPin *Pin)
|
||||
{
|
||||
if (Pin->LinkedTo.Num() == 0)
|
||||
{
|
||||
// Commit suicide; transitions must always have an input and output connection
|
||||
Modify();
|
||||
|
||||
// Our parent graph will have our graph in SubGraphs so needs to be modified to record that.
|
||||
if (UEdGraph *ParentGraph = GetGraph())
|
||||
{
|
||||
ParentGraph->Modify();
|
||||
}
|
||||
|
||||
DestroyNode();
|
||||
}
|
||||
}
|
||||
|
||||
void UEdComboActionGraphEdge::PrepareForCopying()
|
||||
{
|
||||
this->ComboActionGraphEdge->Rename(nullptr, this, REN_DontCreateRedirectors | REN_DoNotDirty);
|
||||
}
|
||||
|
||||
void UEdComboActionGraphEdge::CreateConnections(UEdComboActionGraphNode *Start, UEdComboActionGraphNode *End)
|
||||
{
|
||||
Pins[0]->Modify();
|
||||
Pins[0]->LinkedTo.Empty();
|
||||
|
||||
Start->GetOutputPin()->Modify();
|
||||
Pins[0]->MakeLinkTo(Start->GetOutputPin());
|
||||
|
||||
// This to next
|
||||
Pins[1]->Modify();
|
||||
Pins[1]->LinkedTo.Empty();
|
||||
|
||||
End->GetInputPin()->Modify();
|
||||
Pins[1]->MakeLinkTo(End->GetInputPin());
|
||||
}
|
||||
|
||||
UEdComboActionGraphNode *UEdComboActionGraphEdge::GetStartNode()
|
||||
{
|
||||
if (Pins[0]->LinkedTo.Num() > 0)
|
||||
{
|
||||
return Cast<UEdComboActionGraphNode>(Pins[0]->LinkedTo[0]->GetOwningNode());
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
UEdComboActionGraphNode *UEdComboActionGraphEdge::GetEndNode()
|
||||
{
|
||||
if (Pins[1]->LinkedTo.Num() > 0)
|
||||
{
|
||||
return Cast<UEdComboActionGraphNode>(Pins[1]->LinkedTo[0]->GetOwningNode());
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
@ -1,45 +0,0 @@
|
||||
// ©2023 Batty Bovine Productions, LLC. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "EdGraph/EdGraphNode.h"
|
||||
|
||||
#include "EdComboActionGraphEdge.generated.h"
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
UCLASS(MinimalAPI)
|
||||
class UEdComboActionGraphEdge : public UEdGraphNode
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
UPROPERTY()
|
||||
class UEdGraph *Graph;
|
||||
|
||||
UPROPERTY(VisibleAnywhere, Instanced, Category="Combo Action Graph")
|
||||
class UComboActionGraphEdge *ComboActionGraphEdge;
|
||||
|
||||
public:
|
||||
|
||||
void SetEdge(class UComboActionGraphEdge *Edge);
|
||||
|
||||
virtual void AllocateDefaultPins() override;
|
||||
|
||||
virtual FText GetNodeTitle(ENodeTitleType::Type TitleType) const override;
|
||||
|
||||
virtual void PinConnectionListChanged(UEdGraphPin *Pin) override;
|
||||
|
||||
virtual void PrepareForCopying() override;
|
||||
|
||||
virtual UEdGraphPin *GetInputPin() const { return Pins[0]; }
|
||||
virtual UEdGraphPin *GetOutputPin() const { return Pins[1]; }
|
||||
|
||||
void CreateConnections(class UEdComboActionGraphNode *Start, class UEdComboActionGraphNode* End);
|
||||
|
||||
class UEdComboActionGraphNode *GetStartNode();
|
||||
class UEdComboActionGraphNode *GetEndNode();
|
||||
};
|
||||
@ -1,173 +0,0 @@
|
||||
// ©2023 Batty Bovine Productions, LLC. All Rights Reserved.
|
||||
|
||||
#include "EdComboActionGraphNode.h"
|
||||
|
||||
#include "Ed/EdComboActionGraph.h"
|
||||
#include "Helpers/ComboActionEditorBFC.h"
|
||||
#include "Nodes/ComboActionGraphNode.h"
|
||||
#include "Settings/ComboActionGraphEditorSettings.h"
|
||||
|
||||
#define LOCTEXT_NAMESPACE "UEdComboActionGraphNode"
|
||||
|
||||
DEFINE_LOG_CATEGORY(LogEdComboActionGraphNode);
|
||||
|
||||
|
||||
UEdComboActionGraphNode::UEdComboActionGraphNode()
|
||||
{
|
||||
bCanRenameNode = true;
|
||||
|
||||
bAllowCopy = true;
|
||||
bAllowDelete = true;
|
||||
bAllowDuplicate = true;
|
||||
bAllowPaste = true;
|
||||
}
|
||||
|
||||
void UEdComboActionGraphNode::SetComboActionGraphNode(UComboActionGraphNode *NewNode)
|
||||
{
|
||||
this->ComboActionGraphNode = NewNode;
|
||||
|
||||
if (this->ComboActionGraphNode)
|
||||
{
|
||||
this->bAllowCopy = this->ComboActionGraphNode->bAllowCopy;
|
||||
this->bAllowDelete = this->ComboActionGraphNode->bAllowDelete;
|
||||
this->bAllowDuplicate = this->ComboActionGraphNode->bAllowPaste;
|
||||
this->bAllowPaste = this->ComboActionGraphNode->bAllowPaste;
|
||||
}
|
||||
}
|
||||
|
||||
UEdComboActionGraph *UEdComboActionGraphNode::GetEdComboActionGraph() const
|
||||
{
|
||||
return Cast<UEdComboActionGraph>(this->GetGraph());
|
||||
};
|
||||
|
||||
void UEdComboActionGraphNode::AllocateDefaultPins()
|
||||
{
|
||||
if (this->ComboActionGraphNode == nullptr)
|
||||
{
|
||||
UE_LOG(LogEdComboActionGraphNode, Error, TEXT("[AllocateDefaultPins] Cannot find Owning Graph Node!"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (this->ComboActionGraphNode->bAllowInputNodes)
|
||||
{
|
||||
this->CreatePin(EGPD_Input, "MultipleNodes", FName(), TEXT("In"));
|
||||
}
|
||||
|
||||
if (this->ComboActionGraphNode->bAllowOutputNodes)
|
||||
{
|
||||
this->CreatePin(EGPD_Output, "MultipleNodes", FName(), TEXT("Out"));
|
||||
}
|
||||
}
|
||||
|
||||
FText UEdComboActionGraphNode::GetNodeTitle(ENodeTitleType::Type TitleType) const
|
||||
{
|
||||
return UComboActionEditorBFC::GetNodeTitle(this->ComboActionGraphNode);
|
||||
}
|
||||
|
||||
void UEdComboActionGraphNode::PrepareForCopying()
|
||||
{
|
||||
this->ComboActionGraphNode->Rename(nullptr, this, REN_DontCreateRedirectors | REN_DoNotDirty);
|
||||
}
|
||||
|
||||
void UEdComboActionGraphNode::AutowireNewNode(UEdGraphPin* FromPin)
|
||||
{
|
||||
Super::AutowireNewNode(FromPin);
|
||||
|
||||
if (FromPin != nullptr)
|
||||
{
|
||||
if (GetSchema()->TryCreateConnection(FromPin, GetInputPin()))
|
||||
{
|
||||
FromPin->GetOwningNode()->NodeConnectionListChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UEdGraphPin* UEdComboActionGraphNode::GetInputPin() const
|
||||
{
|
||||
return Pins[0];
|
||||
}
|
||||
|
||||
UEdGraphPin* UEdComboActionGraphNode::GetOutputPin() const
|
||||
{
|
||||
if (Pins.IsValidIndex(1))
|
||||
{
|
||||
return Pins[1];
|
||||
}
|
||||
|
||||
return Pins[0];
|
||||
}
|
||||
|
||||
bool UEdComboActionGraphNode::CanUserDeleteNode() const
|
||||
{
|
||||
if(!Super::CanUserDeleteNode())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this->ComboActionGraphNode)
|
||||
{
|
||||
return this->ComboActionGraphNode->bAllowDelete;
|
||||
}
|
||||
return bAllowDelete;
|
||||
}
|
||||
|
||||
bool UEdComboActionGraphNode::CanDuplicateNode() const
|
||||
{
|
||||
if(!Super::CanUserDeleteNode())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this->ComboActionGraphNode)
|
||||
{
|
||||
return this->ComboActionGraphNode->bAllowCopy;
|
||||
}
|
||||
|
||||
return bAllowCopy;
|
||||
}
|
||||
|
||||
bool UEdComboActionGraphNode::CanUserPasteNodes() const
|
||||
{
|
||||
if (this->ComboActionGraphNode)
|
||||
{
|
||||
return this->ComboActionGraphNode->bAllowPaste;
|
||||
}
|
||||
|
||||
return bAllowPaste;
|
||||
}
|
||||
|
||||
FText UEdComboActionGraphNode::GetTooltipText() const
|
||||
{
|
||||
if (this->ComboActionGraphNode)
|
||||
{
|
||||
return this->ComboActionGraphNode->GetNodeTooltipText();
|
||||
}
|
||||
|
||||
return NSLOCTEXT("UEdComboActionGraphNode", "DefaultToolTip", "Combo Action Node");
|
||||
}
|
||||
|
||||
#if WITH_EDITOR
|
||||
FLinearColor UEdComboActionGraphNode::GetBackgroundColor() const
|
||||
{
|
||||
return this->ComboActionGraphNode ? this->ComboActionGraphNode->GetBackgroundColour() : FLinearColor::Black;
|
||||
}
|
||||
|
||||
FSlateIcon UEdComboActionGraphNode::GetIconAndTint(FLinearColor& OutColor) const
|
||||
{
|
||||
static const FSlateIcon Icon = FSlateIcon(FComboInputSlateStyle::GetAppStyleSetName(), "MDSStyleSet.Node.Icon.small");
|
||||
OutColor = this->ComboActionGraphNode->GetBackgroundColour();
|
||||
return Icon;
|
||||
}
|
||||
#endif
|
||||
|
||||
void UEdComboActionGraphNode::PostEditUndo()
|
||||
{
|
||||
Super::PostEditUndo();
|
||||
}
|
||||
|
||||
void UEdComboActionGraphNode::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent)
|
||||
{
|
||||
Super::PostEditChangeProperty(PropertyChangedEvent);
|
||||
}
|
||||
|
||||
#undef LOCTEXT_NAMESPACE
|
||||
@ -1,62 +0,0 @@
|
||||
// ©2023 Batty Bovine Productions, LLC. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
|
||||
#include "SEdComboActionGraphNode.h"
|
||||
#include "EdGraph/EdGraphNode.h"
|
||||
|
||||
#include "EdComboActionGraphNode.generated.h"
|
||||
|
||||
DECLARE_LOG_CATEGORY_EXTERN(LogEdComboActionGraphNode, Log, All);
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
UCLASS(MinimalAPI)
|
||||
class UEdComboActionGraphNode : public UEdGraphNode
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
UEdComboActionGraphNode();
|
||||
|
||||
void SetComboActionGraphNode(UComboActionGraphNode *NewNode);
|
||||
class UEdComboActionGraph *GetEdComboActionGraph() const;
|
||||
|
||||
virtual void AllocateDefaultPins() override;
|
||||
virtual FText GetNodeTitle(ENodeTitleType::Type TitleType) const override;
|
||||
virtual void PrepareForCopying() override;
|
||||
virtual void AutowireNewNode(UEdGraphPin *FromPin) override;
|
||||
|
||||
virtual UEdGraphPin *GetInputPin() const;
|
||||
virtual UEdGraphPin *GetOutputPin() const;
|
||||
|
||||
virtual bool CanUserDeleteNode() const override;
|
||||
virtual bool CanDuplicateNode() const override;
|
||||
|
||||
virtual bool CanUserPasteNodes() const;
|
||||
|
||||
virtual FText GetTooltipText() const override;
|
||||
|
||||
#if WITH_EDITOR
|
||||
virtual void PostEditUndo() override;
|
||||
virtual void PostEditChangeProperty(FPropertyChangedEvent &PropertyChangedEvent) override;
|
||||
|
||||
virtual FLinearColor GetBackgroundColor() const;
|
||||
virtual FSlateIcon GetIconAndTint(FLinearColor &OutColor) const override;
|
||||
#endif
|
||||
|
||||
UPROPERTY(VisibleAnywhere, Instanced, Category="Combo Action Graph")
|
||||
class UComboActionGraphNode *ComboActionGraphNode;
|
||||
|
||||
SEdComboActionGraphNode *SEdNode;
|
||||
|
||||
private:
|
||||
bool bAllowCopy;
|
||||
bool bAllowDelete;
|
||||
bool bAllowDuplicate;
|
||||
bool bAllowPaste;
|
||||
};
|
||||
@ -1,44 +0,0 @@
|
||||
// ©2023 Batty Bovine Productions, LLC. All Rights Reserved.
|
||||
|
||||
#include "FAssetEditorToolbarComboActionGraph.h"
|
||||
|
||||
#include "ComboInputEditor.h"
|
||||
#include "Ed/AssetEditor_ComboActionGraph.h"
|
||||
#include "Ed/FComboActionGraphEditorCommands.h"
|
||||
|
||||
#define LOCTEXT_NAMESPACE "AssetEditorToolbarComboActionGraph"
|
||||
|
||||
|
||||
void FAssetEditorToolbarComboActionGraph::AddComboActionGraphToolbar(TSharedPtr<FExtender> Extender)
|
||||
{
|
||||
check(this->ComboActionGraphEditor.IsValid());
|
||||
TSharedPtr<FAssetEditor_ComboActionGraph> ComboActionGraphEditorPtr = this->ComboActionGraphEditor.Pin();
|
||||
|
||||
TSharedPtr<FExtender> ToolbarExtender = MakeShareable(new FExtender);
|
||||
ToolbarExtender->AddToolBarExtension("Asset", EExtensionHook::After, ComboActionGraphEditorPtr->GetToolkitCommands(), FToolBarExtensionDelegate::CreateSP( this, &FAssetEditorToolbarComboActionGraph::FillComboActionGraphToolbar ));
|
||||
ComboActionGraphEditorPtr->AddToolbarExtender(ToolbarExtender);
|
||||
}
|
||||
|
||||
void FAssetEditorToolbarComboActionGraph::FillComboActionGraphToolbar(FToolBarBuilder &ToolbarBuilder)
|
||||
{
|
||||
check(this->ComboActionGraphEditor.IsValid());
|
||||
TSharedPtr<FAssetEditor_ComboActionGraph> MounteaDialogueGraphEditorPtr = this->ComboActionGraphEditor.Pin();
|
||||
|
||||
ToolbarBuilder.BeginSection("Util");
|
||||
{
|
||||
ToolbarBuilder.AddToolBarButton(FComboActionGraphEditorCommands::Get().AutoArrange,
|
||||
NAME_None,
|
||||
LOCTEXT("AutoArrange_Label", "Auto Arrange"),
|
||||
LOCTEXT("AutoArrange_ToolTip", "ALPHA version!\n\nTries its best to arrange Graph Nodes. Don't judge too harshly please."),
|
||||
FSlateIcon(FComboInputSlateStyle::GetAppStyleSetName(), "MDSStyleSet.AutoArrange"));
|
||||
|
||||
ToolbarBuilder.AddToolBarButton(FComboActionGraphEditorCommands::Get().ValidateGraph,
|
||||
NAME_None,
|
||||
LOCTEXT("ValidateGraph_Label", "Validate Graph"),
|
||||
LOCTEXT("ValidateGraph_ToolTip", "Validates Graph if there are any invalid connections or broken data."),
|
||||
FSlateIcon(FComboInputSlateStyle::GetAppStyleSetName(), "MDSStyleSet.ValidateGraph"));
|
||||
}
|
||||
ToolbarBuilder.EndSection();
|
||||
}
|
||||
|
||||
#undef LOCTEXT_NAMESPACE
|
||||
@ -1,22 +0,0 @@
|
||||
// ©2023 Batty Bovine Productions, LLC. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
|
||||
|
||||
class FAssetEditorToolbarComboActionGraph : public TSharedFromThis<FAssetEditorToolbarComboActionGraph>
|
||||
{
|
||||
public:
|
||||
FAssetEditorToolbarComboActionGraph(TSharedPtr<FAssetEditor_ComboActionGraph> InComboActionGraphEditor)
|
||||
: ComboActionGraphEditor(InComboActionGraphEditor) {}
|
||||
|
||||
void AddComboActionGraphToolbar(TSharedPtr<FExtender> Extender);
|
||||
|
||||
private:
|
||||
void FillComboActionGraphToolbar(FToolBarBuilder &ToolbarBuilder);
|
||||
|
||||
protected:
|
||||
TWeakPtr<FAssetEditor_ComboActionGraph> ComboActionGraphEditor;
|
||||
|
||||
};
|
||||
@ -1,30 +0,0 @@
|
||||
// ©2023 Batty Bovine Productions, LLC. All Rights Reserved.
|
||||
|
||||
#include "FComboActionGraphEditorCommands.h"
|
||||
|
||||
#define LOCTEXT_NAMESPACE "ComboActionGraphEditorCommands"
|
||||
|
||||
|
||||
void FComboActionGraphEditorCommands::RegisterCommands()
|
||||
{
|
||||
UI_COMMAND
|
||||
(
|
||||
AutoArrange,
|
||||
"Auto Arrange",
|
||||
"Auto Arrange",
|
||||
EUserInterfaceActionType::Button,
|
||||
FInputChord()
|
||||
);
|
||||
|
||||
|
||||
UI_COMMAND
|
||||
(
|
||||
ValidateGraph,
|
||||
"Validate Graph",
|
||||
"Validate Graph",
|
||||
EUserInterfaceActionType::Button,
|
||||
FInputChord()
|
||||
);
|
||||
}
|
||||
|
||||
#undef LOCTEXT_NAMESPACE
|
||||
@ -1,19 +0,0 @@
|
||||
// ©2023 Batty Bovine Productions, LLC. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
|
||||
class FComboActionGraphEditorCommands : public TCommands<FComboActionGraphEditorCommands>
|
||||
{
|
||||
public:
|
||||
FComboActionGraphEditorCommands()
|
||||
: TCommands<FComboActionGraphEditorCommands>("ComboActionGraphEditor", NSLOCTEXT("Contexts", "ComboActionGraphEditor", "Combo Action Graph Editor"), NAME_None, FAppStyle::GetAppStyleSetName())
|
||||
{
|
||||
}
|
||||
|
||||
TSharedPtr<FUICommandInfo> AutoArrange;
|
||||
TSharedPtr<FUICommandInfo> ValidateGraph;
|
||||
|
||||
virtual void RegisterCommands() override;
|
||||
};
|
||||
@ -1,209 +0,0 @@
|
||||
// ©2023 Batty Bovine Productions, LLC. All Rights Reserved.
|
||||
|
||||
#include "FConnectionDrawingPolicy_ComboActionGraph.h"
|
||||
|
||||
#include "ComboInputEditor.h"
|
||||
#include "Ed/EdComboActionGraphEdge.h"
|
||||
#include "Ed/EdComboActionGraphNode.h"
|
||||
#include "Settings/ComboActionGraphEditorSettings.h"
|
||||
|
||||
DEFINE_LOG_CATEGORY(LogConnectionDrawingPolicy_ComboActionGraph);
|
||||
|
||||
|
||||
FConnectionDrawingPolicy_ComboActionGraph::FConnectionDrawingPolicy_ComboActionGraph(int32 InBackLayerID, int32 InFrontLayerID, float ZoomFactor, const FSlateRect &InClippingRect, FSlateWindowElementList &InDrawElements, UEdGraph *InGraphObj)
|
||||
: FKismetConnectionDrawingPolicy(InBackLayerID, InFrontLayerID, ZoomFactor, InClippingRect, InDrawElements, InGraphObj)
|
||||
, GraphObj(InGraphObj)
|
||||
{
|
||||
if (const UComboActionGraphEditorSettings* GraphEditorSettings = GetMutableDefault<UComboActionGraphEditorSettings>())
|
||||
{
|
||||
FComboInputEditorModule &ComboInputEditorModule = FComboInputEditorModule::Get();
|
||||
switch (GraphEditorSettings->GetArrowType())
|
||||
{
|
||||
case EComboActionArrowType::SimpleArrow:
|
||||
ArrowImage = ComboInputEditorModule.GetComboInputEditorStyleSet()->GetBrush(TEXT("MDSStyleSet.Graph.SimpleArrow"));
|
||||
break;
|
||||
case EComboActionArrowType::HollowArrow:
|
||||
ArrowImage = ComboInputEditorModule.GetComboInputEditorStyleSet()->GetBrush(TEXT("MDSStyleSet.Graph.HollowArrow"));
|
||||
break;
|
||||
case EComboActionArrowType::FancyArrow:
|
||||
ArrowImage = ComboInputEditorModule.GetComboInputEditorStyleSet()->GetBrush(TEXT("MDSStyleSet.Graph.FancyArrow"));
|
||||
break;
|
||||
case EComboActionArrowType::Bubble:
|
||||
ArrowImage = ComboInputEditorModule.GetComboInputEditorStyleSet()->GetBrush(TEXT("MDSStyleSet.Graph.Bubble"));
|
||||
break;
|
||||
case EComboActionArrowType::None:
|
||||
default:
|
||||
ArrowImage = nullptr;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ArrowImage = FAppStyle::GetBrush( TEXT("GenericPlay") );
|
||||
}
|
||||
|
||||
ArrowRadius = ArrowImage ? ArrowImage->ImageSize * ZoomFactor * 0.5f : FVector2D(0.f);
|
||||
MidpointImage = nullptr;
|
||||
MidpointRadius = FVector2D::ZeroVector;
|
||||
HoverDeemphasisDarkFraction = 0.8f;
|
||||
|
||||
BubbleImage = FAppStyle::GetBrush( TEXT("Graph.Arrow") );
|
||||
}
|
||||
|
||||
void FConnectionDrawingPolicy_ComboActionGraph::DetermineWiringStyle(UEdGraphPin *OutputPin, UEdGraphPin *InputPin, FConnectionParams &Params)
|
||||
{
|
||||
Params.AssociatedPin1 = OutputPin;
|
||||
Params.AssociatedPin2 = InputPin;
|
||||
|
||||
const UComboActionGraphEditorSettings *MounteaDialogueGraphEditorSettings = GetDefault<UComboActionGraphEditorSettings>();
|
||||
if (MounteaDialogueGraphEditorSettings)
|
||||
{
|
||||
Params.WireThickness = MounteaDialogueGraphEditorSettings->GetWireWidth();
|
||||
}
|
||||
else
|
||||
{
|
||||
Params.WireThickness = 1.f;
|
||||
}
|
||||
|
||||
const bool bDeemphasizeUnhoveredPins = HoveredPins.Num() > 0;
|
||||
if (bDeemphasizeUnhoveredPins)
|
||||
{
|
||||
ApplyHoverDeemphasis(OutputPin, InputPin, /*inout*/ Params.WireThickness, /*inout*/ Params.WireColor);
|
||||
}
|
||||
}
|
||||
|
||||
void FConnectionDrawingPolicy_ComboActionGraph::Draw(TMap<TSharedRef<SWidget>, FArrangedWidget> &InPinGeometries, FArrangedChildren &ArrangedNodes)
|
||||
{
|
||||
// Build an acceleration structure to quickly find geometry for the nodes
|
||||
NodeWidgetMap.Empty();
|
||||
for (int32 NodeIndex = 0; NodeIndex < ArrangedNodes.Num(); ++NodeIndex)
|
||||
{
|
||||
FArrangedWidget& CurWidget = ArrangedNodes[NodeIndex];
|
||||
TSharedRef<SGraphNode> ChildNode = StaticCastSharedRef<SGraphNode>(CurWidget.Widget);
|
||||
NodeWidgetMap.Add(ChildNode->GetNodeObj(), NodeIndex);
|
||||
}
|
||||
|
||||
// Now draw
|
||||
FConnectionDrawingPolicy::Draw(InPinGeometries, ArrangedNodes);
|
||||
}
|
||||
|
||||
void FConnectionDrawingPolicy_ComboActionGraph::DrawSplineWithArrow(const FGeometry &StartGeom, const FGeometry &EndGeom, const FConnectionParams &Params)
|
||||
{
|
||||
// Get a reasonable seed point (halfway between the boxes)
|
||||
const FVector2D StartCenter = FGeometryHelper::CenterOf(StartGeom);
|
||||
const FVector2D EndCenter = FGeometryHelper::CenterOf(EndGeom);
|
||||
const FVector2D SeedPoint = (StartCenter + EndCenter) * 0.5f;
|
||||
|
||||
// Find the (approximate) closest points between the two boxes
|
||||
const FVector2D StartAnchorPoint = FGeometryHelper::FindClosestPointOnGeom(StartGeom, SeedPoint);
|
||||
const FVector2D EndAnchorPoint = FGeometryHelper::FindClosestPointOnGeom(EndGeom, SeedPoint);
|
||||
|
||||
this->DrawSplineWithArrow(StartAnchorPoint, EndAnchorPoint, Params);
|
||||
}
|
||||
|
||||
void FConnectionDrawingPolicy_ComboActionGraph::DrawSplineWithArrow(const FVector2D &StartPoint, const FVector2D &EndPoint, const FConnectionParams &Params)
|
||||
{
|
||||
// bUserFlag1 indicates that we need to reverse the direction of connection (used by debugger)
|
||||
const FVector2D &P0 = Params.bUserFlag1 ? EndPoint : StartPoint;
|
||||
const FVector2D &P1 = Params.bUserFlag1 ? StartPoint : EndPoint;
|
||||
|
||||
UE_LOG(LogConnectionDrawingPolicy_ComboActionGraph, Verbose, TEXT("%s I %s"), *P0.ToString(), *P1.ToString());
|
||||
|
||||
FConnectionParams NewParams = Params;
|
||||
//NewParams.bDrawBubbles = true;
|
||||
|
||||
if (const UComboActionGraphEditorSettings *MounteaDialogueGraphEditorSettings = GetMutableDefault<UComboActionGraphEditorSettings>())
|
||||
{
|
||||
NewParams.WireThickness = MounteaDialogueGraphEditorSettings->GetWireWidth();
|
||||
}
|
||||
|
||||
Internal_DrawLineWithArrow(P0, P1, NewParams);
|
||||
}
|
||||
|
||||
void FConnectionDrawingPolicy_ComboActionGraph::DrawPreviewConnector(const FGeometry &PinGeometry, const FVector2D &StartPoint, const FVector2D &EndPoint, UEdGraphPin* Pin)
|
||||
{
|
||||
FConnectionParams Params;
|
||||
DetermineWiringStyle(Pin, nullptr, /*inout*/ Params);
|
||||
|
||||
if (Pin->Direction == EEdGraphPinDirection::EGPD_Output)
|
||||
{
|
||||
DrawSplineWithArrow(FGeometryHelper::FindClosestPointOnGeom(PinGeometry, EndPoint), EndPoint, Params);
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawSplineWithArrow(FGeometryHelper::FindClosestPointOnGeom(PinGeometry, StartPoint), StartPoint, Params);
|
||||
}
|
||||
}
|
||||
|
||||
FVector2D FConnectionDrawingPolicy_ComboActionGraph::ComputeSplineTangent(const FVector2D &Start, const FVector2D &End) const
|
||||
{
|
||||
const FVector2D Delta = End - Start;
|
||||
const FVector2D NormDelta = Delta.GetSafeNormal();
|
||||
|
||||
return NormDelta;
|
||||
}
|
||||
|
||||
void FConnectionDrawingPolicy_ComboActionGraph::DetermineLinkGeometry(FArrangedChildren &ArrangedNodes, TSharedRef<SWidget> &OutputPinWidget, UEdGraphPin *OutputPin, UEdGraphPin *InputPin, FArrangedWidget *&StartWidgetGeometry, FArrangedWidget *&EndWidgetGeometry)
|
||||
{
|
||||
if (UEdComboActionGraphEdge *EdgeNode = Cast<UEdComboActionGraphEdge>(InputPin->GetOwningNode()))
|
||||
{
|
||||
UEdComboActionGraphNode* Start = EdgeNode->GetStartNode();
|
||||
UEdComboActionGraphNode* End = EdgeNode->GetEndNode();
|
||||
if (Start != nullptr && End != nullptr)
|
||||
{
|
||||
int32* StartNodeIndex = NodeWidgetMap.Find(Start);
|
||||
int32* EndNodeIndex = NodeWidgetMap.Find(End);
|
||||
if (StartNodeIndex != nullptr && EndNodeIndex != nullptr)
|
||||
{
|
||||
StartWidgetGeometry = &(ArrangedNodes[*StartNodeIndex]);
|
||||
EndWidgetGeometry = &(ArrangedNodes[*EndNodeIndex]);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
StartWidgetGeometry = PinGeometries->Find(OutputPinWidget);
|
||||
|
||||
if (TSharedPtr<SGraphPin>* pTargetWidget = PinToPinWidgetMap.Find(InputPin))
|
||||
{
|
||||
TSharedRef<SGraphPin> InputWidget = (*pTargetWidget).ToSharedRef();
|
||||
EndWidgetGeometry = PinGeometries->Find(InputWidget);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FConnectionDrawingPolicy_ComboActionGraph::Internal_DrawLineWithArrow(const FVector2D &StartAnchorPoint, const FVector2D &EndAnchorPoint, const FConnectionParams &Params)
|
||||
{
|
||||
const float LineSeparationAmount = 4.5f;
|
||||
|
||||
const FVector2D DeltaPos = EndAnchorPoint - StartAnchorPoint;
|
||||
const FVector2D UnitDelta = DeltaPos.GetSafeNormal();
|
||||
const FVector2D Normal = FVector2D(DeltaPos.Y, -DeltaPos.X).GetSafeNormal();
|
||||
|
||||
// Come up with the final start/end points
|
||||
const FVector2D DirectionBias = Normal * LineSeparationAmount;
|
||||
const FVector2D LengthBias = ArrowRadius.X * UnitDelta;
|
||||
const FVector2D StartPoint = StartAnchorPoint + DirectionBias + LengthBias;
|
||||
const FVector2D EndPoint = EndAnchorPoint + DirectionBias - LengthBias;
|
||||
|
||||
// Draw a line/spline
|
||||
DrawConnection(WireLayerID, StartPoint, EndPoint, Params);
|
||||
|
||||
// Draw the arrow
|
||||
if (ArrowImage)
|
||||
{
|
||||
const FVector2D ArrowDrawPos = EndPoint - ArrowRadius;
|
||||
const float AngleInRadians = FMath::Atan2(DeltaPos.Y, DeltaPos.X);
|
||||
|
||||
FSlateDrawElement::MakeRotatedBox(
|
||||
DrawElementsList,
|
||||
ArrowLayerID,
|
||||
FPaintGeometry(ArrowDrawPos, ArrowImage->ImageSize * ZoomFactor, ZoomFactor),
|
||||
ArrowImage,
|
||||
ESlateDrawEffect::None,
|
||||
AngleInRadians,
|
||||
TOptional<FVector2D>(),
|
||||
FSlateDrawElement::RelativeToElement,
|
||||
Params.WireColor
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -1,36 +0,0 @@
|
||||
// ©2023 Batty Bovine Productions, LLC. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "BlueprintConnectionDrawingPolicy.h"
|
||||
#include "ConnectionDrawingPolicy.h"
|
||||
|
||||
DECLARE_LOG_CATEGORY_EXTERN(LogConnectionDrawingPolicy_ComboActionGraph, Log, All);
|
||||
|
||||
|
||||
class FConnectionDrawingPolicy_ComboActionGraph : public FKismetConnectionDrawingPolicy
|
||||
{
|
||||
|
||||
public:
|
||||
FConnectionDrawingPolicy_ComboActionGraph(int32 InBackLayerID, int32 InFrontLayerID, float ZoomFactor, const FSlateRect& InClippingRect, FSlateWindowElementList& InDrawElements, UEdGraph* InGraphObj);
|
||||
virtual ~FConnectionDrawingPolicy_ComboActionGraph() {};
|
||||
|
||||
// FConnectionDrawingPolicy interface
|
||||
virtual void DetermineWiringStyle(UEdGraphPin* OutputPin, UEdGraphPin* InputPin, /*inout*/ FConnectionParams& Params) override;
|
||||
virtual void Draw(TMap<TSharedRef<SWidget>, FArrangedWidget>& InPinGeometries, FArrangedChildren& ArrangedNodes) override;
|
||||
virtual void DrawSplineWithArrow(const FGeometry& StartGeom, const FGeometry& EndGeom, const FConnectionParams& Params) override;
|
||||
virtual void DrawSplineWithArrow(const FVector2D& StartPoint, const FVector2D& EndPoint, const FConnectionParams& Params) override;
|
||||
virtual void DrawPreviewConnector(const FGeometry& PinGeometry, const FVector2D& StartPoint, const FVector2D& EndPoint, UEdGraphPin* Pin) override;
|
||||
virtual FVector2D ComputeSplineTangent(const FVector2D& Start, const FVector2D& End) const override;
|
||||
virtual void DetermineLinkGeometry(FArrangedChildren& ArrangedNodes, TSharedRef<SWidget>& OutputPinWidget, UEdGraphPin* OutputPin, UEdGraphPin* InputPin, FArrangedWidget*& StartWidgetGeometry, FArrangedWidget*& EndWidgetGeometry) override;
|
||||
// End of FConnectionDrawingPolicy interface
|
||||
|
||||
protected:
|
||||
void Internal_DrawLineWithArrow(const FVector2D& StartAnchorPoint, const FVector2D& EndAnchorPoint, const FConnectionParams& Params);
|
||||
|
||||
protected:
|
||||
UEdGraph *GraphObj;
|
||||
TMap<UEdGraphNode*, int32> NodeWidgetMap;
|
||||
|
||||
};
|
||||
@ -1,131 +0,0 @@
|
||||
#include "SEdComboActionGraphEdge.h"
|
||||
|
||||
#include "ConnectionDrawingPolicy.h"
|
||||
#include "SGraphPanel.h"
|
||||
|
||||
#include "Ed/EdComboActionGraphEdge.h"
|
||||
#include "Ed/EdComboActionGraphNode.h"
|
||||
#include "Widgets/Images/SImage.h"
|
||||
|
||||
#define LOCTEXT_NAMESPACE "SEdComboActionGraphEdge"
|
||||
|
||||
|
||||
void SEdComboActionGraphEdge::Construct(const FArguments &InArgs, UEdComboActionGraphEdge *InNode)
|
||||
{
|
||||
this->GraphNode = InNode;
|
||||
this->UpdateGraphNode();
|
||||
}
|
||||
|
||||
bool SEdComboActionGraphEdge::RequiresSecondPassLayout() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void SEdComboActionGraphEdge::PerformSecondPassLayout(const TMap<UObject*, TSharedRef<SNode>>& NodeToWidgetLookup) const
|
||||
{
|
||||
UEdComboActionGraphEdge *EdgeNode = CastChecked<UEdComboActionGraphEdge>(GraphNode);
|
||||
|
||||
FGeometry StartGeom;
|
||||
FGeometry EndGeom;
|
||||
|
||||
UEdComboActionGraphNode *Start = EdgeNode->GetStartNode();
|
||||
UEdComboActionGraphNode *End = EdgeNode->GetEndNode();
|
||||
if (Start != nullptr && End != nullptr)
|
||||
{
|
||||
const TSharedRef<SNode> *pFromWidget = NodeToWidgetLookup.Find(Start);
|
||||
const TSharedRef<SNode> *pToWidget = NodeToWidgetLookup.Find(End);
|
||||
if (pFromWidget != nullptr && pToWidget != nullptr)
|
||||
{
|
||||
const TSharedRef<SNode>& FromWidget = *pFromWidget;
|
||||
const TSharedRef<SNode>& ToWidget = *pToWidget;
|
||||
|
||||
StartGeom = FGeometry(FVector2D(Start->NodePosX, Start->NodePosY), FVector2D::ZeroVector, FromWidget->GetDesiredSize(), 1.0f);
|
||||
EndGeom = FGeometry(FVector2D(End->NodePosX, End->NodePosY), FVector2D::ZeroVector, ToWidget->GetDesiredSize(), 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
PositionBetweenTwoNodesWithOffset(StartGeom, EndGeom, 0, 1);
|
||||
}
|
||||
|
||||
void SEdComboActionGraphEdge::UpdateGraphNode()
|
||||
{
|
||||
InputPins.Empty();
|
||||
OutputPins.Empty();
|
||||
|
||||
RightNodeBox.Reset();
|
||||
LeftNodeBox.Reset();
|
||||
|
||||
|
||||
this->ContentScale.Bind( this, &SGraphNode::GetContentScale );
|
||||
this->GetOrAddSlot( ENodeZone::Center )
|
||||
.HAlign(HAlign_Center)
|
||||
.VAlign(VAlign_Center)
|
||||
[
|
||||
SNew(SOverlay)
|
||||
/*+ SOverlay::Slot()
|
||||
[
|
||||
SNew(SImage)
|
||||
.Image(FAppStyle::GetBrush("Graph.TransitionNode.ColorSpill"))
|
||||
.ColorAndOpacity(this, &SEdComboActionGraphEdge::GetEdgeColor)
|
||||
]*/
|
||||
+ SOverlay::Slot()
|
||||
[
|
||||
SNew(SImage)
|
||||
.Image(FAppStyle::GetBrush("GraphEditor.RefPinIcon"))
|
||||
.ColorAndOpacity(this, &SEdComboActionGraphEdge::GetEdgeColor)
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
void SEdComboActionGraphEdge::PositionBetweenTwoNodesWithOffset(const FGeometry& StartGeom, const FGeometry& EndGeom, int32 NodeIndex, int32 MaxNodes) const
|
||||
{
|
||||
// Get a reasonable seed point (halfway between the boxes)
|
||||
const FVector2D StartCenter = FGeometryHelper::CenterOf(StartGeom);
|
||||
const FVector2D EndCenter = FGeometryHelper::CenterOf(EndGeom);
|
||||
const FVector2D SeedPoint = (StartCenter + EndCenter) * 0.5f;
|
||||
|
||||
// Find the (approximate) closest points between the two boxes
|
||||
const FVector2D StartAnchorPoint = FGeometryHelper::FindClosestPointOnGeom(StartGeom, SeedPoint);
|
||||
const FVector2D EndAnchorPoint = FGeometryHelper::FindClosestPointOnGeom(EndGeom, SeedPoint);
|
||||
|
||||
// Position ourselves halfway along the connecting line between the nodes, elevated away perpendicular to the direction of the line
|
||||
const float Height = 30.0f;
|
||||
|
||||
const FVector2D DesiredNodeSize = GetDesiredSize();
|
||||
|
||||
FVector2D DeltaPos(EndAnchorPoint - StartAnchorPoint);
|
||||
|
||||
if (DeltaPos.IsNearlyZero())
|
||||
{
|
||||
DeltaPos = FVector2D(10.0f, 0.0f);
|
||||
}
|
||||
|
||||
const FVector2D Normal = FVector2D(DeltaPos.Y, -DeltaPos.X).GetSafeNormal();
|
||||
|
||||
const FVector2D NewCenter = StartAnchorPoint + (0.5f * DeltaPos) + (Height * Normal);
|
||||
|
||||
FVector2D DeltaNormal = DeltaPos.GetSafeNormal();
|
||||
|
||||
// Calculate node offset in the case of multiple transitions between the same two nodes
|
||||
// MultiNodeOffset: the offset where 0 is the centre of the transition, -1 is 1 <size of node>
|
||||
// towards the PrevStateNode and +1 is 1 <size of node> towards the NextStateNode.
|
||||
|
||||
const float MutliNodeSpace = 0.2f; // Space between multiple transition nodes (in units of <size of node> )
|
||||
const float MultiNodeStep = (1.f + MutliNodeSpace); //Step between node centres (Size of node + size of node spacer)
|
||||
|
||||
const float MultiNodeStart = -((MaxNodes - 1) * MultiNodeStep) / 2.f;
|
||||
const float MultiNodeOffset = MultiNodeStart + (NodeIndex * MultiNodeStep);
|
||||
|
||||
// Now we need to adjust the new center by the node size, zoom factor and multi node offset
|
||||
const FVector2D NewCorner = NewCenter - (0.5f * DesiredNodeSize) + (DeltaNormal * MultiNodeOffset * DesiredNodeSize.Size());
|
||||
|
||||
GraphNode->NodePosX = NewCorner.X;
|
||||
GraphNode->NodePosY = NewCorner.Y;
|
||||
}
|
||||
|
||||
FSlateColor SEdComboActionGraphEdge::GetEdgeColor() const
|
||||
{
|
||||
return FLinearColor(0.9f, 0.9f, 0.9f, 1.0f);
|
||||
}
|
||||
|
||||
#undef LOCTEXT_NAMESPACE
|
||||
@ -1,33 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Styling/SlateColor.h"
|
||||
#include "Widgets/DeclarativeSyntaxSupport.h"
|
||||
#include "Widgets/SWidget.h"
|
||||
#include "SNodePanel.h"
|
||||
#include "SGraphNode.h"
|
||||
|
||||
|
||||
class SEdComboActionGraphEdge : public SGraphNode
|
||||
{
|
||||
public:
|
||||
SLATE_BEGIN_ARGS(SEdComboActionGraphEdge){}
|
||||
SLATE_END_ARGS()
|
||||
|
||||
void Construct(const FArguments &InArgs, class UEdComboActionGraphEdge *InNode);
|
||||
|
||||
virtual bool RequiresSecondPassLayout() const override;
|
||||
virtual void PerformSecondPassLayout(const TMap<UObject*, TSharedRef<SNode> > &NodeToWidgetLookup) const override;
|
||||
|
||||
virtual void UpdateGraphNode() override;
|
||||
|
||||
// Calculate position for multiple nodes to be placed between a start and end point, by providing this nodes index and max expected nodes
|
||||
void PositionBetweenTwoNodesWithOffset(const FGeometry &StartGeom, const FGeometry &EndGeom, int32 NodeIndex, int32 MaxNodes) const;
|
||||
|
||||
protected:
|
||||
FSlateColor GetEdgeColor() const;
|
||||
|
||||
private:
|
||||
TSharedPtr<STextEntryPopup> TextEntryWidget;
|
||||
|
||||
};
|
||||
@ -1,879 +0,0 @@
|
||||
// ©2023 Batty Bovine Productions, LLC. All Rights Reserved.
|
||||
|
||||
#include "SEdComboActionGraphNode.h"
|
||||
|
||||
#include "ComboActionGraph.h"
|
||||
#include "ComboInputAssets.h"
|
||||
#include "ComboInputEditor.h"
|
||||
#include "GraphEditorSettings.h"
|
||||
#include "SCommentBubble.h"
|
||||
#include "SGraphPin.h"
|
||||
#include "SlateOptMacros.h"
|
||||
|
||||
#include "Blueprint/UserWidget.h"
|
||||
#include "Ed/SEdComboActionGraphNodeIndex.h"
|
||||
#include "Ed/EdComboActionGraphNode.h"
|
||||
#include "Helpers/ComboActionGraphColors.h"
|
||||
#include "Nodes/ComboActionGraphNode_ActionNodeBase.h"
|
||||
#include "Nodes/ComboActionGraphNode_StartNode.h"
|
||||
#include "Settings/ComboActionGraphEditorSettings.h"
|
||||
#include "Widgets/Layout/SGridPanel.h"
|
||||
#include "Widgets/Layout/SScaleBox.h"
|
||||
#include "Widgets/Text/SInlineEditableTextBlock.h"
|
||||
|
||||
#define LOCTEXT_NAMESPACE "EdComboActionGraph"
|
||||
|
||||
|
||||
#pragma region Pin
|
||||
|
||||
class SComboActionGraphPin : public SGraphPin
|
||||
{
|
||||
public:
|
||||
SLATE_BEGIN_ARGS(SComboActionGraphPin) {}
|
||||
SLATE_END_ARGS()
|
||||
|
||||
void Construct(const FArguments &InArgs, UEdGraphPin *InPin)
|
||||
{
|
||||
this->SetCursor(EMouseCursor::Default);
|
||||
|
||||
this->bShowLabel = true;
|
||||
|
||||
this->GraphPinObj = InPin;
|
||||
check(this->GraphPinObj != nullptr);
|
||||
|
||||
const UEdGraphSchema *Schema = this->GraphPinObj->GetSchema();
|
||||
check(Schema);
|
||||
|
||||
// Pins Out/In Border
|
||||
SBorder::Construct(SBorder::FArguments()
|
||||
.BorderImage(this, &SComboActionGraphPin::GetPinBorder)
|
||||
.BorderBackgroundColor(this, &SComboActionGraphPin::GetPinColor)
|
||||
.OnMouseButtonDown(this, &SComboActionGraphPin::OnPinMouseDown)
|
||||
.Cursor(this, &SComboActionGraphPin::GetPinCursor)
|
||||
.Padding(FMargin(5.0f))
|
||||
);
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual FSlateColor GetPinColor() const override
|
||||
{
|
||||
if (const UComboActionGraphEditorSettings *GraphEditorSettings = GetMutableDefault<UComboActionGraphEditorSettings>())
|
||||
{
|
||||
switch (GraphEditorSettings->GetNodeTheme())
|
||||
{
|
||||
case EComboActionNodeTheme::DarkTheme:
|
||||
return ComboActionGraphColors::PinsDock::LightTheme;
|
||||
case EComboActionNodeTheme::LightTheme:
|
||||
return ComboActionGraphColors::PinsDock::DarkTheme;
|
||||
default:
|
||||
return ComboActionGraphColors::PinsDock::LightTheme;
|
||||
}
|
||||
}
|
||||
|
||||
return ComboActionGraphColors::Pin::Default;
|
||||
}
|
||||
|
||||
virtual TSharedRef<SWidget> GetDefaultValueWidget() override
|
||||
{
|
||||
return SNew(STextBlock);
|
||||
}
|
||||
|
||||
const FSlateBrush *GetPinBorder() const
|
||||
{
|
||||
FComboInputEditorModule &ComboInputEditorModule = FComboInputEditorModule::Get();
|
||||
|
||||
if (const UComboActionGraphEditorSettings *GraphEditorSettings = GetMutableDefault<UComboActionGraphEditorSettings>())
|
||||
{
|
||||
switch (GraphEditorSettings->GetNodeType())
|
||||
{
|
||||
case EComboActionNodeType::SoftCorners:
|
||||
return ComboInputEditorModule.GetComboInputEditorStyleSet()->GetBrush("MDSStyleSet.Node.TextSoftEdges");
|
||||
case EComboActionNodeType::HardCorners:
|
||||
return ComboInputEditorModule.GetComboInputEditorStyleSet()->GetBrush("MDSStyleSet.Node.TextHardEdges");
|
||||
}
|
||||
}
|
||||
|
||||
return ComboInputEditorModule.GetComboInputEditorStyleSet()->GetBrush(TEXT("MDSStyleSet.Graph.PinDocksOverlay"));
|
||||
}
|
||||
};
|
||||
|
||||
#pragma endregion
|
||||
|
||||
void SEdComboActionGraphNode::Construct(const FArguments &InArgs, UEdComboActionGraphNode *InNode)
|
||||
{
|
||||
this->GraphNode = InNode;
|
||||
this->UpdateGraphNode();
|
||||
InNode->SEdNode = this;
|
||||
//bIsHovered = false;
|
||||
|
||||
this->GraphEditorSettings = GetMutableDefault<UComboActionGraphEditorSettings>();
|
||||
}
|
||||
|
||||
void SEdComboActionGraphNode::OnMouseEnter(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
|
||||
{
|
||||
//bIsHovered = true;
|
||||
|
||||
this->SetToolTipText(GetTooltipText());
|
||||
this->OnVisualizeTooltip(GetToolTip()->AsWidget());
|
||||
|
||||
SGraphNode::OnMouseEnter(MyGeometry, MouseEvent);
|
||||
}
|
||||
|
||||
void SEdComboActionGraphNode::OnMouseLeave(const FPointerEvent& MouseEvent)
|
||||
{
|
||||
//bIsHovered = false;
|
||||
|
||||
this->SetToolTipText(FText::GetEmpty());
|
||||
this->OnToolTipClosing();
|
||||
|
||||
SGraphNode::OnMouseLeave(MouseEvent);
|
||||
}
|
||||
|
||||
const FSlateBrush *SEdComboActionGraphNode::GetIndexBrush() const
|
||||
{
|
||||
FComboInputEditorModule &ComboInputEditorModule = FComboInputEditorModule::Get();
|
||||
return ComboInputEditorModule.GetComboInputEditorStyleSet()->GetBrush("MDSStyleSet.Node.TextSoftEdges");
|
||||
}
|
||||
|
||||
BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
|
||||
|
||||
void SEdComboActionGraphNode::UpdateGraphNode()
|
||||
{
|
||||
const FMargin NodePadding = FMargin(2.0f);
|
||||
const FMargin UnifiedRowsPadding = FMargin(0.f, 1.15f, 0.f, 0.f);
|
||||
|
||||
const FSlateColor DefaultFontColor = ComboActionGraphColors::TextColors::Normal;
|
||||
|
||||
this->InputPins.Empty();
|
||||
this->OutputPins.Empty();
|
||||
|
||||
// Reset variables that are going to be exposed, in case we are refreshing an already setup node.
|
||||
this->RightNodeBox.Reset();
|
||||
this->LeftNodeBox.Reset();
|
||||
this->OutputPinBox.Reset();
|
||||
|
||||
// Set this here so that it isn't null.
|
||||
SAssignNew(this->InlineEditableText, SInlineEditableTextBlock);
|
||||
|
||||
TSharedPtr<SErrorText> ErrorText;
|
||||
TSharedPtr<SNodeTitle> NodeTitle = SNew(SNodeTitle, this->GraphNode);
|
||||
|
||||
TSharedPtr<SVerticalBox> StackBox;
|
||||
TSharedPtr<SVerticalBox> UniformBox;
|
||||
|
||||
this->ContentScale.Bind(this, &SGraphNode::GetContentScale);
|
||||
|
||||
FComboInputEditorModule &ComboInputEditorModule = FComboInputEditorModule::Get();
|
||||
const FSlateBrush *CircleBrush = ComboInputEditorModule.GetComboInputEditorStyleSet()->GetBrush(TEXT("MDSStyleSet.Node.IndexCircle"));
|
||||
this->GetOrAddSlot(ENodeZone::Left)
|
||||
.SlotOffset(TAttribute<FVector2D>(this, &SEdComboActionGraphNode::GetIndexSlotOffset))
|
||||
.SlotSize(TAttribute<FVector2D>(this, &SEdComboActionGraphNode::GetIndexSlotSize))
|
||||
[
|
||||
SNew(SOverlay)
|
||||
+SOverlay::Slot()
|
||||
.HAlign(EHorizontalAlignment::HAlign_Fill)
|
||||
.VAlign(EVerticalAlignment::VAlign_Fill)
|
||||
[
|
||||
SNew(SBox)
|
||||
.WidthOverride(CircleBrush->ImageSize.X)
|
||||
.HeightOverride(CircleBrush->ImageSize.Y)
|
||||
]
|
||||
|
||||
+SOverlay::Slot()
|
||||
.HAlign(EHorizontalAlignment::HAlign_Fill)
|
||||
.VAlign(EVerticalAlignment::VAlign_Fill)
|
||||
[
|
||||
SNew(SBorder)
|
||||
.BorderImage(CircleBrush)
|
||||
.BorderBackgroundColor(FLinearColor::Gray)
|
||||
.Padding(FMargin(4.0f))
|
||||
.HAlign(EHorizontalAlignment::HAlign_Center)
|
||||
.VAlign(EVerticalAlignment::VAlign_Center)
|
||||
[
|
||||
SNew(STextBlock)
|
||||
.Font(FCoreStyle::GetDefaultFontStyle("Regular", 8))
|
||||
.Text(this, &SEdComboActionGraphNode::GetIndexText)
|
||||
.Visibility(this, &SEdComboActionGraphNode::GetIndexSlotVisibility)
|
||||
]
|
||||
]
|
||||
];
|
||||
|
||||
this->GetOrAddSlot(ENodeZone::Center)
|
||||
.HAlign(EHorizontalAlignment::HAlign_Fill)
|
||||
.VAlign(EVerticalAlignment::VAlign_Fill)
|
||||
[
|
||||
SNew(SBox)
|
||||
[
|
||||
// OUTER STYLE
|
||||
SNew(SBorder)
|
||||
.BorderImage(this, &SEdComboActionGraphNode::GetNodeTypeBrush)
|
||||
.Padding(3.0f)
|
||||
.BorderBackgroundColor(this, &SEdComboActionGraphNode::GetBorderBackgroundColor)
|
||||
[
|
||||
|
||||
SNew(SOverlay)
|
||||
|
||||
// Adding some colours so its not so boring
|
||||
+ SOverlay::Slot()
|
||||
.HAlign(EHorizontalAlignment::HAlign_Fill)
|
||||
.VAlign(EVerticalAlignment::VAlign_Fill)
|
||||
[
|
||||
// INNER STYLE
|
||||
SNew(SBorder)
|
||||
.BorderImage(this, &SEdComboActionGraphNode::GetNodeTypeBrush)
|
||||
.HAlign(EHorizontalAlignment::HAlign_Fill)
|
||||
.VAlign(EVerticalAlignment::VAlign_Center)
|
||||
.Visibility(EVisibility::SelfHitTestInvisible)
|
||||
.BorderBackgroundColor(this, &SEdComboActionGraphNode::GetBorderFrontColor)
|
||||
]
|
||||
|
||||
// Pins and node details
|
||||
+ SOverlay::Slot()
|
||||
.HAlign(EHorizontalAlignment::HAlign_Center)
|
||||
.VAlign(EVerticalAlignment::VAlign_Fill)
|
||||
[
|
||||
SNew(SHorizontalBox)
|
||||
|
||||
// INPUT PIN AREA
|
||||
+ SHorizontalBox::Slot()
|
||||
.AutoWidth()
|
||||
[
|
||||
SNew(SVerticalBox)
|
||||
+ SVerticalBox::Slot()
|
||||
.VAlign(EVerticalAlignment::VAlign_Fill)
|
||||
|
||||
+ SVerticalBox::Slot()
|
||||
.VAlign(EVerticalAlignment::VAlign_Center)
|
||||
[
|
||||
SAssignNew(this->LeftNodeBox, SVerticalBox)
|
||||
]
|
||||
|
||||
+ SVerticalBox::Slot()
|
||||
.VAlign(EVerticalAlignment::VAlign_Fill)
|
||||
]
|
||||
|
||||
+ SHorizontalBox::Slot()
|
||||
.Padding(FMargin(NodePadding.Left, 0.0f, NodePadding.Right, 0.0f))
|
||||
.VAlign(EVerticalAlignment::VAlign_Fill)
|
||||
[
|
||||
SNew(SVerticalBox)
|
||||
+ SVerticalBox::Slot()
|
||||
.AutoHeight()
|
||||
[
|
||||
SAssignNew(this->NodeBody, SBorder)
|
||||
.BorderImage(this, &SEdComboActionGraphNode::GetTextNodeTypeBrush)
|
||||
.BorderBackgroundColor(this, &SEdComboActionGraphNode::GetNodeTitleBackgroundColor)
|
||||
.HAlign(EHorizontalAlignment::HAlign_Fill)
|
||||
.VAlign(EVerticalAlignment::VAlign_Center)
|
||||
.Visibility(EVisibility::SelfHitTestInvisible)
|
||||
[
|
||||
SNew(SBox)
|
||||
//.MinDesiredWidth(FOptionalSize(145.f))
|
||||
[
|
||||
SNew(SVerticalBox)
|
||||
|
||||
+ SVerticalBox::Slot()
|
||||
.AutoHeight()
|
||||
[
|
||||
SNew(SOverlay)
|
||||
+ SOverlay::Slot()
|
||||
.HAlign(EHorizontalAlignment::HAlign_Center)
|
||||
.VAlign(EVerticalAlignment::VAlign_Fill)
|
||||
[
|
||||
SNew(SVerticalBox)
|
||||
#pragma region NameSlot
|
||||
// NAME SLOT
|
||||
+ SVerticalBox::Slot()
|
||||
.AutoHeight()
|
||||
.HAlign(HAlign_Center)
|
||||
[
|
||||
SNew(SHorizontalBox)
|
||||
+ SHorizontalBox::Slot()
|
||||
.AutoWidth()
|
||||
[
|
||||
// POPUP ERROR MESSAGE
|
||||
SAssignNew(ErrorText, SErrorText)
|
||||
.BackgroundColor(
|
||||
this,
|
||||
&SEdComboActionGraphNode::GetErrorColor)
|
||||
.ToolTipText(
|
||||
this,
|
||||
&SEdComboActionGraphNode::GetErrorMsgToolTip)
|
||||
]
|
||||
+ SHorizontalBox::Slot()
|
||||
.AutoWidth()
|
||||
.HAlign(HAlign_Center)
|
||||
[
|
||||
SNew(SHorizontalBox)
|
||||
+ SHorizontalBox::Slot()
|
||||
.Padding(FMargin(4.0f, 0.0f, 4.0f, 0.0f))
|
||||
[
|
||||
SNew(SVerticalBox)
|
||||
+ SVerticalBox::Slot()
|
||||
.HAlign(EHorizontalAlignment::HAlign_Center)
|
||||
.AutoHeight()
|
||||
[
|
||||
SNew(STextBlock)
|
||||
.Text(this, &SEdComboActionGraphNode::GetComboActionName)
|
||||
.Justification(ETextJustify::Center)
|
||||
.Visibility(EVisibility::Visible)
|
||||
.Font(FCoreStyle::GetDefaultFontStyle("Bold", 14))
|
||||
.ColorAndOpacity(FSlateColor(FLinearColor(230.0f / 255.0f, 230.0f / 255.0f, 230.0f / 255.0f)))
|
||||
.ShadowOffset(FVector2D(2, 2))
|
||||
.ShadowColorAndOpacity(FLinearColor(0.f, 0.f, 0.f, 0.7f))
|
||||
]
|
||||
|
||||
+ SVerticalBox::Slot()
|
||||
.AutoHeight()
|
||||
[
|
||||
NodeTitle.ToSharedRef()
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
#pragma endregion
|
||||
]
|
||||
]
|
||||
#pragma region Unified
|
||||
+ SVerticalBox::Slot()
|
||||
.VAlign(EVerticalAlignment::VAlign_Fill)
|
||||
[
|
||||
SNew(SBox)
|
||||
.Visibility(this, &SEdComboActionGraphNode::GetResponseStackVisibility)
|
||||
.HAlign(EHorizontalAlignment::HAlign_Fill)
|
||||
[
|
||||
SNew(SVerticalBox)
|
||||
//+ SVerticalBox::Slot()
|
||||
//[
|
||||
// SNew(SBox)
|
||||
// .Visibility(this, &SEdComboActionGraphNode::ShowDecoratorsBottomPadding)
|
||||
// [
|
||||
// SNew(SSpacer)
|
||||
// .Size(FVector2D(0.f, 2.5f))
|
||||
// ]
|
||||
//]
|
||||
|
||||
#pragma region ResponseStack
|
||||
// RESPONSE STACK
|
||||
+ SVerticalBox::Slot()
|
||||
.AutoHeight()
|
||||
.HAlign(EHorizontalAlignment::HAlign_Fill)
|
||||
.VAlign(EVerticalAlignment::VAlign_Fill)
|
||||
.Padding(FMargin(8.0f, 0.0f, 8.0f, 0.0f))
|
||||
[
|
||||
SNew(SBox)
|
||||
.Visibility(EVisibility::Visible)
|
||||
.MaxDesiredWidth(FOptionalSize(130.0f))
|
||||
.HAlign(EHorizontalAlignment::HAlign_Fill)
|
||||
[
|
||||
SNew(SHorizontalBox)
|
||||
.Visibility(EVisibility::HitTestInvisible)
|
||||
#pragma region Title
|
||||
+ SHorizontalBox::Slot()
|
||||
.HAlign(EHorizontalAlignment::HAlign_Center)
|
||||
[
|
||||
SNew(STextBlock)
|
||||
.Text(LOCTEXT("A", "Info:"))
|
||||
.Font(FCoreStyle::GetDefaultFontStyle("Bold", 8))
|
||||
.ColorAndOpacity(DefaultFontColor)
|
||||
]
|
||||
]
|
||||
#pragma endregion
|
||||
#pragma region Title
|
||||
[
|
||||
SNew(SVerticalBox)
|
||||
.Visibility(EVisibility::HitTestInvisible)
|
||||
|
||||
+ SVerticalBox::Slot()
|
||||
.HAlign(EHorizontalAlignment::HAlign_Left)
|
||||
[
|
||||
SNew(STextBlock)
|
||||
.Text(this, &SEdComboActionGraphNode::GetComboInputName)
|
||||
.Font(FCoreStyle::GetDefaultFontStyle("Bold", 8))
|
||||
.ColorAndOpacity(DefaultFontColor)
|
||||
]
|
||||
|
||||
+ SVerticalBox::Slot()
|
||||
.HAlign(EHorizontalAlignment::HAlign_Left)
|
||||
[
|
||||
SNew(STextBlock)
|
||||
.Text(this, &SEdComboActionGraphNode::GetComboInputTriggerActionName)
|
||||
.Font(FCoreStyle::GetDefaultFontStyle("Bold", 8))
|
||||
.ColorAndOpacity(DefaultFontColor)
|
||||
]
|
||||
#pragma endregion
|
||||
]
|
||||
]
|
||||
#pragma endregion
|
||||
+ SVerticalBox::Slot()
|
||||
.HAlign(EHorizontalAlignment::HAlign_Center)
|
||||
.VAlign(EVerticalAlignment::VAlign_Fill)
|
||||
[
|
||||
SNew(SSpacer)
|
||||
.Size(FVector2D(0.f, 2.5f))
|
||||
]
|
||||
]
|
||||
]
|
||||
#pragma endregion
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
|
||||
+ SHorizontalBox::Slot()
|
||||
.AutoWidth()
|
||||
[
|
||||
SNew(SSpacer)
|
||||
.Size(FVector2D(0.0f, 10.0f))
|
||||
]
|
||||
|
||||
// OUTPUT PIN AREA
|
||||
+ SHorizontalBox::Slot()
|
||||
.AutoWidth()
|
||||
.Padding(20.0f, 0.0f)
|
||||
[
|
||||
SNew(SVerticalBox)
|
||||
+ SVerticalBox::Slot()
|
||||
[
|
||||
SAssignNew(this->RightNodeBox, SVerticalBox)
|
||||
+ SVerticalBox::Slot()
|
||||
.HAlign(EHorizontalAlignment::HAlign_Fill)
|
||||
.VAlign(EVerticalAlignment::VAlign_Center)
|
||||
[
|
||||
SAssignNew(this->OutputPinBox, SHorizontalBox)
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
];
|
||||
|
||||
// Create comment bubble
|
||||
TSharedPtr<SCommentBubble> CommentBubble;
|
||||
const FSlateColor CommentColor = GetDefault<UGraphEditorSettings>()->DefaultCommentNodeTitleColor;
|
||||
|
||||
SAssignNew(CommentBubble, SCommentBubble)
|
||||
.GraphNode(this->GraphNode)
|
||||
.Text(this, &SGraphNode::GetNodeComment)
|
||||
.OnTextCommitted(this, &SGraphNode::OnCommentTextCommitted)
|
||||
.ColorAndOpacity(CommentColor)
|
||||
.AllowPinning(true)
|
||||
.EnableTitleBarBubble(true)
|
||||
.EnableBubbleCtrls(true)
|
||||
.GraphLOD(this, &SGraphNode::GetCurrentLOD)
|
||||
.IsGraphNodeHovered(this, &SGraphNode::IsHovered);
|
||||
|
||||
GetOrAddSlot(ENodeZone::TopCenter)
|
||||
.SlotOffset(TAttribute<FVector2D>(CommentBubble.Get(), &SCommentBubble::GetOffset))
|
||||
.SlotSize(TAttribute<FVector2D>(CommentBubble.Get(), &SCommentBubble::GetSize))
|
||||
.AllowScaling(TAttribute<bool>(CommentBubble.Get(), &SCommentBubble::IsScalingAllowed))
|
||||
.VAlign(EVerticalAlignment::VAlign_Top)
|
||||
[
|
||||
CommentBubble.ToSharedRef()
|
||||
];
|
||||
|
||||
ErrorReporting = ErrorText;
|
||||
ErrorReporting->SetError(ErrorMsg);
|
||||
CreatePinWidgets();
|
||||
}
|
||||
|
||||
void SEdComboActionGraphNode::CreatePinWidgets()
|
||||
{
|
||||
UEdComboActionGraphNode *StateNode = CastChecked<UEdComboActionGraphNode>(this->GraphNode);
|
||||
|
||||
for (int32 PinIdx = 0; PinIdx < StateNode->Pins.Num(); PinIdx++)
|
||||
{
|
||||
UEdGraphPin* MyPin = StateNode->Pins[PinIdx];
|
||||
if (!MyPin->bHidden)
|
||||
{
|
||||
TSharedPtr<SGraphPin> NewPin = SNew(SComboActionGraphPin, MyPin);
|
||||
|
||||
AddPin(NewPin.ToSharedRef());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SEdComboActionGraphNode::AddPin(const TSharedRef<SGraphPin>& PinToAdd)
|
||||
{
|
||||
PinToAdd->SetOwner(SharedThis(this));
|
||||
|
||||
const UEdGraphPin* PinObj = PinToAdd->GetPinObj();
|
||||
const bool bAdvancedParameter = PinObj && PinObj->bAdvancedView;
|
||||
if (bAdvancedParameter)
|
||||
{
|
||||
PinToAdd->SetVisibility( TAttribute<EVisibility>(PinToAdd, &SGraphPin::IsPinVisibleAsAdvanced) );
|
||||
}
|
||||
|
||||
if (PinToAdd->GetDirection() == EEdGraphPinDirection::EGPD_Input)
|
||||
{
|
||||
this->LeftNodeBox->AddSlot()
|
||||
.HAlign(HAlign_Fill)
|
||||
.VAlign(VAlign_Fill)
|
||||
.FillHeight(1.0f)
|
||||
.Padding(20.0f,0.0f)
|
||||
[
|
||||
PinToAdd
|
||||
];
|
||||
this->InputPins.Add(PinToAdd);
|
||||
}
|
||||
else // Direction == EEdGraphPinDirection::EGPD_Output
|
||||
{
|
||||
this->OutputPinBox->AddSlot()
|
||||
.HAlign(HAlign_Fill)
|
||||
.VAlign(VAlign_Fill)
|
||||
.FillWidth(1.0f)
|
||||
[
|
||||
PinToAdd
|
||||
];
|
||||
this->OutputPins.Add(PinToAdd);
|
||||
}
|
||||
}
|
||||
|
||||
bool SEdComboActionGraphNode::IsNameReadOnly() const
|
||||
{
|
||||
UEdComboActionGraphNode *EdNode_Node = Cast<UEdComboActionGraphNode>(this->GraphNode);
|
||||
check(EdNode_Node != nullptr);
|
||||
|
||||
UComboActionGraph *ComboActionGraphNode = EdNode_Node->ComboActionGraphNode->Graph;
|
||||
check(this->GraphNode != nullptr);
|
||||
|
||||
return !this->GraphNode->bCanRenameNode || SGraphNode::IsNameReadOnly();
|
||||
}
|
||||
|
||||
END_SLATE_FUNCTION_BUILD_OPTIMIZATION
|
||||
|
||||
void SEdComboActionGraphNode::OnNameTextCommitted(const FText& InText, ETextCommit::Type CommitInfo)
|
||||
{
|
||||
if (InText.IsEmpty()) return;
|
||||
|
||||
SGraphNode::OnNameTextCommited(InText, CommitInfo);
|
||||
|
||||
UEdComboActionGraphNode *MyNode = CastChecked<UEdComboActionGraphNode>(this->GraphNode);
|
||||
|
||||
if (MyNode != nullptr && MyNode->ComboActionGraphNode != nullptr)
|
||||
{
|
||||
const FScopedTransaction Transaction(LOCTEXT("ComboActionGraphEditorRenameNode", "Combo Action Editor: Rename Node"));
|
||||
MyNode->Modify();
|
||||
MyNode->ComboActionGraphNode->Modify();
|
||||
MyNode->ComboActionGraphNode->SetNodeTitle(InText);
|
||||
UpdateGraphNode();
|
||||
}
|
||||
}
|
||||
|
||||
const FSlateBrush *SEdComboActionGraphNode::GetNodeTypeBrush() const
|
||||
{
|
||||
FComboInputEditorModule &ComboInputEditorModule = FComboInputEditorModule::Get();
|
||||
if (this->GraphEditorSettings)
|
||||
{
|
||||
switch (this->GraphEditorSettings->GetNodeType())
|
||||
{
|
||||
case EComboActionNodeType::SoftCorners:
|
||||
return ComboInputEditorModule.GetComboInputEditorStyleSet()->GetBrush("MDSStyleSet.Node.SoftEdges");
|
||||
case EComboActionNodeType::HardCorners:
|
||||
return ComboInputEditorModule.GetComboInputEditorStyleSet()->GetBrush("MDSStyleSet.Node.HardEdges");
|
||||
}
|
||||
}
|
||||
|
||||
return ComboInputEditorModule.GetComboInputEditorStyleSet()->GetBrush("MDSStyleSet.Node.SoftEdges");
|
||||
}
|
||||
|
||||
const FSlateBrush *SEdComboActionGraphNode::GetTextNodeTypeBrush() const
|
||||
{
|
||||
FComboInputEditorModule &ComboInputEditorModule = FComboInputEditorModule::Get();
|
||||
if (this->GraphEditorSettings)
|
||||
{
|
||||
switch (this->GraphEditorSettings->GetNodeType())
|
||||
{
|
||||
case EComboActionNodeType::SoftCorners:
|
||||
return ComboInputEditorModule.GetComboInputEditorStyleSet()->GetBrush("MDSStyleSet.Node.TextSoftEdges");
|
||||
case EComboActionNodeType::HardCorners:
|
||||
return ComboInputEditorModule.GetComboInputEditorStyleSet()->GetBrush("MDSStyleSet.Node.TextHardEdges");
|
||||
}
|
||||
}
|
||||
|
||||
return ComboInputEditorModule.GetComboInputEditorStyleSet()->GetBrush("MDSStyleSet.Node.TextSoftEdges");
|
||||
}
|
||||
|
||||
FSlateColor SEdComboActionGraphNode::GetBorderBackgroundColor() const
|
||||
{
|
||||
UEdComboActionGraphNode *MyNode = CastChecked<UEdComboActionGraphNode>(this->GraphNode);
|
||||
return MyNode ? MyNode->GetBackgroundColor() : ComboActionGraphColors::NodeBorder::HighlightAbortRange0;
|
||||
}
|
||||
|
||||
FSlateColor SEdComboActionGraphNode::GetBorderFrontColor() const
|
||||
{
|
||||
if (this->GraphEditorSettings)
|
||||
{
|
||||
switch (this->GraphEditorSettings->GetNodeTheme())
|
||||
{
|
||||
case EComboActionNodeTheme::DarkTheme:
|
||||
return ComboActionGraphColors::Overlay::DarkTheme;
|
||||
case EComboActionNodeTheme::LightTheme:
|
||||
return ComboActionGraphColors::Overlay::LightTheme;
|
||||
}
|
||||
}
|
||||
|
||||
return ComboActionGraphColors::Overlay::DarkTheme;
|
||||
}
|
||||
|
||||
FSlateColor SEdComboActionGraphNode::GetNodeTitleBackgroundColor() const
|
||||
{
|
||||
return ComboActionGraphColors::NodeBody::Default;
|
||||
}
|
||||
|
||||
FSlateColor SEdComboActionGraphNode::GetDecoratorsBackgroundColor() const
|
||||
{
|
||||
return ComboActionGraphColors::DecoratorsBody::Default;
|
||||
}
|
||||
|
||||
FSlateColor SEdComboActionGraphNode::GetPinsDockColor() const
|
||||
{
|
||||
if (this->GraphEditorSettings)
|
||||
{
|
||||
switch (this->GraphEditorSettings->GetNodeTheme())
|
||||
{
|
||||
case EComboActionNodeTheme::DarkTheme:
|
||||
return ComboActionGraphColors::PinsDock::DarkTheme;
|
||||
case EComboActionNodeTheme::LightTheme:
|
||||
return ComboActionGraphColors::PinsDock::LightTheme;
|
||||
}
|
||||
}
|
||||
|
||||
return ComboActionGraphColors::Overlay::DarkTheme;
|
||||
}
|
||||
|
||||
EVisibility SEdComboActionGraphNode::GetDragOverMarkerVisibility() const
|
||||
{
|
||||
return EVisibility::Visible;
|
||||
}
|
||||
|
||||
const FSlateBrush*SEdComboActionGraphNode::GetNameIcon() const
|
||||
{
|
||||
return FAppStyle::GetBrush(TEXT("BTEditor.Graph.BTNode.Icon"));
|
||||
}
|
||||
|
||||
const FSlateBrush*SEdComboActionGraphNode::GetBulletPointImageBrush() const
|
||||
{
|
||||
FComboInputEditorModule &ComboInputEditorModule = FComboInputEditorModule::Get();
|
||||
return ComboInputEditorModule.GetComboInputEditorStyleSet()->GetBrush( "MDSStyleSet.Icon.BulletPoint" );
|
||||
}
|
||||
|
||||
FText SEdComboActionGraphNode::GetIndexOverlayTooltipText() const
|
||||
{
|
||||
return LOCTEXT("NodeIndexTooltip", "Node index");
|
||||
}
|
||||
|
||||
FText SEdComboActionGraphNode::GetIndexText() const
|
||||
{
|
||||
if (const UEdComboActionGraphNode *EdParentNode = Cast<UEdComboActionGraphNode>(GraphNode))
|
||||
{
|
||||
if (const auto Node = EdParentNode->ComboActionGraphNode)
|
||||
{
|
||||
if (const auto Graph = Node->Graph)
|
||||
{
|
||||
const int32 Index = Graph->AllNodes.Find(Node);
|
||||
return FText::AsNumber(Index);
|
||||
}
|
||||
|
||||
return FText::AsNumber(EdParentNode->ComboActionGraphNode->GetNodeIndex());
|
||||
}
|
||||
}
|
||||
return FText::AsNumber(INDEX_NONE);
|
||||
}
|
||||
|
||||
EVisibility SEdComboActionGraphNode::GetIndexSlotVisibility() const
|
||||
{
|
||||
if (this->IsHovered())
|
||||
{
|
||||
return EVisibility::SelfHitTestInvisible;
|
||||
}
|
||||
|
||||
return EVisibility::Collapsed;
|
||||
}
|
||||
|
||||
FVector2D SEdComboActionGraphNode::GetIndexSlotOffset() const
|
||||
{
|
||||
if (this->IsHovered())
|
||||
{
|
||||
return FVector2D(-20.f);
|
||||
}
|
||||
|
||||
return FVector2D(-15.f);
|
||||
}
|
||||
|
||||
FVector2D SEdComboActionGraphNode::GetIndexSlotSize() const
|
||||
{
|
||||
if (this->IsHovered())
|
||||
{
|
||||
return FVector2D(24.f);
|
||||
}
|
||||
|
||||
return FVector2D(12.f);
|
||||
}
|
||||
|
||||
void SEdComboActionGraphNode::OnIndexHoverStateChanged(bool bArg) const
|
||||
{
|
||||
// TODO something
|
||||
}
|
||||
|
||||
FSlateColor SEdComboActionGraphNode::GetOverlayWidgetBackgroundColor(bool bArg) const
|
||||
{
|
||||
return bArg ? ComboActionGraphColors::IndexBorder::HoveredState : ComboActionGraphColors::IndexBorder::NormalState;
|
||||
}
|
||||
|
||||
EVisibility SEdComboActionGraphNode::ShowImplementsOnlySlot_Unified() const
|
||||
{
|
||||
if (this->GraphEditorSettings)
|
||||
{
|
||||
if (this->GraphEditorSettings->ShowDetailedInfo_NumDecorators() && !this->GraphEditorSettings->ShowDetailedInfo_InheritsDecorators())
|
||||
{
|
||||
return EVisibility::SelfHitTestInvisible; //return HasGraphDecorators() ? EVisibility::Visible : EVisibility::Collapsed;
|
||||
}
|
||||
}
|
||||
return EVisibility::Collapsed;
|
||||
}
|
||||
|
||||
EVisibility SEdComboActionGraphNode::ShowImplementsOnlySlot_Stack() const
|
||||
{
|
||||
if (this->GraphEditorSettings)
|
||||
{
|
||||
if (this->GraphEditorSettings->GetDecoratorsStyle() == EComboActionDecoratorsInfoStyle::Stack)
|
||||
{
|
||||
if (this->GraphEditorSettings->ShowDetailedInfo_NumDecorators())
|
||||
{
|
||||
return EVisibility::SelfHitTestInvisible; //return HasGraphDecorators() ? EVisibility::Visible : EVisibility::Collapsed;
|
||||
}
|
||||
}
|
||||
}
|
||||
return EVisibility::Collapsed;
|
||||
}
|
||||
|
||||
EVisibility SEdComboActionGraphNode::ShowInheritsDecoratorsSlot_Stack() const
|
||||
{
|
||||
if (this->GraphEditorSettings)
|
||||
{
|
||||
if (this->GraphEditorSettings->GetDecoratorsStyle() == EComboActionDecoratorsInfoStyle::Stack)
|
||||
{
|
||||
if (this->GraphEditorSettings->ShowDetailedInfo_InheritsDecorators())
|
||||
{
|
||||
return EVisibility::SelfHitTestInvisible; //return HasGraphDecorators() ? EVisibility::Visible : EVisibility::Collapsed;
|
||||
}
|
||||
}
|
||||
}
|
||||
return EVisibility::Collapsed;
|
||||
}
|
||||
|
||||
EVisibility SEdComboActionGraphNode::ShowAllDecorators() const
|
||||
{
|
||||
if (this->GraphEditorSettings)
|
||||
{
|
||||
if (this->GraphEditorSettings->GetDecoratorsStyle() == EComboActionDecoratorsInfoStyle::Unified)
|
||||
{
|
||||
if (this->GraphEditorSettings->ShowDetailedInfo_InheritsDecorators() && this->GraphEditorSettings->ShowDetailedInfo_NumDecorators())
|
||||
{
|
||||
return EVisibility::SelfHitTestInvisible; //return HasGraphDecorators() ? EVisibility::Visible : EVisibility::Collapsed;
|
||||
}
|
||||
}
|
||||
}
|
||||
return EVisibility::Collapsed;
|
||||
}
|
||||
|
||||
EVisibility SEdComboActionGraphNode::ShowDecoratorsBottomPadding() const
|
||||
{
|
||||
if (this->GraphEditorSettings)
|
||||
{
|
||||
if (this->GraphEditorSettings->ShowDetailedInfo_InheritsDecorators() || this->GraphEditorSettings->ShowDetailedInfo_NumDecorators())
|
||||
{
|
||||
return EVisibility::SelfHitTestInvisible;
|
||||
}
|
||||
}
|
||||
return EVisibility::Collapsed;
|
||||
}
|
||||
|
||||
EComboActionDecoratorsInfoStyle SEdComboActionGraphNode::GetDecoratorsStyle() const
|
||||
{
|
||||
if (this->GraphEditorSettings)
|
||||
{
|
||||
return this->GraphEditorSettings->GetDecoratorsStyle();
|
||||
}
|
||||
|
||||
if (const UComboActionGraphEditorSettings *TempSettings = GetMutableDefault<UComboActionGraphEditorSettings>())
|
||||
{
|
||||
return TempSettings->GetDecoratorsStyle();
|
||||
}
|
||||
|
||||
return EComboActionDecoratorsInfoStyle::Stack;
|
||||
}
|
||||
|
||||
EVisibility SEdComboActionGraphNode::GetResponseStackVisibility() const
|
||||
{
|
||||
if (const UEdComboActionGraphNode *EdParentNode = Cast<UEdComboActionGraphNode>(this->GraphNode))
|
||||
{
|
||||
if (const UComboActionGraphNode_ActionNodeBase *ActionNode = Cast<UComboActionGraphNode_ActionNodeBase>(EdParentNode->ComboActionGraphNode))
|
||||
{
|
||||
return EVisibility::SelfHitTestInvisible;
|
||||
}
|
||||
}
|
||||
return EVisibility::Collapsed;
|
||||
}
|
||||
|
||||
FText SEdComboActionGraphNode::GetTooltipText() const
|
||||
{
|
||||
if (const UEdComboActionGraphNode *EdParentNode = Cast<UEdComboActionGraphNode>(this->GraphNode))
|
||||
{
|
||||
return EdParentNode->GetTooltipText();
|
||||
}
|
||||
return LOCTEXT("SEdComboActionGraphNode_Tooltip", "invalid node selected");
|
||||
}
|
||||
|
||||
FText SEdComboActionGraphNode::GetComboActionName() const
|
||||
{
|
||||
if (const UEdComboActionGraphNode *EdParentNode = Cast<UEdComboActionGraphNode>(this->GraphNode))
|
||||
{
|
||||
if (const UComboActionGraphNode_ActionNodeBase *ActionNode = Cast<UComboActionGraphNode_ActionNodeBase>(EdParentNode->ComboActionGraphNode))
|
||||
{
|
||||
if (UComboAction *ComboAction = ActionNode->GetComboAction())
|
||||
{
|
||||
return FText::FromName(ComboAction->ActionName);
|
||||
}
|
||||
}
|
||||
else if (const UComboActionGraphNode_StartNode *StartNode = Cast<UComboActionGraphNode_StartNode>(EdParentNode->ComboActionGraphNode))
|
||||
{
|
||||
return LOCTEXT("SEdComboActionGraphNode_StartName", "Start");
|
||||
}
|
||||
}
|
||||
return LOCTEXT("SEdComboActionGraphNode_ComboActionNameNotSet", "NOT CONFIGURED");
|
||||
}
|
||||
|
||||
FText SEdComboActionGraphNode::GetComboInputName() const
|
||||
{
|
||||
if (const UEdComboActionGraphNode *EdParentNode = Cast<UEdComboActionGraphNode>(this->GraphNode))
|
||||
{
|
||||
if (const UComboActionGraphNode_ActionNodeBase *ActionNode = Cast<UComboActionGraphNode_ActionNodeBase>(EdParentNode->ComboActionGraphNode))
|
||||
{
|
||||
if (UComboInputAsset *ComboInput = ActionNode->GetComboInput())
|
||||
{
|
||||
return FText::Format(LOCTEXT("SEdComboActionGraphNode_ComboInputName", "When {0}"), FText::FromName(ComboInput->ComboInputName));
|
||||
}
|
||||
}
|
||||
}
|
||||
return LOCTEXT("SEdComboActionGraphNode_ComboInputNameNotSet", "No combo input");
|
||||
}
|
||||
|
||||
FText SEdComboActionGraphNode::GetComboInputTriggerActionName() const
|
||||
{
|
||||
if (const UEdComboActionGraphNode *EdParentNode = Cast<UEdComboActionGraphNode>(this->GraphNode))
|
||||
{
|
||||
if (const UComboActionGraphNode_ActionNodeBase *ActionNode = Cast<UComboActionGraphNode_ActionNodeBase>(EdParentNode->ComboActionGraphNode))
|
||||
{
|
||||
const FString &EnumNameString = StaticEnum<EComboActionTriggerEvent>()->GetNameByValue((uint8)ActionNode->GetTriggerEvent()).ToString();
|
||||
FString EnumType, EnumValueName;
|
||||
EnumNameString.Split("::", &EnumType, &EnumValueName);
|
||||
return FText::Format(LOCTEXT("SEdComboActionGraphNode_TriggerActionName", "is {0}"), FText::FromString(EnumValueName));
|
||||
}
|
||||
}
|
||||
return LOCTEXT("SEdComboActionGraphNode_TriggerActionNameNotSet", "No trigger event");
|
||||
}
|
||||
|
||||
#undef LOCTEXT_NAMESPACE
|
||||
@ -1,78 +0,0 @@
|
||||
// ©2023 Batty Bovine Productions, LLC. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
|
||||
#include "SGraphNode.h"
|
||||
#include "Settings\ComboActionGraphEditorSettings.h"
|
||||
|
||||
|
||||
class SEdComboActionGraphNode : public SGraphNode
|
||||
{
|
||||
public:
|
||||
SLATE_BEGIN_ARGS(SEdComboActionGraphNode) {}
|
||||
SLATE_END_ARGS()
|
||||
|
||||
void Construct(const FArguments &InArgs, class UEdComboActionGraphNode *InNode);
|
||||
|
||||
virtual void OnMouseEnter(const FGeometry &MyGeometry, const FPointerEvent &MouseEvent) override;
|
||||
virtual void OnMouseLeave(const FPointerEvent &MouseEvent) override;
|
||||
|
||||
const FSlateBrush *GetIndexBrush() const;
|
||||
|
||||
virtual void UpdateGraphNode() override;
|
||||
virtual void CreatePinWidgets() override;
|
||||
virtual void AddPin(const TSharedRef<SGraphPin> &PinToAdd) override;
|
||||
virtual bool IsNameReadOnly() const override;
|
||||
|
||||
void OnNameTextCommitted(const FText &InText, ETextCommit::Type CommitInfo);
|
||||
|
||||
virtual const FSlateBrush *GetNodeTypeBrush () const;
|
||||
virtual const FSlateBrush *GetTextNodeTypeBrush () const;
|
||||
virtual FSlateColor GetBorderBackgroundColor() const;
|
||||
virtual FSlateColor GetBorderFrontColor() const;
|
||||
virtual FSlateColor GetNodeTitleBackgroundColor() const;
|
||||
virtual FSlateColor GetDecoratorsBackgroundColor() const;
|
||||
|
||||
virtual FSlateColor GetPinsDockColor() const;
|
||||
|
||||
virtual EVisibility GetDragOverMarkerVisibility() const;
|
||||
|
||||
virtual const FSlateBrush *GetNameIcon() const;
|
||||
|
||||
const FSlateBrush *GetBulletPointImageBrush() const;
|
||||
|
||||
virtual FText GetIndexOverlayTooltipText() const;
|
||||
virtual FText GetIndexText() const;
|
||||
EVisibility GetIndexSlotVisibility() const;
|
||||
FVector2D GetIndexSlotOffset() const;
|
||||
FVector2D GetIndexSlotSize() const;
|
||||
|
||||
virtual void OnIndexHoverStateChanged(bool bArg) const;
|
||||
virtual FSlateColor GetOverlayWidgetBackgroundColor(bool bArg) const;
|
||||
|
||||
EVisibility ShowImplementsOnlySlot_Unified() const;
|
||||
EVisibility ShowImplementsOnlySlot_Stack() const;
|
||||
EVisibility ShowInheritsDecoratorsSlot_Stack() const;
|
||||
EVisibility ShowAllDecorators() const;
|
||||
EVisibility ShowDecoratorsBottomPadding() const;
|
||||
|
||||
virtual EComboActionDecoratorsInfoStyle GetDecoratorsStyle() const;
|
||||
EVisibility GetResponseStackVisibility() const;
|
||||
|
||||
FText GetTooltipText() const;
|
||||
|
||||
FText GetComboActionName() const;
|
||||
FText GetComboInputName() const;
|
||||
FText GetComboInputTriggerActionName() const;
|
||||
|
||||
protected:
|
||||
TSharedPtr<SBorder> NodeBody;
|
||||
TSharedPtr<SHorizontalBox> OutputPinBox;
|
||||
|
||||
class UComboActionGraphEditorSettings *GraphEditorSettings = nullptr;
|
||||
|
||||
FLinearColor NodeInnerColor;
|
||||
FLinearColor PinsDockColor;
|
||||
};
|
||||
@ -1,37 +0,0 @@
|
||||
// ©2023 Batty Bovine Productions, LLC. All Rights Reserved.
|
||||
|
||||
#include "SEdComboActionGraphNodeIndex.h"
|
||||
|
||||
#include "ComboInputEditor.h"
|
||||
|
||||
|
||||
void SEdComboActionGraphNodeIndex::Construct(const FArguments &InArgs)
|
||||
{
|
||||
FComboInputEditorModule &ComboInputEditorModule = FComboInputEditorModule::Get();
|
||||
const FSlateBrush* CircleBrush = ComboInputEditorModule.GetComboInputEditorStyleSet()->GetBrush(TEXT("MDSStyleSet.Node.IndexCircle"));
|
||||
ChildSlot
|
||||
[
|
||||
SNew(SOverlay)
|
||||
+SOverlay::Slot()
|
||||
.HAlign(EHorizontalAlignment::HAlign_Fill)
|
||||
.VAlign(EVerticalAlignment::VAlign_Fill)
|
||||
[
|
||||
// Add a dummy box here to make sure the widget doesnt get smaller than the brush
|
||||
SNew(SBox)
|
||||
.WidthOverride(CircleBrush->ImageSize.X)
|
||||
.HeightOverride(CircleBrush->ImageSize.Y)
|
||||
]
|
||||
|
||||
+SOverlay::Slot()
|
||||
.HAlign(EHorizontalAlignment::HAlign_Fill)
|
||||
.VAlign(EVerticalAlignment::VAlign_Fill)
|
||||
[
|
||||
SNew(SBorder)
|
||||
.BorderImage(CircleBrush)
|
||||
.BorderBackgroundColor(this, &SEdComboActionGraphNodeIndex::GetBackgroundColor)
|
||||
.Padding(FMargin(4.0f))
|
||||
.VAlign(EVerticalAlignment::VAlign_Center)
|
||||
.HAlign(EHorizontalAlignment::HAlign_Center)
|
||||
]
|
||||
];
|
||||
}
|
||||
@ -1,33 +0,0 @@
|
||||
// ©2023 Batty Bovine Productions, LLC. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Widgets/DeclarativeSyntaxSupport.h"
|
||||
#include "Widgets/SCompoundWidget.h"
|
||||
|
||||
class SEdComboActionGraphNodeIndex : public SCompoundWidget
|
||||
{
|
||||
public:
|
||||
/** Delegate event fired when the hover state of this widget changes */
|
||||
DECLARE_DELEGATE_OneParam(FOnHoverStateChanged, bool /* bHovered */);
|
||||
|
||||
/** Delegate used to receive the background color of the node, depending on hover state and state of other siblings */
|
||||
DECLARE_DELEGATE_RetVal_OneParam(FSlateColor, FOnGetBackgroundColor, bool /* bHovered */);
|
||||
|
||||
SLATE_BEGIN_ARGS(SEdComboActionGraphNodeIndex) {}
|
||||
SLATE_ATTRIBUTE(TSharedPtr<SWidget>, OverlayBody)
|
||||
|
||||
// Events
|
||||
SLATE_EVENT(FOnHoverStateChanged, OnHoverStateChanged)
|
||||
SLATE_EVENT(FOnGetBackgroundColor, OnGetBackgroundColor)
|
||||
SLATE_END_ARGS()
|
||||
|
||||
void Construct(const FArguments &InArgs);
|
||||
|
||||
/** Get the color we use to display the rounded border */
|
||||
FSlateColor GetBackgroundColor() const { return FSlateColor::UseForeground(); }
|
||||
|
||||
private:
|
||||
/** The OverlayBody used for this widget*/
|
||||
TSharedPtr<SWidget> OverlayBody;
|
||||
};
|
||||
@ -1,87 +0,0 @@
|
||||
// ©2023 Batty Bovine Productions, LLC. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
|
||||
#include "ComboInputAssets.h"
|
||||
#include "Ed/EdComboActionGraphNode.h"
|
||||
#include "Kismet/BlueprintFunctionLibrary.h"
|
||||
#include "Nodes/ComboActionGraphNode.h"
|
||||
#include "Nodes/ComboActionGraphNode_ActionNodeBase.h"
|
||||
#include "Settings/ComboActionGraphEditorSettings.h"
|
||||
|
||||
#include "ComboActionEditorBFC.generated.h"
|
||||
|
||||
|
||||
/**
|
||||
* Editor Only helper functions.
|
||||
*/
|
||||
UCLASS()
|
||||
class UComboActionEditorBFC : public UBlueprintFunctionLibrary
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
|
||||
#if WITH_EDITOR
|
||||
static FText GetNodeTitle(UComboActionGraphNode *Node)
|
||||
{
|
||||
if (!Node)
|
||||
{
|
||||
return FText::FromString("Invalid Node");
|
||||
}
|
||||
|
||||
const UComboActionGraphEditorSettings *Settings = GetDefault<UComboActionGraphEditorSettings>();
|
||||
if (Settings)
|
||||
{
|
||||
if (Settings->ShowAutomaticNames())
|
||||
{
|
||||
if (const UComboActionGraphNode_ActionNodeBase *DialogueNodeBase = Cast<UComboActionGraphNode_ActionNodeBase>(Node))
|
||||
{
|
||||
if (const UComboInputAsset *ComboInput = DialogueNodeBase->GetComboInput())
|
||||
{
|
||||
return FText::FromString(ComboInput->GetName());
|
||||
}
|
||||
}
|
||||
|
||||
return Node->GetInternalName();
|
||||
}
|
||||
}
|
||||
|
||||
return Node->GetNodeTitle();
|
||||
}
|
||||
|
||||
static EComboActionNodeTheme GetNodeTheme()
|
||||
{
|
||||
const UComboActionGraphEditorSettings *Settings = GetDefault<UComboActionGraphEditorSettings>();
|
||||
if (Settings != nullptr)
|
||||
{
|
||||
return Settings->GetNodeTheme();
|
||||
}
|
||||
|
||||
return EComboActionNodeTheme::DarkTheme;
|
||||
}
|
||||
|
||||
static void TriggerPreviewRefresh(TArray<UObject*> NodeObjects)
|
||||
{
|
||||
for (auto Itr : NodeObjects)
|
||||
{
|
||||
UEdComboActionGraphNode *SelectedNode = Cast<UEdComboActionGraphNode>(Itr);
|
||||
if (!SelectedNode || !SelectedNode->ComboActionGraphNode)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
UComboActionGraphNode_ActionNodeBase *DialogueNodeBase = Cast<UComboActionGraphNode_ActionNodeBase>(SelectedNode->ComboActionGraphNode);
|
||||
if (!DialogueNodeBase)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
DialogueNodeBase->UpdatePreviews();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
};
|
||||
@ -1,92 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
|
||||
namespace ComboActionGraphColors
|
||||
{
|
||||
namespace NodeBody
|
||||
{
|
||||
constexpr FLinearColor Default(0.1f, 0.1f, 0.1f);
|
||||
constexpr FLinearColor Root(0.5f, 0.5f, 0.5f, 0.1f);
|
||||
constexpr FLinearColor Error(1.0f, 0.0f, 0.0f);
|
||||
}
|
||||
|
||||
namespace DecoratorsBody
|
||||
{
|
||||
constexpr FLinearColor Default(0.1f, 0.1f, 0.1f);
|
||||
}
|
||||
|
||||
namespace NodeBorder
|
||||
{
|
||||
constexpr FLinearColor Inactive(0.08f, 0.08f, 0.08f);
|
||||
constexpr FLinearColor Root(0.2f, 0.2f, 0.2f, 0.2f);
|
||||
constexpr FLinearColor Selected(1.00f, 0.08f, 0.08f);
|
||||
constexpr FLinearColor ActiveDebugging(1.0f, 1.0f, 0.0f);
|
||||
constexpr FLinearColor InactiveDebugging(0.4f, 0.4f, 0.0f);
|
||||
constexpr FLinearColor HighlightAbortRange0(0.0f, 0.22f, 0.4f);
|
||||
constexpr FLinearColor HighlightAbortRange1(0.0f, 0.4f, 0.22f);
|
||||
constexpr FLinearColor Disconnected(0.f, 0.f, 0.f);
|
||||
constexpr FLinearColor BrokenWithParent(1.f, 0.f, 1.f);
|
||||
constexpr FLinearColor QuickFind(0.f, 0.8f, 0.f);
|
||||
}
|
||||
|
||||
namespace Pin
|
||||
{
|
||||
constexpr FLinearColor Diff(0.9f, 0.2f, 0.15f);
|
||||
constexpr FLinearColor Hover(1.0f, 0.7f, 0.0f);
|
||||
constexpr FLinearColor Default(0.02f, 0.02f, 0.02f);
|
||||
constexpr FLinearColor SingleNode(0.02f, 0.02f, 0.02f);
|
||||
}
|
||||
|
||||
namespace Connection
|
||||
{
|
||||
constexpr FLinearColor Default(1.0f, 1.0f, 1.0f);
|
||||
}
|
||||
|
||||
namespace Action
|
||||
{
|
||||
constexpr FLinearColor DragMarker(1.0f, 1.0f, 0.2f);
|
||||
}
|
||||
|
||||
namespace Overlay
|
||||
{
|
||||
constexpr FLinearColor LightTheme(1.f, 1.f, 1.f, 0.45f);
|
||||
constexpr FLinearColor DarkTheme(0.f, 0.f, 0.f, 0.9f);
|
||||
}
|
||||
|
||||
namespace PinsDock
|
||||
{
|
||||
constexpr FLinearColor DarkTheme(0.075f, 0.075f, 0.075f, 1.f);
|
||||
constexpr FLinearColor LightTheme(0.075f, 0.075f, 0.075f, 1.f);
|
||||
}
|
||||
|
||||
namespace ValidationGraph
|
||||
{
|
||||
constexpr FLinearColor LightTheme(0.1f, 0.1f, 0.1f, 1.f);
|
||||
constexpr FLinearColor DarkTheme(0.05f, 0.05f, 0.05f, 1.f);
|
||||
}
|
||||
|
||||
namespace IndexBorder
|
||||
{
|
||||
constexpr FLinearColor NormalState(0.05f, 0.05f, 0.05f, 1.f);
|
||||
constexpr FLinearColor HoveredState(0.05f, 0.05f, 0.05f, 1.f);
|
||||
}
|
||||
|
||||
namespace BulletPointsColors
|
||||
{
|
||||
constexpr FLinearColor Normal(0.8f, 0.8f, 0.8f, 1.f);
|
||||
constexpr FLinearColor Disabled(0.8f, 0.8f, 0.8f, 0.2f);
|
||||
}
|
||||
|
||||
namespace TextColors
|
||||
{
|
||||
constexpr FLinearColor Normal(0.8f, 0.8f, 0.8f, 1.f);
|
||||
constexpr FLinearColor Disabled(0.8f, 0.8f, 0.8f, 0.2f);
|
||||
}
|
||||
|
||||
namespace Previews
|
||||
{
|
||||
constexpr FLinearColor Normal(0.8f, 0.8f, 0.8f, 0.05f);
|
||||
constexpr FLinearColor Invalid(0.8f, 0.8f, 0.8f, 0.2f);
|
||||
}
|
||||
}
|
||||
@ -1,257 +0,0 @@
|
||||
// ©2023 Batty Bovine Productions, LLC. All Rights Reserved.
|
||||
|
||||
#include "ComboActionGraphEditorUtilities.h"
|
||||
|
||||
#include "ComboActionGraph.h"
|
||||
#include "K2Node_Event.h"
|
||||
|
||||
#include "Ed/AssetEditor_ComboActionGraph.h"
|
||||
#include "Ed/EdComboActionGraph.h"
|
||||
#include "Ed/EdComboActionGraphNode.h"
|
||||
#include "Kismet2/BlueprintEditorUtils.h"
|
||||
#include "Kismet2/KismetEditorUtilities.h"
|
||||
#include "Kismet2/SClassPickerDialog.h"
|
||||
#include "Layout/AssetEditorTabs.h"
|
||||
|
||||
|
||||
bool FComboActionGraphEditorUtilities::PickChildrenOfClass(const FText &TitleText, UClass *&OutChosenClass, UClass *Class)
|
||||
{
|
||||
// Create filter
|
||||
TSharedPtr<FComboActionClassViewerFilter> Filter = MakeShareable(new FComboActionClassViewerFilter);
|
||||
Filter->AllowedChildrenOfClasses.Add(Class);
|
||||
|
||||
// Fill in options
|
||||
FClassViewerInitializationOptions Options;
|
||||
Options.Mode = EClassViewerMode::ClassPicker;
|
||||
Options.bShowUnloadedBlueprints = true;
|
||||
Options.ClassFilters.Add(Filter.ToSharedRef());
|
||||
|
||||
Options.DisplayMode = EClassViewerDisplayMode::TreeView;
|
||||
|
||||
Options.bShowNoneOption = false;
|
||||
Options.InitiallySelectedClass = Class;
|
||||
|
||||
Options.bExpandRootNodes = true;
|
||||
Options.NameTypeToDisplay = EClassViewerNameTypeToDisplay::DisplayName;
|
||||
|
||||
return SClassPickerDialog::PickClass(TitleText, Options, OutChosenClass, Class);
|
||||
}
|
||||
|
||||
bool FComboActionGraphEditorUtilities::OpenBlueprintEditor(UBlueprint *Blueprint, EComboActionBlueprintOpenType OpenType, FName FunctionNameToOpen, bool bForceFullEditor, bool bAddBlueprintFunctionIfItDoesNotExist)
|
||||
{
|
||||
if (!Blueprint)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Blueprint->bForceFullEditor = bForceFullEditor;
|
||||
|
||||
// Find Function Graph
|
||||
UObject *ObjectToFocusOn = nullptr;
|
||||
if (OpenType != EComboActionBlueprintOpenType::None && FunctionNameToOpen != NAME_None)
|
||||
{
|
||||
UClass* Class = Blueprint->GeneratedClass;
|
||||
check(Class);
|
||||
|
||||
if (OpenType == EComboActionBlueprintOpenType::Function)
|
||||
{
|
||||
ObjectToFocusOn = bAddBlueprintFunctionIfItDoesNotExist
|
||||
? FComboActionGraphEditorUtilities::BlueprintGetOrAddFunction(Blueprint, FunctionNameToOpen, Class)
|
||||
: FComboActionGraphEditorUtilities::BlueprintGetFunction(Blueprint, FunctionNameToOpen, Class);
|
||||
}
|
||||
else if (OpenType == EComboActionBlueprintOpenType::Event)
|
||||
{
|
||||
ObjectToFocusOn = bAddBlueprintFunctionIfItDoesNotExist
|
||||
? FComboActionGraphEditorUtilities::BlueprintGetOrAddEvent(Blueprint, FunctionNameToOpen, Class)
|
||||
: FComboActionGraphEditorUtilities::BlueprintGetEvent(Blueprint, FunctionNameToOpen, Class);
|
||||
}
|
||||
}
|
||||
|
||||
// Default to the last uber graph
|
||||
if (ObjectToFocusOn == nullptr)
|
||||
{
|
||||
ObjectToFocusOn = Blueprint->GetLastEditedUberGraph();
|
||||
}
|
||||
if (ObjectToFocusOn)
|
||||
{
|
||||
FKismetEditorUtilities::BringKismetToFocusAttentionOnObject(ObjectToFocusOn);
|
||||
return true;
|
||||
}
|
||||
|
||||
return FComboActionGraphEditorUtilities::OpenEditorForAsset(Blueprint);
|
||||
}
|
||||
|
||||
UEdGraph *FComboActionGraphEditorUtilities::BlueprintGetOrAddFunction(UBlueprint *Blueprint, FName FunctionName, UClass *FunctionClassSignature)
|
||||
{
|
||||
if (!Blueprint || Blueprint->BlueprintType != BPTYPE_Normal)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Find existing function
|
||||
if (UEdGraph *GraphFunction = BlueprintGetFunction(Blueprint, FunctionName, FunctionClassSignature))
|
||||
{
|
||||
return GraphFunction;
|
||||
}
|
||||
|
||||
// Create a new function
|
||||
UEdGraph *NewGraph = FBlueprintEditorUtils::CreateNewGraph(Blueprint, FunctionName, UEdGraph::StaticClass(), UEdGraphSchema_K2::StaticClass());
|
||||
FBlueprintEditorUtils::AddFunctionGraph(Blueprint, NewGraph, /*bIsUserCreated=*/ false, FunctionClassSignature);
|
||||
Blueprint->LastEditedDocuments.Add(NewGraph);
|
||||
return NewGraph;
|
||||
}
|
||||
|
||||
UEdGraph *FComboActionGraphEditorUtilities::BlueprintGetFunction(UBlueprint *Blueprint, FName FunctionName, UClass *FunctionClassSignature)
|
||||
{
|
||||
if (!Blueprint || Blueprint->BlueprintType != BPTYPE_Normal)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Find existing function
|
||||
for (UEdGraph *GraphFunction : Blueprint->FunctionGraphs)
|
||||
{
|
||||
if (FunctionName == GraphFunction->GetFName())
|
||||
{
|
||||
return GraphFunction;
|
||||
}
|
||||
}
|
||||
|
||||
// Find in the implemented Interfaces Graphs
|
||||
for (const FBPInterfaceDescription &Interface : Blueprint->ImplementedInterfaces)
|
||||
{
|
||||
for (UEdGraph *GraphFunction : Interface.Graphs)
|
||||
{
|
||||
if (FunctionName == GraphFunction->GetFName())
|
||||
{
|
||||
return GraphFunction;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
UK2Node_Event *FComboActionGraphEditorUtilities::BlueprintGetOrAddEvent(UBlueprint *Blueprint, FName EventName, UClass *EventClassSignature)
|
||||
{
|
||||
if (!Blueprint || Blueprint->BlueprintType != EBlueprintType::BPTYPE_Normal)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Find existing event
|
||||
if (UK2Node_Event *EventNode = FComboActionGraphEditorUtilities::BlueprintGetEvent(Blueprint, EventName, EventClassSignature))
|
||||
{
|
||||
return EventNode;
|
||||
}
|
||||
|
||||
// Create a New Event
|
||||
if (Blueprint->UbergraphPages.Num())
|
||||
{
|
||||
int32 NodePositionY = 0;
|
||||
UK2Node_Event* NodeEvent = FKismetEditorUtilities::AddDefaultEventNode(
|
||||
Blueprint,
|
||||
Blueprint->UbergraphPages[0],
|
||||
EventName,
|
||||
EventClassSignature,
|
||||
NodePositionY
|
||||
);
|
||||
NodeEvent->SetEnabledState(ENodeEnabledState::Enabled);
|
||||
NodeEvent->NodeComment = "";
|
||||
NodeEvent->bCommentBubbleVisible = false;
|
||||
return NodeEvent;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
UK2Node_Event *FComboActionGraphEditorUtilities::BlueprintGetEvent(UBlueprint *Blueprint, FName EventName, UClass *EventClassSignature)
|
||||
{
|
||||
if (!Blueprint || Blueprint->BlueprintType != EBlueprintType::BPTYPE_Normal)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
TArray<UK2Node_Event*> AllEvents;
|
||||
FBlueprintEditorUtils::GetAllNodesOfClass<UK2Node_Event>(Blueprint, AllEvents);
|
||||
for (UK2Node_Event *EventNode : AllEvents)
|
||||
{
|
||||
if (EventNode->bOverrideFunction && EventNode->EventReference.GetMemberName() == EventName)
|
||||
{
|
||||
return EventNode;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool FComboActionGraphEditorUtilities::OpenEditorForAsset(const UObject* Asset)
|
||||
{
|
||||
if (!IsValid(Asset) || !GEditor)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return GEditor->GetEditorSubsystem<UAssetEditorSubsystem>()->OpenEditorForAsset(const_cast<UObject*>(Asset));
|
||||
}
|
||||
|
||||
bool FComboActionGraphEditorUtilities::OpenEditorAndJumpToGraphNode(TWeakPtr<FAssetEditor_ComboActionGraph> DialogueEditorPtr, const UEdGraphNode *GraphNode, bool bFocusIfOpen)
|
||||
{
|
||||
if (!IsValid(GraphNode))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!DialogueEditorPtr.IsValid())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Open if not already.
|
||||
UComboActionGraph *Dialogue = FComboActionGraphEditorUtilities::GetActionFromGraphNode(GraphNode);
|
||||
if (!FComboActionGraphEditorUtilities::OpenEditorForAsset(Dialogue))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Could still fail focus on the graph node
|
||||
if (IAssetEditorInstance *EditorInstance = FindEditorForAsset(Dialogue, bFocusIfOpen))
|
||||
{
|
||||
EditorInstance->FocusWindow(const_cast<UEdGraphNode*>(GraphNode));
|
||||
|
||||
UEdComboActionGraph *GraphEditor = Cast<UEdComboActionGraph>(Dialogue->EdGraph);
|
||||
if (GraphEditor)
|
||||
{
|
||||
TSet<const UEdGraphNode*> SelectedNodes;
|
||||
SelectedNodes.Add(GraphNode);
|
||||
|
||||
GraphEditor->SelectNodeSet(SelectedNodes);
|
||||
DialogueEditorPtr.Pin()->JumpToNode(GraphNode);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
UComboActionGraph *FComboActionGraphEditorUtilities::GetActionFromGraphNode(const UEdGraphNode *GraphNode)
|
||||
{
|
||||
if (const UEdComboActionGraphNode *ComboActionBaseNode = Cast<UEdComboActionGraphNode>(GraphNode))
|
||||
{
|
||||
return ComboActionBaseNode->GetEdComboActionGraph()->GetComboActionGraph();
|
||||
}
|
||||
if (const UEdComboActionGraph *ComboActionGraph = Cast<UEdComboActionGraph>(GraphNode->GetGraph()))
|
||||
{
|
||||
return Cast<UComboActionGraph>(ComboActionGraph->GetComboActionGraph());
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
IAssetEditorInstance *FComboActionGraphEditorUtilities::FindEditorForAsset(UObject* Asset, bool bFocusIfOpen)
|
||||
{
|
||||
if (!IsValid(Asset) || !GEditor)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
return GEditor->GetEditorSubsystem<UAssetEditorSubsystem>()->FindEditorForAsset(Asset, bFocusIfOpen);
|
||||
}
|
||||
|
||||
@ -1,103 +0,0 @@
|
||||
// ©2023 Batty Bovine Productions, LLC. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ClassViewerFilter.h"
|
||||
|
||||
|
||||
enum class EComboActionBlueprintOpenType : uint8
|
||||
{
|
||||
None = 0,
|
||||
Function,
|
||||
Event
|
||||
};
|
||||
|
||||
class FComboActionClassViewerFilter : public IClassViewerFilter
|
||||
{
|
||||
public:
|
||||
// All children of these classes will be included unless filtered out by another setting.
|
||||
TSet<const UClass*> AllowedChildrenOfClasses;
|
||||
|
||||
virtual bool IsClassAllowed(const FClassViewerInitializationOptions &InInitOptions, const UClass *InClass, TSharedRef<FClassViewerFilterFuncs> InFilterFuncs) override
|
||||
{
|
||||
return !InClass->HasAnyClassFlags(this->DisallowedClassFlags)
|
||||
&& InFilterFuncs->IfInChildOfClassesSet(this->AllowedChildrenOfClasses, InClass) != EFilterReturn::Failed;
|
||||
}
|
||||
|
||||
virtual bool IsUnloadedClassAllowed(const FClassViewerInitializationOptions &InInitOptions, const TSharedRef<const IUnloadedBlueprintData> InUnloadedClassData, TSharedRef<FClassViewerFilterFuncs> InFilterFuncs) override
|
||||
{
|
||||
return !InUnloadedClassData->HasAnyClassFlags(this->DisallowedClassFlags)
|
||||
&& InFilterFuncs->IfInChildOfClassesSet(this->AllowedChildrenOfClasses, InUnloadedClassData) != EFilterReturn::Failed;
|
||||
}
|
||||
|
||||
private:
|
||||
// Disallowed class flags.
|
||||
EClassFlags DisallowedClassFlags = CLASS_Deprecated;
|
||||
};
|
||||
|
||||
class FComboActionGraphEditorUtilities
|
||||
{
|
||||
public:
|
||||
static bool PickChildrenOfClass(const FText &TitleText, UClass *&OutChosenClass, UClass *Class);
|
||||
static bool OpenBlueprintEditor
|
||||
(
|
||||
UBlueprint *Blueprint,
|
||||
EComboActionBlueprintOpenType OpenType = EComboActionBlueprintOpenType::None,
|
||||
FName FunctionNameToOpen = NAME_None,
|
||||
bool bForceFullEditor = true,
|
||||
bool bAddBlueprintFunctionIfItDoesNotExist = false
|
||||
);
|
||||
|
||||
static UEdGraph *BlueprintGetOrAddFunction(UBlueprint *Blueprint, FName FunctionName, UClass *FunctionClassSignature);
|
||||
|
||||
static UEdGraph *BlueprintGetFunction(UBlueprint *Blueprint, FName FunctionName, UClass *FunctionClassSignature);
|
||||
|
||||
static class UK2Node_Event *BlueprintGetOrAddEvent(UBlueprint *Blueprint, FName EventName, UClass *EventClassSignature);
|
||||
|
||||
static class UK2Node_Event *BlueprintGetEvent(UBlueprint *Blueprint, FName EventName, UClass *EventClassSignature);
|
||||
|
||||
static bool OpenEditorForAsset(const UObject *Asset);
|
||||
|
||||
static bool IsABlueprintClass(const UClass *Class) { return Cast<UBlueprintGeneratedClass>(Class) != nullptr; }
|
||||
|
||||
static bool GetAllChildClassesOf(const UClass *ParentClass, TArray<UClass*> &OutNativeClasses, TArray<UClass*> &OutBlueprintClasses)
|
||||
{
|
||||
// Iterate over UClass, this might be heavy on performance
|
||||
for (TObjectIterator<UClass> It; It; ++It)
|
||||
{
|
||||
UClass *ChildClass = *It;
|
||||
if (!ChildClass->IsChildOf(ParentClass))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// It is a child of the Parent Class
|
||||
// make sure we don't include our parent class in the array
|
||||
if (ChildClass == ParentClass)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (FComboActionGraphEditorUtilities::IsABlueprintClass(ChildClass))
|
||||
{
|
||||
// Blueprint
|
||||
OutBlueprintClasses.Add(ChildClass);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Native
|
||||
OutNativeClasses.Add(ChildClass);
|
||||
}
|
||||
}
|
||||
|
||||
return OutNativeClasses.Num() > 0 || OutBlueprintClasses.Num() > 0;
|
||||
}
|
||||
|
||||
static bool OpenEditorAndJumpToGraphNode(TWeakPtr<class FAssetEditor_ComboActionGraph> DialogueEditorPtr, const UEdGraphNode *GraphNode, bool bFocusIfOpen = false);
|
||||
|
||||
static class UComboActionGraph *GetActionFromGraphNode(const UEdGraphNode *GraphNode);
|
||||
|
||||
static IAssetEditorInstance *FindEditorForAsset(UObject *Asset, bool bFocusIfOpen);
|
||||
};
|
||||
|
||||
|
||||
@ -1,11 +0,0 @@
|
||||
// ©2023 Batty Bovine Productions, LLC. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
struct FAssetEditorTabs_ComboActionGraph
|
||||
{
|
||||
// Tab identifiers
|
||||
static const FName ComboActionGraphPropertyID;
|
||||
static const FName ViewportID;
|
||||
static const FName SearchToolbarID;
|
||||
};
|
||||
@ -1,166 +0,0 @@
|
||||
// All rights reserved Dominik Pavlicek 2023
|
||||
|
||||
|
||||
#include "Layout/ComboActionForceDirectedSolveLayoutStrategy.h"
|
||||
|
||||
#include "ComboActionGraph.h"
|
||||
#include "Ed/EdComboActionGraph.h"
|
||||
#include "Ed/EdComboActionGraphNode.h"
|
||||
#include "Nodes/ComboActionGraphNode.h"
|
||||
#include "Settings/ComboActionGraphEditorSettings.h"
|
||||
|
||||
UComboActionForceDirectedSolveLayoutStrategy::UComboActionForceDirectedSolveLayoutStrategy()
|
||||
{
|
||||
this->bRandomInit = false;
|
||||
this->CoolDownRate = 10;
|
||||
this->InitTemperature = 10.f;
|
||||
}
|
||||
|
||||
static inline float CoolDown(float Temp, float CoolDownRate)
|
||||
{
|
||||
if (Temp < .01) return .01;
|
||||
return Temp - (Temp / CoolDownRate);
|
||||
}
|
||||
|
||||
static inline float GetAttractForce(float X, float K)
|
||||
{
|
||||
return (X * X) / K;
|
||||
}
|
||||
|
||||
static inline float GetRepulseForce(float X, float k)
|
||||
{
|
||||
return X != 0 ? k * k / X : TNumericLimits<float>::Max();
|
||||
}
|
||||
|
||||
void UComboActionForceDirectedSolveLayoutStrategy::Layout(UEdGraph *InEdGraph)
|
||||
{
|
||||
this->EdGraph = Cast<UEdComboActionGraph>(InEdGraph);
|
||||
check(this->EdGraph != nullptr);
|
||||
|
||||
this->EdGraph->RebuildComboActionGraph();
|
||||
this->Graph = this->EdGraph->GetComboActionGraph();
|
||||
check(this->Graph != nullptr);
|
||||
|
||||
if (this->Settings != nullptr)
|
||||
{
|
||||
this->OptimalDistance = Settings->GetOptimalDistance();
|
||||
this->MaxIteration = Settings->GetMaxIteration();
|
||||
this->bRandomInit = Settings->IsRandomInit();
|
||||
}
|
||||
|
||||
FBox2D PreTreeBound(ForceInitToZero);
|
||||
for (int32 i = 0; i < Graph->RootNodes.Num(); ++i)
|
||||
{
|
||||
PreTreeBound = this->LayoutOneTree(Graph->RootNodes[i], PreTreeBound);
|
||||
}
|
||||
}
|
||||
|
||||
FBox2D UComboActionForceDirectedSolveLayoutStrategy::LayoutOneTree(UComboActionGraphNode *RootNode, const FBox2D &PreTreeBound)
|
||||
{
|
||||
float Temp = this->InitTemperature;
|
||||
FBox2D TreeBound = GetActualBounds(RootNode);
|
||||
TreeBound.Min.X += PreTreeBound.Max.X + this->OptimalDistance;
|
||||
TreeBound.Max.X += PreTreeBound.Max.X + this->OptimalDistance;
|
||||
|
||||
if (this->bRandomInit)
|
||||
{
|
||||
this->RandomLayoutOneTree(RootNode, TreeBound);
|
||||
}
|
||||
|
||||
float RepulseForce, AttractForce, Distance;
|
||||
FVector2D Diff;
|
||||
|
||||
TMap<UEdGraphNode*, FVector2D> NodeToDisplacement;
|
||||
|
||||
for (const TObjectPtr<UEdGraphNode> &EdNode : this->EdGraph->Nodes)
|
||||
{
|
||||
NodeToDisplacement.Add(EdNode, FVector2D(0.0f, 0.0f));
|
||||
}
|
||||
|
||||
for (int32 IterationNum = 0; IterationNum < this->MaxIteration; IterationNum++)
|
||||
{
|
||||
// Calculate the repulsive forces.
|
||||
for (int32 i = 0; i < this->EdGraph->Nodes.Num(); i++)
|
||||
{
|
||||
for (int32 j = 0; j < this->EdGraph->Nodes.Num(); j++)
|
||||
{
|
||||
if (i == j)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Diff.X = this->EdGraph->Nodes[i]->NodePosX - this->EdGraph->Nodes[j]->NodePosX;
|
||||
Diff.Y = this->EdGraph->Nodes[i]->NodePosY - this->EdGraph->Nodes[j]->NodePosY;
|
||||
Distance = Diff.Size();
|
||||
Diff.Normalize();
|
||||
|
||||
RepulseForce = Distance > 2 * this->OptimalDistance ? 0 : GetRepulseForce(Distance, this->OptimalDistance);
|
||||
|
||||
NodeToDisplacement[this->EdGraph->Nodes[i]] += Diff * RepulseForce;
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate the attractive forces.
|
||||
int Level = 0;
|
||||
TArray<UComboActionGraphNode*> CurrLevelNodes = { RootNode };
|
||||
TArray<UComboActionGraphNode*> NextLevelNodes;
|
||||
|
||||
while (CurrLevelNodes.Num() != 0)
|
||||
{
|
||||
for (int32 i = 0; i < CurrLevelNodes.Num(); i++)
|
||||
{
|
||||
UComboActionGraphNode *Node = CurrLevelNodes[i];
|
||||
check(Node != nullptr);
|
||||
|
||||
UEdComboActionGraphNode *EdNode_ParentNode = this->EdGraph->NodeMap[Node];
|
||||
|
||||
for (int32 j = 0; j < Node->ChildNodes.Num(); j++)
|
||||
{
|
||||
NextLevelNodes.Add(Node->ChildNodes[j]);
|
||||
|
||||
UEdComboActionGraphNode *EdNode_ChildNode = this->EdGraph->NodeMap[Node->ChildNodes[j]];
|
||||
|
||||
Diff.X = EdNode_ChildNode->NodePosX - EdNode_ParentNode->NodePosY;
|
||||
Diff.Y = EdNode_ChildNode->NodePosY - EdNode_ParentNode->NodePosY;
|
||||
Distance = Diff.Size();
|
||||
Diff.Normalize();
|
||||
|
||||
AttractForce = GetAttractForce(Distance, this->OptimalDistance);
|
||||
|
||||
NodeToDisplacement[EdNode_ParentNode] += Distance * Diff;
|
||||
NodeToDisplacement[EdNode_ChildNode] -= Distance * Diff;
|
||||
}
|
||||
}
|
||||
|
||||
CurrLevelNodes = NextLevelNodes;
|
||||
NextLevelNodes.Reset();
|
||||
Level++;
|
||||
}
|
||||
|
||||
for (UEdGraphNode *EdNode : this->EdGraph->Nodes)
|
||||
{
|
||||
Distance = NodeToDisplacement[EdNode].Size();
|
||||
NodeToDisplacement[EdNode].Normalize();
|
||||
|
||||
float Minimum = Distance < Temp ? Distance : Temp;
|
||||
EdNode->NodePosX += NodeToDisplacement[EdNode].X * Minimum;
|
||||
EdNode->NodePosY += NodeToDisplacement[EdNode].Y * Minimum;
|
||||
}
|
||||
|
||||
Temp = CoolDown(Temp, this->CoolDownRate);
|
||||
}
|
||||
|
||||
FBox2D ActualBound = GetActualBounds(RootNode);
|
||||
|
||||
FVector2D Center = ActualBound.GetCenter();
|
||||
FVector2D TreeCenter = TreeBound.GetCenter();
|
||||
|
||||
FVector2D Scale = (TreeBound.Max - TreeBound.Min) / (ActualBound.Max - ActualBound.Min);
|
||||
|
||||
for (UEdGraphNode *EdNode : EdGraph->Nodes)
|
||||
{
|
||||
EdNode->NodePosX = TreeCenter.X + Scale.X * (EdNode->NodePosX - Center.X);
|
||||
EdNode->NodePosY = TreeCenter.Y + Scale.Y * (EdNode->NodePosY - Center.Y);
|
||||
}
|
||||
|
||||
return TreeBound;
|
||||
}
|
||||
@ -1,30 +0,0 @@
|
||||
// All rights reserved Dominik Pavlicek 2023
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Layout/ComboActionGraphLayoutStrategy.h"
|
||||
#include "UObject/Object.h"
|
||||
|
||||
#include "ComboActionForceDirectedSolveLayoutStrategy.generated.h"
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
UCLASS()
|
||||
class COMBOINPUTEDITOR_API UComboActionForceDirectedSolveLayoutStrategy : public UComboActionGraphLayoutStrategy
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UComboActionForceDirectedSolveLayoutStrategy();
|
||||
|
||||
virtual void Layout(UEdGraph *EdGraph) override;
|
||||
|
||||
protected:
|
||||
virtual FBox2D LayoutOneTree(UComboActionGraphNode* RootNode, const FBox2D &PreTreeBound);
|
||||
|
||||
protected:
|
||||
bool bRandomInit;
|
||||
float InitTemperature;
|
||||
float CoolDownRate;
|
||||
};
|
||||
@ -1,95 +0,0 @@
|
||||
// ©2023 Batty Bovine Productions, LLC. All Rights Reserved.
|
||||
|
||||
#include "ComboActionGraphLayoutStrategy.h"
|
||||
|
||||
#include "Ed/EdComboActionGraph.h"
|
||||
#include "Ed/EdComboActionGraphNode.h"
|
||||
#include "Ed/SEdComboActionGraphNode.h"
|
||||
#include "Nodes/ComboActionGraphNode.h"
|
||||
|
||||
#include "Kismet/KismetMathLibrary.h"
|
||||
|
||||
|
||||
UComboActionGraphLayoutStrategy::UComboActionGraphLayoutStrategy()
|
||||
{
|
||||
Settings = nullptr;
|
||||
MaxIteration = 50;
|
||||
OptimalDistance = 150;
|
||||
}
|
||||
|
||||
int32 UComboActionGraphLayoutStrategy::GetNodeWidth(UEdComboActionGraphNode *EdNode)
|
||||
{
|
||||
return EdNode->SEdNode->GetCachedGeometry().GetLocalSize().X;
|
||||
}
|
||||
|
||||
int32 UComboActionGraphLayoutStrategy::GetNodeHeight(UEdComboActionGraphNode *EdNode)
|
||||
{
|
||||
return EdNode->SEdNode->GetCachedGeometry().GetLocalSize().Y;
|
||||
}
|
||||
|
||||
FBox2D UComboActionGraphLayoutStrategy::GetNodeBound(UEdGraphNode* EdNode)
|
||||
{
|
||||
int32 NodeWidth = GetNodeWidth(Cast<UEdComboActionGraphNode>(EdNode));
|
||||
int32 NodeHeight = GetNodeHeight(Cast<UEdComboActionGraphNode>(EdNode));
|
||||
FVector2D Min(EdNode->NodePosX, EdNode->NodePosY);
|
||||
FVector2D Max(EdNode->NodePosX + NodeWidth, EdNode->NodePosY + NodeHeight);
|
||||
return FBox2D(Min, Max);
|
||||
}
|
||||
|
||||
FBox2D UComboActionGraphLayoutStrategy::GetActualBounds(UComboActionGraphNode *RootNode)
|
||||
{
|
||||
int Level = 0;
|
||||
TArray<UComboActionGraphNode*> CurrLevelNodes = { RootNode };
|
||||
TArray<UComboActionGraphNode*> NextLevelNodes;
|
||||
|
||||
FBox2D Rtn = GetNodeBound(this->EdGraph->NodeMap[RootNode]);
|
||||
|
||||
while (CurrLevelNodes.Num() != 0)
|
||||
{
|
||||
for (const UComboActionGraphNode *Node : CurrLevelNodes)
|
||||
{
|
||||
check(Node != nullptr);
|
||||
|
||||
Rtn += GetNodeBound(this->EdGraph->NodeMap[Node]);
|
||||
|
||||
for (UComboActionGraphNode *ChildNode : Node->ChildNodes)
|
||||
{
|
||||
NextLevelNodes.Add(ChildNode);
|
||||
}
|
||||
}
|
||||
|
||||
CurrLevelNodes = NextLevelNodes;
|
||||
NextLevelNodes.Reset();
|
||||
++Level;
|
||||
}
|
||||
return Rtn;
|
||||
}
|
||||
|
||||
void UComboActionGraphLayoutStrategy::RandomLayoutOneTree(UComboActionGraphNode *RootNode, const FBox2D &Bound)
|
||||
{
|
||||
int Level = 0;
|
||||
TArray<UComboActionGraphNode*> CurrLevelNodes = { RootNode };
|
||||
TArray<UComboActionGraphNode*> NextLevelNodes;
|
||||
|
||||
while (CurrLevelNodes.Num() != 0)
|
||||
{
|
||||
for (const UComboActionGraphNode *Node : CurrLevelNodes)
|
||||
{
|
||||
check(Node != nullptr);
|
||||
|
||||
UEdComboActionGraphNode *EdNode_Node = this->EdGraph->NodeMap[Node];
|
||||
|
||||
EdNode_Node->NodePosX = UKismetMathLibrary::RandomFloatInRange(Bound.Min.X, Bound.Max.X);
|
||||
EdNode_Node->NodePosY = UKismetMathLibrary::RandomFloatInRange(Bound.Min.Y, Bound.Max.Y);
|
||||
|
||||
for (UComboActionGraphNode *ChildNode : Node->ChildNodes)
|
||||
{
|
||||
NextLevelNodes.Add(ChildNode);
|
||||
}
|
||||
}
|
||||
|
||||
CurrLevelNodes = NextLevelNodes;
|
||||
NextLevelNodes.Reset();
|
||||
++Level;
|
||||
}
|
||||
}
|
||||
@ -1,42 +0,0 @@
|
||||
// ©2023 Batty Bovine Productions, LLC. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "UObject/Object.h"
|
||||
|
||||
#include "ComboActionGraphLayoutStrategy.generated.h"
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
UCLASS(Abstract)
|
||||
class COMBOINPUTEDITOR_API UComboActionGraphLayoutStrategy : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
UComboActionGraphLayoutStrategy();
|
||||
|
||||
virtual void Layout(UEdGraph *G) {};
|
||||
|
||||
UComboActionGraphEditorSettings *Settings;
|
||||
|
||||
protected:
|
||||
int32 GetNodeWidth(UEdComboActionGraphNode *EdNode);
|
||||
|
||||
int32 GetNodeHeight(UEdComboActionGraphNode *EdNode);
|
||||
|
||||
FBox2D GetNodeBound(UEdGraphNode *EdNode);
|
||||
|
||||
FBox2D GetActualBounds(UComboActionGraphNode *RootNode);
|
||||
|
||||
virtual void RandomLayoutOneTree(UComboActionGraphNode *RootNode, const FBox2D &Bound);
|
||||
|
||||
protected:
|
||||
UComboActionGraph *Graph;
|
||||
UEdComboActionGraph *EdGraph;
|
||||
int32 MaxIteration;
|
||||
int32 OptimalDistance;
|
||||
};
|
||||