A Demo Project for the UnrealEngineSDK
Loading...
Searching...
No Matches
DlgMemory.h
Go to the documentation of this file.
1// Copyright Csaba Molnar, Daniel Butum. All Rights Reserved.
2#pragma once
3
4#include "CoreMinimal.h"
5
6#include "DlgMemory.generated.h"
7
8USTRUCT(BlueprintType)
9struct DLGSYSTEM_API FDlgHistory
10{
11 GENERATED_USTRUCT_BODY()
12public:
13 FDlgHistory() {}
15 void Add(int32 NodeIndex, const FGuid& NodeGUID)
16 {
17 if (NodeIndex >= 0)
18 {
19 VisitedNodeIndices.Add(NodeIndex);
20 }
21 if (NodeGUID.IsValid())
22 {
23 VisitedNodeGUIDs.Add(NodeGUID);
24 }
25 }
26
27 // The following scenarios will be present:
28 //
29 // ---------------------------------------------------------------------------------------
30 // A. Scenario
31 // - User has save files with only VisitedNodeIndices present
32 // - Developer does NOT resave the Dialogue files so that the Nodes don't have a valid GUID
33 //
34 // Result:
35 // The history will just use the Node Indices because the GUID will not be valid for any Node
36 //
37 // ---------------------------------------------------------------------------------------
38 // B. Scenario
39 // - User has save files with only the VisitedNodeIndices present
40 // - Developer DOES resave the Dialogue files so that the Nodes have a valid GUID
41 //
42 // Result:
43 // The history will still use the Node Indices to figure out if a Node Is Visited,
44 // even tho the Dialogue Nodes have a valid GUIDs we won't use those because the user save files
45 // has VisitedNodeGUIDs.Num() < VisitedNodeIndices.Num() (the user most likely has empty VisitedNodeGUIDs),
46 // because the way the history is constructed now the following is a requirement
47 // VisitedNodeGUIDs.Num() >= VisitedNodeIndices.Num(), if this is not met we just fallback to the Node Indices
48 //
49 // ---------------------------------------------------------------------------------------
50 // C. Scenario
51 // - User has save files with the VisitedNodeIndices present and some VisitedNodeGUIDs but not all of them,
52 // because he only got the new update after he played some time through the game
53 // - Developer DOES resave the Dialogue files so that the Nodes have a valid GUID and the game is in the users
54 // hands for some time for them to play.
55 //
56 // Result:
57 // Same as in Scenario B we will still use the Node Indices, because the requirement
58 // VisitedNodeGUIDs.Num() >= VisitedNodeIndices.Num() is NOT met
59 bool CanUseGUIDForSearch() const
60 {
61 return VisitedNodeGUIDs.Num() >= VisitedNodeIndices.Num();
62 }
63
64 bool Contains(int32 NodeIndex, const FGuid& NodeGUID) const
65 {
66 // Use GUID
67 if (CanUseGUIDForSearch() && NodeGUID.IsValid())
68 {
69 return VisitedNodeGUIDs.Contains(NodeGUID);
70 }
71
72 // FallBack to Node Index
73 return VisitedNodeIndices.Contains(NodeIndex);
74 }
75
76 bool operator==(const FDlgHistory& Other) const;
77
78public:
79 // Sed of already visited Node indices
80 // NOTE: if you serialize this but then later change the dialogue node positions this will have the wrong indices
81 // NOTE: You should use VisitedNodeGUIDs
82 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Dialogue|History")
83 TSet<int32> VisitedNodeIndices;
84
85 // Set of already visited node GUIDs
86 // This was added to fix Issue 30 (https://gitlab.com/NotYetGames/DlgSystem/-/issues/30)
87 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Dialogue|History")
88 TSet<FGuid> VisitedNodeGUIDs;
89};
91// Singleton to store Dialogue history
92// TODO: investigate if this is multiplayer friendly, it does not seem so as there exists only a single global dialogue memory
93USTRUCT()
94struct DLGSYSTEM_API FDlgMemory
95{
96 GENERATED_USTRUCT_BODY()
97public:
98 FDlgMemory() {}
99 static FDlgMemory* GetInstance()
100 {
101 static FDlgMemory Instance;
102 return &Instance;
103 }
104 static FDlgMemory& Get()
105 {
106 auto* Instance = GetInstance();
107 check(Instance != nullptr);
108 return *Instance;
110
111 // Removes all entries
112 void Empty() { HistoryMap.Empty(); }
113
114 // Adds an entry to the map or overrides an existing one
115 void SetEntry(const FGuid& DialogueGUID, const FDlgHistory& History)
116 {
117 FDlgHistory* OldEntry = HistoryMap.Find(DialogueGUID);
118
119 if (OldEntry == nullptr)
120 {
121 HistoryMap.Add(DialogueGUID, History);
122 }
123 else
124 {
125 *OldEntry = History;
126 }
127 }
129 // Returns the entry for the given name, or nullptr if it does not exist */
130 FDlgHistory* GetEntry(const FGuid& DialogueGUID) { return HistoryMap.Find(DialogueGUID); }
131
132 void SetNodeVisited(const FGuid& DialogueGUID, int32 NodeIndex, const FGuid& NodeGUID)
133 {
134 // Add it if it does not exist already
135 FDlgHistory* History = HistoryMap.Find(DialogueGUID);
136 if (History == nullptr)
137 {
138 History = &HistoryMap.Add(DialogueGUID);
139 }
140
141 History->Add(NodeIndex, NodeGUID);
142 }
144 bool IsNodeVisited(const FGuid& DialogueGUID, int32 NodeIndex, const FGuid& NodeGUID) const
146 // Dialogue entry does not even exist
147 const FDlgHistory* History = HistoryMap.Find(DialogueGUID);
148 if (History == nullptr)
149 {
150 return false;
151 }
152
153 return History->Contains(NodeIndex, NodeGUID);
154 }
155
156 bool IsNodeIndexVisited(const FGuid& DialogueGUID, int32 NodeIndex) const
158 // Dialogue entry does not even exist
159 const FDlgHistory* History = HistoryMap.Find(DialogueGUID);
160 if (History == nullptr)
161 {
162 return false;
163 }
164
165 return History->VisitedNodeIndices.Contains(NodeIndex);
166 }
167
168 bool IsNodeGUIDVisited(const FGuid& DialogueGUID, const FGuid& NodeGUID) const
170 // Dialogue entry does not even exist
171 const FDlgHistory* History = HistoryMap.Find(DialogueGUID);
172 if (History == nullptr)
173 {
174 return false;
175 }
176
177 return History->VisitedNodeGUIDs.Contains(NodeGUID);
178 }
179
180 const TMap<FGuid, FDlgHistory>& GetHistoryMaps() const { return HistoryMap; }
181 void SetHistoryMap(const TMap<FGuid, FDlgHistory>& Map) { HistoryMap = Map; }
182
183private:
184 // Key: Dialogue unique identifier GUID
185 // Value: set of already visited nodes
186 UPROPERTY()
187 TMap<FGuid, FDlgHistory> HistoryMap;
188};
189
190template<>
191struct TStructOpsTypeTraits<FDlgHistory> : public TStructOpsTypeTraitsBase2<FDlgHistory>
192{
193 enum
195 WithIdenticalViaEquality = true
196 };
197};
USTRUCT(BlueprintType)
Definition DlgMemory.h:13
TSet< FGuid > VisitedNodeGUIDs
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Dialogue|History")
Definition DlgMemory.h:99
void Add(int32 NodeIndex, const FGuid &NodeGUID)
Definition DlgMemory.h:18
bool Contains(int32 NodeIndex, const FGuid &NodeGUID) const
Definition DlgMemory.h:67
bool CanUseGUIDForSearch() const
Definition DlgMemory.h:62
TSet< int32 > VisitedNodeIndices
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Dialogue|History")
Definition DlgMemory.h:90
GENERATED_USTRUCT_BODY()
USTRUCT()
Definition DlgMemory.h:108
const TMap< FGuid, FDlgHistory > & GetHistoryMaps() const
Definition DlgMemory.h:193
void Empty()
Definition DlgMemory.h:125
void SetEntry(const FGuid &DialogueGUID, const FDlgHistory &History)
Definition DlgMemory.h:128
static FDlgMemory * GetInstance()
Definition DlgMemory.h:112
TMap< FGuid, FDlgHistory > HistoryMap
UPROPERTY()
Definition DlgMemory.h:202
bool IsNodeVisited(const FGuid &DialogueGUID, int32 NodeIndex, const FGuid &NodeGUID) const
Definition DlgMemory.h:157
bool IsNodeIndexVisited(const FGuid &DialogueGUID, int32 NodeIndex) const
Definition DlgMemory.h:169
bool IsNodeGUIDVisited(const FGuid &DialogueGUID, const FGuid &NodeGUID) const
Definition DlgMemory.h:181
void SetNodeVisited(const FGuid &DialogueGUID, int32 NodeIndex, const FGuid &NodeGUID)
Definition DlgMemory.h:145
GENERATED_USTRUCT_BODY()
void SetHistoryMap(const TMap< FGuid, FDlgHistory > &Map)
Definition DlgMemory.h:194
static FDlgMemory & Get()
Definition DlgMemory.h:117
FDlgHistory * GetEntry(const FGuid &DialogueGUID)
Definition DlgMemory.h:143