From 9ff7eb801feabb1411c63776fbaeb1695edcb106 Mon Sep 17 00:00:00 2001 From: goat Date: Mon, 27 Mar 2023 19:43:29 +0200 Subject: [PATCH] feat: add GameLifecycle service --- Dalamud/Game/ClientState/ClientState.cs | 8 +++- Dalamud/Game/Framework.cs | 11 ++++- Dalamud/Game/GameLifecycle.cs | 63 +++++++++++++++++++++++++ 3 files changed, 79 insertions(+), 3 deletions(-) create mode 100644 Dalamud/Game/GameLifecycle.cs diff --git a/Dalamud/Game/ClientState/ClientState.cs b/Dalamud/Game/ClientState/ClientState.cs index cacb42c0a..1f72d853f 100644 --- a/Dalamud/Game/ClientState/ClientState.cs +++ b/Dalamud/Game/ClientState/ClientState.cs @@ -23,6 +23,7 @@ namespace Dalamud.Game.ClientState; [ServiceManager.BlockingEarlyLoadedService] public sealed class ClientState : IDisposable, IServiceType { + private readonly GameLifecycle lifecycle; private readonly ClientStateAddressResolver address; private readonly Hook setupTerritoryTypeHook; @@ -36,8 +37,9 @@ public sealed class ClientState : IDisposable, IServiceType private bool lastFramePvP = false; [ServiceManager.ServiceConstructor] - private ClientState(SigScanner sigScanner, DalamudStartInfo startInfo) + private ClientState(SigScanner sigScanner, DalamudStartInfo startInfo, GameLifecycle lifecycle) { + this.lifecycle = lifecycle; this.address = new ClientStateAddressResolver(); this.address.Setup(sigScanner); @@ -174,6 +176,8 @@ public sealed class ClientState : IDisposable, IServiceType this.IsLoggedIn = true; this.Login?.InvokeSafely(this, null); gameGui.ResetUiHideState(); + + this.lifecycle.ResetLogout(); } if (!condition.Any() && this.lastConditionNone == false) @@ -183,6 +187,8 @@ public sealed class ClientState : IDisposable, IServiceType this.IsLoggedIn = false; this.Logout?.InvokeSafely(this, null); gameGui.ResetUiHideState(); + + this.lifecycle.SetLogout(); } this.IsPvP = GameMain.IsInPvPArea(); diff --git a/Dalamud/Game/Framework.cs b/Dalamud/Game/Framework.cs index f2c65723c..21bd9e646 100644 --- a/Dalamud/Game/Framework.cs +++ b/Dalamud/Game/Framework.cs @@ -25,6 +25,8 @@ namespace Dalamud.Game; [ServiceManager.BlockingEarlyLoadedService] public sealed class Framework : IDisposable, IServiceType { + private readonly GameLifecycle lifecycle; + private static Stopwatch statsStopwatch = new(); private readonly Stopwatch updateStopwatch = new(); @@ -41,10 +43,11 @@ public sealed class Framework : IDisposable, IServiceType [ServiceManager.ServiceDependency] private readonly DalamudConfiguration configuration = Service.Get(); - + [ServiceManager.ServiceConstructor] - private Framework(SigScanner sigScanner) + private Framework(SigScanner sigScanner, GameLifecycle lifecycle) { + this.lifecycle = lifecycle; this.hitchDetector = new HitchDetector("FrameworkUpdate", this.configuration.FrameworkUpdateHitch); this.Address = new FrameworkAddressResolver(); @@ -489,6 +492,10 @@ public sealed class Framework : IDisposable, IServiceType this.IsFrameworkUnloading = true; this.DispatchUpdateEvents = false; + // All the same, for now... + this.lifecycle.SetShuttingDown(); + this.lifecycle.SetUnloading(); + Log.Information("Framework::Destroy!"); Service.Get().Unload(); this.RunPendingTickTasks(); diff --git a/Dalamud/Game/GameLifecycle.cs b/Dalamud/Game/GameLifecycle.cs new file mode 100644 index 000000000..3a6733512 --- /dev/null +++ b/Dalamud/Game/GameLifecycle.cs @@ -0,0 +1,63 @@ +using System.Threading; + +using Dalamud.IoC; +using Dalamud.IoC.Internal; + +namespace Dalamud.Game; + +/// +/// Class offering cancellation tokens for common gameplay events. +/// +[PluginInterface] +[InterfaceVersion("1.0")] +[ServiceManager.BlockingEarlyLoadedService] +public class GameLifecycle : IServiceType +{ + private readonly CancellationTokenSource dalamudUnloadCts = new(); + private readonly CancellationTokenSource gameShutdownCts = new(); + + private CancellationTokenSource logoutCts = new(); + + /// + /// Initializes a new instance of the class. + /// + [ServiceManager.ServiceConstructor] + internal GameLifecycle() + { + } + + /// + /// Gets a token that is cancelled when Dalamud is unloading. + /// + public CancellationToken DalamudUnloadingToken => this.dalamudUnloadCts.Token; + + /// + /// Gets a token that is cancelled when the game is shutting down. + /// + public CancellationToken GameShuttingDownToken => this.gameShutdownCts.Token; + + /// + /// Gets a token that is cancelled when a character is logging out. + /// + public CancellationToken LogoutToken => this.logoutCts.Token; + + /// + /// Mark an unload. + /// + internal void SetUnloading() => this.dalamudUnloadCts.Cancel(); + + /// + /// Mark a shutdown. + /// + internal void SetShuttingDown() => this.gameShutdownCts.Cancel(); + + /// + /// Mark a logout. + /// + internal void SetLogout() => this.logoutCts.Cancel(); + + /// + /// Unmark a logout. + /// + internal void ResetLogout() => this.logoutCts = new(); +}