4#include "Editor/EditorEngine.h"
5#include "Framework/Commands/GenericCommands.h"
6#include "EdGraph/EdGraphNode.h"
7#include "Engine/Font.h"
8#include "Framework/MultiBox/MultiBoxBuilder.h"
10#if ENGINE_MINOR_VERSION >= 24
20#define LOCTEXT_NAMESPACE "DialogueGraphNode"
47 Super::PostEditChangeProperty(PropertyChangedEvent);
48 if (!PropertyChangedEvent.Property)
59 Super::PostEditChangeChainProperty(PropertyChangedEvent);
69 bool bWasModified = Super::Modify(bAlwaysMarkDirty);
74 bWasModified = bWasModified &&
DialogueNode->Modify(bAlwaysMarkDirty);
81 constexpr bool bCheckParent =
false;
84 bWasModified = bWasModified && EdgeNode->SuperModify();
99 return Super::GetNodeTitle(TitleType);
104 return FText::FromString(FullString);
109 Super::PrepareForCopying();
114 DialogueNode->Rename(
nullptr,
this, REN_DontCreateRedirectors);
120 Super::PostCopyNode();
136 FFormatNamedArguments Args;
138 Args.Add(TEXT(
"NodeType"),
DialogueNode ? FText::FromString(
DialogueNode->GetNodeTypeString()) : FText::GetEmpty());
140 return FText::Format(LOCTEXT(
"GraphNodeTooltip",
"ParticipantName = {ParticipantName}\nType = {NodeType}\n{Description}"), Args);
146 check(Pin->GetOwningNode() ==
this);
150 if (Pin->Direction == EGPD_Input)
156 check(Pin->Direction == EGPD_Output);
159 check(Pin == OutputPin);
162 const int32 GraphNodeChildrenNum = OutputPin->LinkedTo.Num();
165 if (DialogueNodeChildrenNum == GraphNodeChildrenNum)
169 check(DiffResult.
Index == INDEX_NONE);
174 else if (DialogueNodeChildrenNum < GraphNodeChildrenNum)
183 check(DialogueNodeChildrenNum > GraphNodeChildrenNum);
184 if (GraphNodeChildrenNum == 0)
200#if ENGINE_MINOR_VERSION >= 24
201void UDialogueGraphNode::GetNodeContextMenuActions(UToolMenu* Menu, UGraphNodeContextMenuContext* Context)
const
204 if (Context->Node && !Context->bIsDebugging && !
IsRootNode())
207 FToolMenuSection& Section = Menu->AddSection(
"DialogueGraphNode_BaseNodeEditCRUD");
210 Section.AddMenuEntry(FDialogueCommands::Get().ConvertSpeechSequenceNodeToSpeechNodes);
215 Section.AddMenuEntry(FDialogueCommands::Get().ConvertSpeechNodesToSpeechSequence);
218 Section.AddMenuEntry(FGenericCommands::Get().Delete);
220 Section.AddMenuEntry(FGenericCommands::Get().Copy);
231 if (Context.Node && !Context.bIsDebugging && !
IsRootNode())
234 Context.MenuBuilder->BeginSection(
"DialogueGraphNode_BaseNodeEditCRUD");
238 Context.MenuBuilder->AddMenuEntry(FDialogueCommands::Get().ConvertSpeechSequenceNodeToSpeechNodes);
243 Context.MenuBuilder->AddMenuEntry(FDialogueCommands::Get().ConvertSpeechNodesToSpeechSequence);
246 Context.MenuBuilder->AddMenuEntry(FGenericCommands::Get().Delete);
248 Context.MenuBuilder->AddMenuEntry(FGenericCommands::Get().Copy);
251 Context.MenuBuilder->EndSection();
259 if (FromPin ==
nullptr)
265 check(FromPin->GetOwningNode() !=
this);
266 check(FromPin->Direction == EGPD_Output);
273 FromPin->GetOwningNode()->NodeConnectionListChanged();
284 return FLinearColor::Black;
324 return FLinearColor::Black;
331 if (ChildNode == TargetNode)
342 Super::RegisterListeners();
366 for (
const FDlgSpeechSequenceEntry & Sequence : GetDialogueNode<UDlgNode_SpeechSequence>().GetNodeSpeechSequence())
368 if (Sequence.VoiceSoundWave !=
nullptr || Sequence.VoiceDialogueWave !=
nullptr)
394 for (
const FDlgSpeechSequenceEntry & Sequence : GetDialogueNode<UDlgNode_SpeechSequence>().GetNodeSpeechSequence())
396 if (Sequence.GenericData !=
nullptr)
409 checkf(
Dialogue->GetNodes()[InIndex] == InNode, TEXT(
"The selected index = %d and with the Node provided does not match the Node from the Dialogue"), InIndex);
418 for (int32 EdgeIndex = 0; EdgeIndex < GraphNodeEdges.Num(); EdgeIndex++)
437 check(NewTargetIndex > INDEX_NONE);
440 check(GraphNodeEdges.IsValidIndex(EdgeIndex));
443 GraphNodeEdges[EdgeIndex]->SetDialogueEdgeTargetIndex(NewTargetIndex);
450 check(GraphNodeEdges.IsValidIndex(EdgeIndex));
454 GraphNodeEdges[EdgeIndex]->SetDialogueEdgeText(NewText);
460 check(InEdges.Num() == GraphNodeEdges.Num());
466 for (int32 EdgeIndex = 0, EdgesNum = InEdges.Num(); EdgeIndex < EdgesNum; EdgeIndex++)
468 GraphNodeEdges[EdgeIndex]->SetDialogueEdge(InEdges[EdgeIndex]);
476 check(NumEdges == GraphNodeEdges.Num());
478 for (int32 EdgeIndex = 0; EdgeIndex < NumEdges; EdgeIndex++)
502 constexpr int32 EstimatedCharWidth = 6;
504 const FString NodeTitle =
GetNodeTitle(ENodeTitleType::FullTitle).ToString();
508 FString ResultFromString;
509 if (NodeTitle.Len() > NodeText.Len())
511 Result = NodeTitle.Len() * EstimatedCharWidth;
512 ResultFromString = NodeTitle;
516 Result = NodeText.Len() * EstimatedCharWidth;
517 ResultFromString = NodeText;
520 if (
const UFont* Font = GetDefault<UEditorEngine>()->EditorFont)
522 Result = Font->GetStringSize(*ResultFromString);
544 const int32 EdgesNum = NodeEdges.Num();
545 const int32 PinsLinkedToNum = OutputPin->LinkedTo.Num();
548 EdgesNum == PinsLinkedToNum,
549 TEXT(
"The node with OLD index = %d does not have the number of PinsLinkedToNum (%d) equal to the EdgesNum (%d) in it's FDlgNode (DialogueNode)"),
556 TEXT(
"The node with OLD index = %d has open output pins (%d), this should not be allowed"),
562 TEXT(
"The node with OLD index = %d does not have the DialogueNode.GraphNode == this (graph node)"),
569 for (int32 EdgeIndex = 0; EdgeIndex < EdgesNum; EdgeIndex++)
572 const FDlgEdge& Edge = NodeEdges[EdgeIndex];
577 TEXT(
"The node with OLD index = %d does not have the dialogue edge at index = %d matching the Edge in the GraphNode. Error message = `%s`"),
589 TArray<UDialogueGraphNode*> ParentNodes;
592 ParentNodes.Add(ParentEdgeConnection->GetParentNode());
601 TArray<UDialogueGraphNode*> ChildNodes;
604 ChildNodes.Add(ChildEdgeConnection->GetChildNode());
613 TArray<UDialogueGraphNode_Edge*> ParentEdgeNodes;
614 for (
const UEdGraphPin* EdgeOutputPin :
GetInputPin()->LinkedTo)
616 UDialogueGraphNode_Edge* ParentEdgeConnection = CastChecked<UDialogueGraphNode_Edge>(EdgeOutputPin->GetOwningNode());
625 ParentEdgeNodes.Add(ParentEdgeConnection);
628 return ParentEdgeNodes;
634 TArray<UDialogueGraphNode_Edge*> ChildEdgeNodes;
635 for (
const UEdGraphPin* EdgeInputPin :
GetOutputPin()->LinkedTo)
637 UDialogueGraphNode_Edge* ChildEdgeConnection = CastChecked<UDialogueGraphNode_Edge>(EdgeInputPin->GetOwningNode());
646 ChildEdgeNodes.Add(ChildEdgeConnection);
649 return ChildEdgeNodes;
660 for (
const UEdGraphPin* EdgeInputPin :
GetOutputPin()->LinkedTo)
662 if (
const UDialogueGraphNode_Edge* ChildEdgeConnection = Cast<UDialogueGraphNode_Edge>(EdgeInputPin->GetOwningNodeUnchecked()))
664 if (ChildEdgeToFind == ChildEdgeConnection)
682 for (
const UEdGraphPin* EdgeOutputPin :
GetInputPin()->LinkedTo)
684 if (
const UDialogueGraphNode_Edge* ParentEdgeConnection = Cast<UDialogueGraphNode_Edge>(EdgeOutputPin->GetOwningNodeUnchecked()))
686 if (ParentEdgeToFind == ParentEdgeConnection)
698 FORCEINLINE
bool operator()(
const TPair<UEdGraphPin*, FDlgEdge>& A,
const TPair<UEdGraphPin*, FDlgEdge>& B)
const
702 return NodeA->NodePosX != NodeB->NodePosX ? NodeA->NodePosX < NodeB->NodePosX : NodeA->NodePosY < NodeB->NodePosY;
709 TArray<TPair<UEdGraphPin*, FDlgEdge>> SyncedArray;
712 const TArray<UEdGraphPin*> ChildPins = OutputPin->LinkedTo;
714 check(ChildPins.Num() == ChildDialogueNodeEdges.Num());
717 const int32 ChildrenNum = ChildPins.Num();
718 SyncedArray.Reserve(ChildrenNum);
719 for (int32 ChildIndex = 0; ChildIndex < ChildrenNum; ChildIndex++)
721 SyncedArray.Emplace(ChildPins[ChildIndex], ChildDialogueNodeEdges[ChildIndex]);
728 OutputPin->LinkedTo.Empty();
730 for (
const TPair<UEdGraphPin*, FDlgEdge>& SyncedPair : SyncedArray)
732 OutputPin->LinkedTo.Add(SyncedPair.Key);
739 if (!PropertyChangedEvent.Property)
746 if (EdgeIndexChanged != INDEX_NONE)
750 check(ChildEdgeNodes.IsValidIndex(EdgeIndexChanged))
753 ChildEdgeNodes[EdgeIndexChanged]->SetDialogueEdge(DialogueEdges[EdgeIndexChanged]);
759 for (int32 EdgeIndex = 0, EdgesNum = ChildEdgeNodes.Num(); EdgeIndex < EdgesNum; EdgeIndex++)
762 ChildEdgeNodes[EdgeIndex]->SetDialogueEdge(DialogueEdges[EdgeIndex]);
791 const TArray<FDlgEdge>& NodeEdges =
GetDialogueNode().GetNodeChildren();
792 const int32 EdgesNum = NodeEdges.Num();
793 const int32 LinkedToNum = OutputPin->LinkedTo.Num();
794 const bool bAreLengthsEqual = EdgesNum == LinkedToNum;
798 if (!bAreLengthsEqual && FMath::Abs(EdgesNum - LinkedToNum) != 1)
800 UE_LOG(LogDlgSystemEditor,
Error,
801 TEXT(
"FindDifferenceBetweenNodeEdgesAndLinkedToPins: EdgesNum (%d) != LinkedToNum (%d), but function was called in the wrong context"),
802 EdgesNum, LinkedToNum);
808 for (int32 Index = 0; Index < EdgesNum && Index < LinkedToNum; Index++)
810 const FDlgEdge& Edge = NodeEdges[Index];
813 Result.
Index = Index;
817 if (Index + 1 < EdgesNum && Index + 1 < LinkedToNum)
828 if (!bAreLengthsEqual && Result.
Index == INDEX_NONE)
830 if (LinkedToNum > EdgesNum)
833 Result.
Index = LinkedToNum - 1;
838 check(EdgesNum > LinkedToNum);
840 Result.
Index = EdgesNum - 1;
853 if (!ThisOutputPin->LinkedTo.IsValidIndex(EdgeIndex))
855 OutMessage = FString::Printf(TEXT(
"The provided EdgeIndex = %d is not a valid index in the ThisOutputPin->LinkedTo Array"), EdgeIndex);
860 const UEdGraphPin* EdgeInputPin = ThisOutputPin->LinkedTo[EdgeIndex];
861 check(EdgeInputPin->Direction == EGPD_Input);
864 const UDialogueGraphNode_Edge* ChildEdgeConnection = CastChecked<UDialogueGraphNode_Edge>(EdgeInputPin->GetOwningNode());
866 check(ChildNode !=
this);
871 OutMessage = TEXT(
"The provided Edge does not match the ChildEdgeConnection.Edge");
878 OutMessage = FString::Printf(
879 TEXT(
"The provided Edge.TargetIndex = %d is DIFFERENT from the ChildNode.NodeIndex = %d"),
890#undef LOCTEXT_NAMESPACE
static bool CanConvertSpeechNodesToSpeechSequence(const TSet< UObject * > &SelectedNodes, TArray< UDialogueGraphNode * > &OutSelectedGraphNodes)
static const TSet< UObject * > GetSelectedNodes(const UEdGraph *Graph)
void SetCompilerWarningMessage(FString Message)
bool HasOutputPin() const
void ClearCompilerMessage()
UDlgDialogue * GetDialogue() const
UEdGraphPin * GetOutputPin() const
const UDialogueGraphSchema * GetDialogueGraphSchema() const
UEdGraphPin * GetInputPin() const
UDialogueGraphNode * GetChildNode() const
bool HasChildNode() const
const FDlgEdge & GetDialogueEdge() const
UDialogueGraphNode * GetParentNode() const
void CheckDialogueNodeIndexMatchesNode() const
int32 EstimateNodeWidth() const
bool HasParentEdgeNode(const UDialogueGraphNode_Edge *ParentEdgeToFind) const
void UpdateEdgesFromDialogueNode()
bool DoesEdgeMatchEdgeIndex(const FDlgEdge &Edge, int32 EdgeIndex, FString &OutMessage) const
void SortChildrenBasedOnXLocation()
void PinConnectionListChanged(UEdGraphPin *Pin) override
void SetDialogueNodeDataChecked(int32 InIndex, UDlgNode *InNode)
virtual int32 GetDialogueNodeIndex() const
bool IsSelectorNode() const
void CheckDialogueNodeSyncWithGraphNode(bool bStrictCheck=false) const
void AutowireNewNode(UEdGraphPin *FromPin) override
virtual void SetDialogueNode(UDlgNode *InNode)
int32 GetChildEdgeIndexForChildNodeIndex(int32 ChildNodeIndex) const
void SetEdgeTextAt(int32 EdgeIndex, const FText &NewText)
TArray< UDialogueGraphNode * > GetChildNodes() const
bool HasVoicePropertiesSet() const
bool IsSelectorFirstNode() const
void OnDialogueNodePropertyChanged(const FPropertyChangedEvent &PropertyChangedEvent, int32 EdgeIndexChanged)
bool HasChildEdgeNode(const UDialogueGraphNode_Edge *ChildEdgeToFind) const
TArray< UDialogueGraphNode * > GetParentNodes() const
virtual void SetDialogueNodeIndex(int32 InIndex)
FLinearColor GetNodeBackgroundColor() const override
int32 NodeIndex
UPROPERTY(VisibleAnywhere, Category = DialogueGraphNode)
bool HasOutputConnectionToNode(const UEdGraphNode *TargetNode) const override
bool IsVirtualParentNode() const
bool HasGenericDataSet() const
const DlgNodeType & GetDialogueNode() const
void CheckAll() const override
void PostEditChangeProperty(FPropertyChangedEvent &PropertyChangedEvent) override
void RegisterListeners() override
void PostCopyNode() override
virtual bool IsRootNode() const
TArray< UDialogueGraphNode_Edge * > GetChildEdgeNodes(bool bCheckParent=true) const
void PostEditImport() override
void ResetDialogueNodeOwner()
bool IsSelectorRandomNode() const
TArray< UDialogueGraphNode_Edge * > GetParentEdgeNodes(bool bCheckChild=true) const
FText GetNodeTitle(ENodeTitleType::Type TitleType) const override
void GetContextMenuActions(const FGraphNodeContextMenuBuilder &Context) const override
void PostEditChangeChainProperty(struct FPropertyChangedChainEvent &PropertyChangedEvent) override
const FDiffNodeEdgeLinkedToPinResult FindDifferenceBetweenNodeEdgesAndLinkedToPins() const
bool IsSpeechNode() const
UDlgNode * DialogueNode
UPROPERTY(EditAnywhere, Instanced, Category = DialogueGraphNode, Meta = (ShowOnlyInnerProperties))
bool IsSpeechSequenceNode() const
bool Modify(bool bAlwaysMarkDirty=true) override
FString GetDocumentationExcerptName() const override
void PrepareForCopying() override
void ApplyCompilerWarnings()
FText GetTooltipText() const override
void SetEdgeTargetIndexAt(int32 EdgeIndex, int32 NewTargetIndex)
void SetEdges(const TArray< FDlgEdge > &InEdges)
bool TryCreateConnection(UEdGraphPin *PinA, UEdGraphPin *PinB) const override
UCLASS(BlueprintType, Meta = (DisplayThumbnail = "true"))
UCLASS(BlueprintType, Abstract, EditInlineNew, ClassGroup = "Dialogue")
virtual const FText & GetNodeText() const
UFUNCTION(BlueprintPure, Category = "Dialogue|Node")
USoundWave * GetNodeVoiceSoundWave() const
UFUNCTION(BlueprintPure, Category = "Dialogue|Node")
virtual FDlgEdge * GetSafeMutableNodeChildAt(int32 EdgeIndex)
const TArray< int32 > GetNodeOpenChildren_DEPRECATED() const
FDialogueNodePropertyChanged OnDialogueNodePropertyChanged
virtual const TArray< FDlgEdge > & GetNodeChildren() const
Gets this nodes children (edges) as a const/mutable array.
virtual int32 GetNumNodeChildren() const
UFUNCTION(BlueprintPure, Category = "Dialogue|Node")
virtual FName GetNodeParticipantName() const
UFUNCTION(BlueprintPure, Category = "Dialogue|Node")
virtual const FDlgEdge & GetNodeChildAt(int32 EdgeIndex) const
UFUNCTION(BlueprintPure, Category = "Dialogue|Node")
virtual void RemoveChildAt(int32 EdgeIndex)
virtual UObject * GetNodeGenericData() const
UFUNCTION(BlueprintPure, Category = "Dialogue|Node")
FString GetDesc() override
virtual UDialogueWave * GetNodeVoiceDialogueWave() const
UFUNCTION(BlueprintPure, Category = "Dialogue|Node")
virtual void AddNodeChild(const FDlgEdge &InChild)
virtual void SetNodeChildren(const TArray< FDlgEdge > &InChildren)
virtual void RemoveAllChildren()
UCLASS(Config = Engine, DefaultConfig, meta = (DisplayName = "Dialogue System Settings"))
FLinearColor SelectorFirstNodeColor
UPROPERTY(Category = "Graph Node Color", Config, EditAnywhere)
FLinearColor EndNodeColor
UPROPERTY(Category = "Graph Node Color", Config, EditAnywhere)
FLinearColor SpeechSequenceNodeColor
UPROPERTY(Category = "Graph Node Color", Config, EditAnywhere)
FLinearColor VirtualParentNodeColor
UPROPERTY(Category = "Graph Node Color", Config, EditAnywhere)
FLinearColor SelectorRandomNodeColor
UPROPERTY(Category = "Graph Node Color", Config, EditAnywhere)
FLinearColor SpeechNodeColor
UPROPERTY(Category = "Graph Node Color", Config, EditAnywhere)
FORCEINLINE bool operator()(const TPair< UEdGraphPin *, FDlgEdge > &A, const TPair< UEdGraphPin *, FDlgEdge > &B) const
@ EDGE_NOT_MATCHING_INDEX
@ LENGTH_MISMATCH_ONE_MORE_EDGE
@ LENGTH_MISMATCH_ONE_MORE_PIN_CONNECTION
int32 TargetIndex
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "Dialogue|Edge", Meta = (ClampMin = -1))
void SetText(const FText &NewText)