A Demo Project for the UnrealEngineSDK
Loading...
Searching...
No Matches
DlgSystemModule.cpp
Go to the documentation of this file.
1// Copyright Csaba Molnar, Daniel Butum. All Rights Reserved.
2#include "DlgSystemModule.h"
3
4#include "Modules/ModuleManager.h"
5#include "AssetRegistryModule.h"
6#include "Framework/Docking/TabManager.h"
7#include "Widgets/Docking/SDockTab.h"
8#include "HAL/IConsoleManager.h"
9#include "HAL/FileManager.h"
10#include "GameFramework/Actor.h"
11
12#if WITH_GAMEPLAY_DEBUGGER
13#include "GameplayDebugger.h"
14#endif // WITH_GAMEPLAY_DEBUGGER
15#if WITH_EDITOR
16#include "WorkspaceMenuStructureModule.h"
17#include "WorkspaceMenuStructure.h"
18#endif // WITH_EDITOR
19
20#include "DlgConstants.h"
21#include "DlgManager.h"
22#include "DlgDialogue.h"
25#include "Logging/DlgLogger.h"
26#include "DlgHelper.h"
27
28#define LOCTEXT_NAMESPACE "FDlgSystemModule"
29
31DEFINE_LOG_CATEGORY(LogDlgSystem)
33
34void FDlgSystemModule::StartupModule()
35{
37
38 // This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module
39 FDlgLogger::Get().Info(TEXT("DlgSystemModule: StartupModule"));
40
41 OnPreLoadMapHandle = FCoreUObjectDelegates::PreLoadMap.AddRaw(this, &Self::HandleOnPreLoadMap);
42 OnPostLoadMapWithWorldHandle = FCoreUObjectDelegates::PostLoadMapWithWorld.AddRaw(this, &Self::HandleOnPostLoadMapWithWorld);
43
44 // Listen for deleted assets
45 // Maybe even check OnAssetRemoved if not loaded into memory?
46 IAssetRegistry& AssetRegistry = FModuleManager::LoadModuleChecked<FAssetRegistryModule>(NAME_MODULE_AssetRegistry).Get();
47 OnInMemoryAssetDeletedHandle = AssetRegistry.OnInMemoryAssetDeleted().AddRaw(this, &Self::HandleOnInMemoryAssetDeleted);
48 // NOTE: this seems to be the same as the OnInMemoryAssetDeleted as they are called from the same method inside
49 // the asset registry.
50 OnAssetRemovedHandle = AssetRegistry.OnAssetRemoved().AddRaw(this, &Self::HandleOnAssetRemoved);
51 OnAssetRenamedHandle = AssetRegistry.OnAssetRenamed().AddRaw(this, &Self::HandleOnAssetRenamed);
52
53#if WITH_GAMEPLAY_DEBUGGER
54 // If the gameplay debugger is available, register the category and notify the editor about the changes
55 IGameplayDebugger& GameplayDebuggerModule = IGameplayDebugger::Get();
56 GameplayDebuggerModule.RegisterCategory(
58 IGameplayDebugger::FOnGetCategory::CreateStatic(&FDlgGameplayDebuggerCategory::MakeInstance),
59 EGameplayDebuggerCategoryState::EnabledInGameAndSimulate
60 );
61 GameplayDebuggerModule.NotifyCategoriesChanged();
62#endif // WITH_GAMEPLAY_DEBUGGER
63
64 // Register tab spawners
65 bHasRegisteredTabSpawners = true;
66
67 DialogueDataDisplayTabSpawnEntry = &FGlobalTabmanager::Get()->RegisterNomadTabSpawner(
69 FOnSpawnTab::CreateLambda([this](const FSpawnTabArgs& Args) -> TSharedRef<SDockTab>
70 {
71 TSharedRef<SDockTab> DialogueDataDisplayTab = SNew(SDockTab)
72 .TabRole(ETabRole::NomadTab)
73 [
74 GetDialogueDataDisplayWindow()
75 ];
76 return DialogueDataDisplayTab;
77 }))
78 .SetDisplayName(LOCTEXT("DialogueDataDisplayTitle", "Dialogue Data Display"))
79 .SetTooltipText(LOCTEXT("DialogueDataDisplayTooltipText", "Open the Dialogue Data Display tab.")
80 );
81}
82
84{
85 // Unregister the console commands in case the user forgot to clear them
87
88 // Unregister the tab spawners
90 FGlobalTabmanager::Get()->UnregisterTabSpawner(DIALOGUE_DATA_DISPLAY_TAB_ID);
91
92#if WITH_GAMEPLAY_DEBUGGER
93 // If the gameplay debugger is available, unregister the category
94 if (IGameplayDebugger::IsAvailable())
95 {
96 IGameplayDebugger& GameplayDebuggerModule = IGameplayDebugger::Get();
97 GameplayDebuggerModule.UnregisterCategory(DIALOGUE_SYSTEM_PLUGIN_NAME);
98 GameplayDebuggerModule.NotifyCategoriesChanged();
99 }
100#endif // WITH_GAMEPLAY_DEBUGGER
101
102 // This function may be called during shutdown to clean up your module. For modules that support dynamic reloading,
103 // we call this function before unloading the module.
104 const FModuleManager& ModuleManger = FModuleManager::Get();
105
106 // Unregister the the asset registry delete listeners
107 if (ModuleManger.IsModuleLoaded(NAME_MODULE_AssetRegistry))
108 {
109 IAssetRegistry& AssetRegistry = FModuleManager::LoadModuleChecked<FAssetRegistryModule>(NAME_MODULE_AssetRegistry).Get();
110 if (OnInMemoryAssetDeletedHandle.IsValid())
111 {
112 AssetRegistry.OnInMemoryAssetDeleted().Remove(OnInMemoryAssetDeletedHandle);
113 }
114 if (OnAssetRemovedHandle.IsValid())
115 {
116 AssetRegistry.OnAssetRemoved().Remove(OnAssetRemovedHandle);
117 }
118 if (OnAssetRenamedHandle.IsValid())
119 {
120 AssetRegistry.OnAssetRenamed().Remove(OnAssetRenamedHandle);
121 }
122 }
123
124 if (OnPreLoadMapHandle.IsValid())
125 {
126 FCoreUObjectDelegates::PreLoadMap.Remove(OnPreLoadMapHandle);
127 }
128 if (OnPostLoadMapWithWorldHandle.IsValid())
129 {
130 FCoreUObjectDelegates::PostLoadMapWithWorld.Remove(OnPostLoadMapWithWorldHandle);
131 }
132
133 FDlgLogger::Get().Info(TEXT("DlgSystemModule: ShutdownModule"));
135}
136
138{
139 TSharedPtr<SDlgDataDisplay> DialogueData = DialogueDataDisplayWidget.Pin();
140 if (!DialogueData.IsValid())
141 {
142 DialogueData = SNew(SDlgDataDisplay, WorldContextObjectPtr);
143 DialogueDataDisplayWidget = DialogueData;
144 }
145
146 return DialogueData.ToSharedRef();
147}
148
153
154void FDlgSystemModule::RegisterConsoleCommands(const TWeakObjectPtr<const UObject>& InWorldContextObjectPtr)
155{
156 // Unregister first to prevent double register of commands
158
159 if (InWorldContextObjectPtr.IsValid())
160 {
161 WorldContextObjectPtr = InWorldContextObjectPtr;
162 }
163
164 IConsoleManager& ConsoleManager = IConsoleManager::Get();
165 ConsoleCommands.Add(
166 ConsoleManager.RegisterConsoleCommand(
167 TEXT("Dlg.DataDisplay"),
168 TEXT("Displays the Dialogue Data Window"),
169 FConsoleCommandDelegate::CreateRaw(this, &Self::DisplayDialogueDataWindow),
170 ECVF_Default
171 )
172 );
173
174 ConsoleCommands.Add(
175 ConsoleManager.RegisterConsoleCommand(
176 TEXT("Dlg.LoadAllDialogues"),
177 TEXT("Load All Dialogues into memory"),
178 FConsoleCommandDelegate::CreateLambda([]()
179 {
181 }),
182 ECVF_Default
183 )
184 );
185
186 // In case the DlgDataDisplay is already opened, simply refresh the actor reference
188}
189
191{
192 WorldContextObjectPtr.Reset();
193 for (IConsoleCommand* Command : ConsoleCommands)
194 {
195 IConsoleManager::Get().UnregisterConsoleObject(Command);
196 }
197 ConsoleCommands.Empty();
198}
199
201{
203 {
204 FDlgLogger::Get().Error(TEXT("Did not Initialize the tab spawner for the DisplayDialogueDataWindow"));
205 return;
206 }
207
209 {
210 // Create, because it does not exist yet
211 FDlgHelper::InvokeTab(FGlobalTabmanager::Get(), FTabId(DIALOGUE_DATA_DISPLAY_TAB_ID));
212 }
213}
214
216{
217 const TSharedPtr<SDockTab> DlgDisplayDataTab =
218 FGlobalTabmanager::Get()->FindExistingLiveTab(FTabId(DIALOGUE_DATA_DISPLAY_TAB_ID));
219 if (DlgDisplayDataTab.IsValid())
220 {
221 // Set the new WorldContextObjectPtr.
222 TSharedRef<SDlgDataDisplay> Window = StaticCastSharedRef<SDlgDataDisplay>(DlgDisplayDataTab->GetContent());
223 if (WorldContextObjectPtr.IsValid())
224 {
225 Window->SetWorldContextObject(WorldContextObjectPtr);
226 Window->RefreshTree(false);
227 }
228
229 // Focus
230 if (bFocus)
231 {
232 FGlobalTabmanager::Get()->DrawAttention(DlgDisplayDataTab.ToSharedRef());
233 }
234
235 return true;
236 }
237
238 return false;
239}
240
242{
243 // Should be safe to access it here
244 // See UAssetRegistryImpl::AssetDeleted
245 if (UDlgDialogue* Dialogue = Cast<UDlgDialogue>(DeletedObject))
246 {
248 }
249}
250
251void FDlgSystemModule::HandleOnAssetRemoved(const FAssetData& RemovedAsset)
252{
253 if (!RemovedAsset.IsAssetLoaded())
254 {
255 return;
256 }
257}
258
259void FDlgSystemModule::HandleOnAssetRenamed(const FAssetData& AssetRenamed, const FString& OldObjectPath)
260{
261 UObject* ObjectRenamed = AssetRenamed.GetAsset();
262 if (UDlgDialogue* Dialogue = Cast<UDlgDialogue>(ObjectRenamed))
263 {
264 HandleDialogueRenamed(Dialogue, OldObjectPath);
265 }
266}
267
269{
270 if (!IsValid(DeletedDialogue))
271 {
272 return;
273 }
274
275 DeletedDialogue->DeleteAllTextFiles();
276}
277
278void FDlgSystemModule::HandleDialogueRenamed(UDlgDialogue* RenamedDialogue, const FString& OldObjectPath)
279{
280 if (!IsValid(RenamedDialogue))
281 {
282 return;
283 }
284
285 // Rename text file file to new location
286 const FString OldTextFilePathName = UDlgDialogue::GetTextFilePathNameFromAssetPathName(OldObjectPath);
287 if (OldTextFilePathName.IsEmpty())
288 {
289 FDlgLogger::Get().Error(TEXT("OldTextFilePathName is empty. This should never happen"));
290 return;
291 }
292
293 // Current PathName
294 const FString CurrentTextFilePathName = RenamedDialogue->GetTextFilePathName(false);
295 if (OldTextFilePathName == CurrentTextFilePathName)
296 {
298 TEXT("Dialogue was renamed but the paths before and after are equal :O | `%s` == `%s`"),
299 *OldTextFilePathName, *CurrentTextFilePathName
300 );
301 return;
302 }
303
304 // Iterate over all possible text formats
305 for (const FString& FileExtension : GetDefault<UDlgSystemSettings>()->GetAllTextFileExtensions())
306 {
307 const FString OldFileName = OldTextFilePathName + FileExtension;
308 const FString NewFileName = CurrentTextFilePathName + FileExtension;
309 FDlgHelper::RenameFile(OldFileName, NewFileName, true);
310 }
311}
312
313void FDlgSystemModule::HandleOnPreLoadMap(const FString& MapName)
314{
315 // NOTE: only in NON editor game
316 const UDlgSystemSettings* Settings = GetDefault<UDlgSystemSettings>();
317 if (!Settings)
318 {
319 return;
320 }
321
323 {
324 FDlgLogger::Get().Debugf(TEXT("PreLoadMap = %s. Clearing Dialogue History"), *MapName);
326 }
327}
328
330{
331 // NOTE: only in NON editor game
332 if (!LoadedWorld)
333 {
334 return;
335 }
336
337 LastLoadedWorld = LoadedWorld;
338 const UDlgSystemSettings* Settings = GetDefault<UDlgSystemSettings>();
339 if (!Settings)
340 {
341 return;
342 }
343
345 {
346 FDlgLogger::Get().Debugf(TEXT("PostLoadMapWithWorld = %s. Registering Console commands"), *LoadedWorld->GetMapName());
347 RegisterConsoleCommands(LoadedWorld);
348 }
349}
350
351#undef LOCTEXT_NAMESPACE
352
static const FName NAME_MODULE_AssetRegistry(TEXT("AssetRegistry"))
static const FName DIALOGUE_DATA_DISPLAY_TAB_ID(TEXT("DlgDataDisplayWindow"))
const FName DIALOGUE_SYSTEM_PLUGIN_NAME(TEXT("DlgSystem"))
IMPLEMENT_MODULE(FOpenXRExpansionEditorModule, OpenXRExpansionEditor)
DEFINE_LOG_CATEGORY(LogVaRest)
static bool RenameFile(const FString &OldPathName, const FString &NewPathName, bool bOverWrite=false, bool bVerbose=true)
Definition DlgHelper.cpp:45
static TSharedPtr< SDockTab > InvokeTab(TSharedPtr< FTabManager > TabManager, const FTabId &TabID)
Definition DlgHelper.cpp:90
static void OnStart()
Definition DlgLogger.cpp:43
static void OnShutdown()
Definition DlgLogger.cpp:49
static FDlgLogger & Get()
Definition DlgLogger.h:24
void UnregisterConsoleCommands() override
TWeakPtr< SDlgDataDisplay > DialogueDataDisplayWidget
FDelegateHandle OnPostLoadMapWithWorldHandle
bool RefreshDisplayDialogueDataWindow(bool bFocus=true)
TSharedRef< SWidget > GetDialogueDataDisplayWindow() override
FDelegateHandle OnAssetRenamedHandle
void HandleDialogueDeleted(UDlgDialogue *DeletedDialogue)
void HandleOnInMemoryAssetDeleted(UObject *DeletedObject)
void ShutdownModule() override
void DisplayDialogueDataWindow() override
void HandleOnPostLoadMapWithWorld(UWorld *LoadedWorld)
FTabSpawnerEntry * DialogueDataDisplayTabSpawnEntry
void HandleDialogueRenamed(UDlgDialogue *RenamedDialogue, const FString &OldObjectPath)
void HandleOnAssetRemoved(const FAssetData &RemovedAsset)
TWeakObjectPtr< UWorld > LastLoadedWorld
void HandleOnPreLoadMap(const FString &MapName)
FDelegateHandle OnAssetRemovedHandle
void HandleOnAssetRenamed(const FAssetData &AssetRenamed, const FString &OldObjectPath)
void RegisterConsoleCommands(const TWeakObjectPtr< const UObject > &InWorldContextObjectPtr) override
FDelegateHandle OnInMemoryAssetDeletedHandle
TArray< IConsoleCommand * > ConsoleCommands
FDelegateHandle OnPreLoadMapHandle
FTabSpawnerEntry * GetDialogueDataDisplaySpawnEntry() override
TWeakObjectPtr< const UObject > WorldContextObjectPtr
FORCEINLINE void Error(const FString &Message)
Definition INYLogger.h:325
void Errorf(const FmtType &Fmt, Types... Args)
Definition INYLogger.h:305
FORCEINLINE void Info(const FString &Message)
Definition INYLogger.h:327
void Debugf(const FmtType &Fmt, Types... Args)
Definition INYLogger.h:314
UCLASS(BlueprintType, Meta = (DisplayThumbnail = "true"))
Definition DlgDialogue.h:85
static FString GetTextFilePathNameFromAssetPathName(const FString &AssetPathName)
bool DeleteAllTextFiles() const
FString GetTextFilePathName(bool bAddExtension=true) const
static void ClearDialogueHistory()
UFUNCTION(BlueprintCallable, Category = "Dialogue|Memory")
static int32 LoadAllDialoguesIntoMemory(bool bAsync=false)
UCLASS(Config = Engine, DefaultConfig, meta = (DisplayName = "Dialogue System Settings"))
bool bClearDialogueHistoryAutomatically
UPROPERTY(Category = "Runtime", Config, EditAnywhere)
bool bRegisterDialogueConsoleCommandsAutomatically
UPROPERTY(Category = "Runtime", Config, EditAnywhere)