A Demo Project for the UnrealEngineSDK
Loading...
Searching...
No Matches
DialogueGraph.cpp
Go to the documentation of this file.
1// Copyright Csaba Molnar, Daniel Butum. All Rights Reserved.
2#include "DialogueGraph.h"
3
4#include "GraphEditAction.h"
5
6#include "DlgDialogue.h"
13
14UDialogueGraph::UDialogueGraph(const FObjectInitializer& ObjectInitializer)
15 : Super(ObjectInitializer)
16{
17 // Set the static editor module interface used by all the dialogues in the DlgSystem module to communicate with the editor.
18 if (!UDlgDialogue::GetDialogueEditorAccess().IsValid())
19 {
20 UDlgDialogue::SetDialogueEditorAccess(TSharedPtr<IDlgDialogueEditorAccess>(new FDlgDialogueEditorAccess));
21 }
22}
23
24bool UDialogueGraph::Modify(bool bAlwaysMarkDirty)
25{
26 if (!CanModify())
27 {
28 return false;
29 }
30
31 bool bWasSaved = Super::Modify(bAlwaysMarkDirty);
32 // Transactions do not support arrays?
33 // See https://answers.unrealengine.com/questions/674286/how-to-undoredo-a-modification-to-an-array.html?sort=oldest
34 // TODO check out why it does not save the arrays, because it uses the standard serializer that also writes to .uasset
35
36 // Mark all nodes for modification
37 // question of space (save them all here) or recompile them after every undo
39 {
40 bWasSaved = bWasSaved && BaseNode->Modify(bAlwaysMarkDirty);
41 }
42
43 return bWasSaved;
44}
45
47{
48 TArray<UDialogueGraphNode_Root*> RootNodeList;
49 GetNodesOfClass<UDialogueGraphNode_Root>(/*out*/ RootNodeList);
50 check(RootNodeList.Num() == 1);
51 return RootNodeList[0];
52}
53
54TArray<UDialogueGraphNode_Base*> UDialogueGraph::GetAllBaseDialogueGraphNodes() const
55{
56 TArray<UDialogueGraphNode_Base*> AllBaseDialogueGraphNodes;
57 GetNodesOfClass<UDialogueGraphNode_Base>(/*out*/ AllBaseDialogueGraphNodes);
58 return AllBaseDialogueGraphNodes;
59}
60
61TArray<UDialogueGraphNode*> UDialogueGraph::GetAllDialogueGraphNodes() const
62{
63 TArray<UDialogueGraphNode*> AllDialogueGraphNodes;
64 GetNodesOfClass<UDialogueGraphNode>(/*out*/ AllDialogueGraphNodes);
65 return AllDialogueGraphNodes;
66}
67
68TArray<UDialogueGraphNode_Edge*> UDialogueGraph::GetAllEdgeDialogueGraphNodes() const
69{
70 TArray<UDialogueGraphNode_Edge*> AllEdgeDialogueGraphNodes;
71 GetNodesOfClass<UDialogueGraphNode_Edge>(/*out*/ AllEdgeDialogueGraphNodes);
72 return AllEdgeDialogueGraphNodes;
73}
74
76{
77 Modify();
78 const int32 NumTimesNodeRemoved = Nodes.Remove(NodeToRemove);
79
80 // This will trigger the compile in the UDialogueGraphSchema::BreakNodeLinks
81 // NOTE: do not call BreakAllNodeLinks on the node as it does not register properly with the
82 // undo system
83 GetSchema()->BreakNodeLinks(*NodeToRemove);
84
85 // Notify
86 FEdGraphEditAction RemovalAction;
87 RemovalAction.Graph = this;
88 RemovalAction.Action = GRAPHACTION_RemoveNode;
89 RemovalAction.Nodes.Add(NodeToRemove);
90 NotifyGraphChanged(RemovalAction);
91
92 return NumTimesNodeRemoved > 0;
93}
94
96{
97 // Assume empty graph
98 check(Nodes.Num() == 0);
101
102 // Step 1: Create the root (start) node
103 {
104 FGraphNodeCreator<UDialogueGraphNode_Root> NodeCreator(*this);
105 UDialogueGraphNode_Root* StartGraphNode = NodeCreator.CreateNode();
106
107 // Create two way direction for both Dialogue Node and Graph Node.
108 UDlgNode* StartNode = Dialogue->GetMutableStartNode();
109 check(StartNode);
110
111 StartGraphNode->SetDialogueNode(StartNode);
112 Dialogue->SetStartNode(StartNode);
113
114 // Finalize creation
115 StartGraphNode->SetPosition(0, 0);
116 NodeCreator.Finalize();
117 }
118
119 // Step 2: Create the Graph Nodes for all the Nodes
120 const TArray<UDlgNode*>& DialogueNodes = Dialogue->GetNodes();
121 const int32 NodesNum = DialogueNodes.Num();
122 for (int32 NodeIndex = 0; NodeIndex < NodesNum; NodeIndex++)
123 {
124 FGraphNodeCreator<UDialogueGraphNode> NodeCreator(*this);
125 UDialogueGraphNode* GraphNode = NodeCreator.CreateNode();
126
127 // Create two way direction for both Dialogue Node and Graph Node.
128 GraphNode->SetDialogueNodeDataChecked(NodeIndex, DialogueNodes[NodeIndex]);
129
130 // Finalize creation
131 GraphNode->SetPosition(0, 0);
132 NodeCreator.Finalize();
133 }
134}
135
137{
138 UDialogueGraphNode_Root* StartNodeGraph = GetRootGraphNode();
140
141 // Assume we have all the nodes created (plus the start node)
143
144 const UDlgNode& StartNodeDialogue = Dialogue->GetStartNode();
145 const TArray<UDlgNode*>& NodesDialogue = Dialogue->GetNodes();
146 // Step 1. Make the root (start) node connections
147 LinkGraphNodeToChildren(NodesDialogue, StartNodeDialogue, StartNodeGraph);
148
149 // Step 2: Create all the connections between the rest of the nodes
150 for (UDlgNode* DialogueNode : NodesDialogue)
151 {
152 LinkGraphNodeToChildren(NodesDialogue, *DialogueNode, CastChecked<UDialogueGraphNode>(DialogueNode->GetGraphNode()));
153 }
154}
155
157 const TArray<UDlgNode*>& NodesDialogue,
158 const UDlgNode& NodeDialogue,
159 UDialogueGraphNode* GraphNode
160) const
161{
162 // Assume we are starting from scratch, no output connections
163 GraphNode->GetOutputPin()->BreakAllPinLinks();
164
165// UEdGraphPin* OutputPin = GraphNode->GetOutputPin();
166 const TArray<FDlgEdge>& NodeEdges = NodeDialogue.GetNodeChildren();
167 TSet<int32> NodeSeenEdges;
168 for (int32 ChildIndex = 0, ChildNum = NodeEdges.Num(); ChildIndex < ChildNum; ChildIndex++)
169 {
170 const int32 TargetIndex = NodeEdges[ChildIndex].TargetIndex;
171 // Ignore invalid edges
172 if (TargetIndex == INDEX_NONE)
173 {
174 continue;
175 }
176
177 // Prevent two edges to the same node.
178 if (NodeSeenEdges.Contains(TargetIndex))
179 {
180 continue;
181 }
182
183 // Get the child node and make sure it has the required number of inputs
184 const UDlgNode& ChildNode = *NodesDialogue[TargetIndex];
185 UDialogueGraphNode* ChildGraphNode = CastChecked<UDialogueGraphNode>(ChildNode.GetGraphNode());
186
187 // Make connection
188 UDialogueGraphNode_Edge* GraphNode_Edge =
189 FDialogueEditorUtilities::SpawnGraphNodeFromTemplate<UDialogueGraphNode_Edge>(
190 GraphNode->GetGraph(), GraphNode->GetDefaultEdgePosition(), false
191 );
192
193 // Create proxy connection from output -> input
194 GraphNode_Edge->CreateConnections(GraphNode, ChildGraphNode);
195 NodeSeenEdges.Add(TargetIndex);
196 }
197 GraphNode->CheckAll();
198 GraphNode->ApplyCompilerWarnings();
199}
200
202{
203 static constexpr bool bIsDirectionVertical = true;
205 const TArray<UDialogueGraphNode*> DialogueGraphNodes = GetAllDialogueGraphNodes();
206 const UDlgSystemSettings* Settings = GetDefault<UDlgSystemSettings>();
207
208 // TODO investigate Node->SnapToGrid
210 RootNode,
211 DialogueGraphNodes,
212 Settings->OffsetBetweenColumnsX,
213 Settings->OffsetBetweenRowsY,
214 bIsDirectionVertical
215 );
216}
217
219{
220 Modify();
221
222 // Could have used RemoveNode on each node but that is unecessary as that is slow and notifies external objects
223 Nodes.Empty();
224 check(Nodes.Num() == 0);
225}
226
228{
229 return GetDefault<UDialogueGraphSchema>(Schema);
230}
static bool AreDialogueNodesInSyncWithGraphNodes(const UDlgDialogue *Dialogue)
static bool CheckAndTryToFixDialogue(UDlgDialogue *Dialogue, bool bDisplayWarning=true)
static void AutoPositionGraphNodes(UDialogueGraphNode *RootNode, const TArray< UDialogueGraphNode * > &GraphNodes, int32 OffsetBetweenColumnsX, int32 OffsetBetweenRowsY, bool bIsDirectionVertical)
bool RemoveGraphNode(UEdGraphNode *NodeToRemove)
UDialogueGraph(const FObjectInitializer &ObjectInitializer)
UDlgDialogue * GetDialogue() const
void LinkGraphNodesFromDialogue() const
UDialogueGraphNode_Root * GetRootGraphNode() const
void LinkGraphNodeToChildren(const TArray< UDlgNode * > &NodesDialogue, const UDlgNode &NodeDialogue, UDialogueGraphNode *NodeGraph) const
bool Modify(bool bAlwaysMarkDirty=true) override
const UDialogueGraphSchema * GetDialogueGraphSchema() const
TArray< UDialogueGraphNode_Edge * > GetAllEdgeDialogueGraphNodes() const
void AutoPositionGraphNodes() const
TArray< UDialogueGraphNode_Base * > GetAllBaseDialogueGraphNodes() const
TArray< UDialogueGraphNode * > GetAllDialogueGraphNodes() const
void CreateGraphNodesFromDialogue()
UEdGraphPin * GetOutputPin() const
virtual void SetPosition(int32 X, int32 Y)
void CreateConnections(UDialogueGraphNode *ParentNode, UDialogueGraphNode *ChildNode)
void SetDialogueNodeDataChecked(int32 InIndex, UDlgNode *InNode)
virtual void SetDialogueNode(UDlgNode *InNode)
FIntPoint GetDefaultEdgePosition() const
void CheckAll() const override
UCLASS(BlueprintType, Meta = (DisplayThumbnail = "true"))
Definition DlgDialogue.h:85
UCLASS(BlueprintType, Abstract, EditInlineNew, ClassGroup = "Dialogue")
Definition DlgNode.h:40
virtual const TArray< FDlgEdge > & GetNodeChildren() const
Gets this nodes children (edges) as a const/mutable array.
Definition DlgNode.h:184
UCLASS(Config = Engine, DefaultConfig, meta = (DisplayName = "Dialogue System Settings"))
int32 OffsetBetweenColumnsX
UPROPERTY(Category = "Position", Config, EditAnywhere, AdvancedDisplay)
int32 OffsetBetweenRowsY
UPROPERTY(Category = "Position", Config, EditAnywhere, AdvancedDisplay)