From 37fc6ffc73b3e09973608ac4c6a28e1a2f94c4fc Mon Sep 17 00:00:00 2001 From: Raymond Date: Tue, 7 Sep 2021 11:14:17 -0400 Subject: [PATCH] feat: condition changed event, expose condition address --- Dalamud/Dalamud.cs | 26 ++-- Dalamud/Game/ClientState/ClientState.cs | 2 + .../Game/ClientState/Conditions/Condition.cs | 112 ++++++++++++++++-- .../Interface/Internal/Windows/DataWindow.cs | 2 +- 4 files changed, 116 insertions(+), 26 deletions(-) diff --git a/Dalamud/Dalamud.cs b/Dalamud/Dalamud.cs index c191b3419..a4d7001d5 100644 --- a/Dalamud/Dalamud.cs +++ b/Dalamud/Dalamud.cs @@ -153,6 +153,19 @@ namespace Dalamud Service.Set(); Log.Information("[T2] NH OK!"); + try + { + Service.Set().Initialize(this.AssetDirectory.FullName); + } + catch (Exception e) + { + Log.Error(e, "Could not initialize DataManager."); + this.Unload(); + return; + } + + Log.Information("[T2] Data OK!"); + var clientState = Service.Set(); Log.Information("[T2] CS OK!"); @@ -192,19 +205,6 @@ namespace Dalamud Log.Information(e, "Could not init IME."); } - try - { - Service.Set().Initialize(this.AssetDirectory.FullName); - } - catch (Exception e) - { - Log.Error(e, "Could not initialize DataManager."); - this.Unload(); - return; - } - - Log.Information("[T2] Data OK!"); - #pragma warning disable CS0618 // Type or member is obsolete Service.Set(); #pragma warning restore CS0618 // Type or member is obsolete diff --git a/Dalamud/Game/ClientState/ClientState.cs b/Dalamud/Game/ClientState/ClientState.cs index 3e50ffc38..52b63ed9e 100644 --- a/Dalamud/Game/ClientState/ClientState.cs +++ b/Dalamud/Game/ClientState/ClientState.cs @@ -125,6 +125,7 @@ namespace Dalamud.Game.ClientState /// public void Enable() { + Service.Get().Enable(); Service.Get().Enable(); this.setupTerritoryTypeHook.Enable(); } @@ -135,6 +136,7 @@ namespace Dalamud.Game.ClientState public void Dispose() { this.setupTerritoryTypeHook.Dispose(); + Service.Get().Dispose(); Service.Get().Dispose(); Service.Get().Update -= this.FrameworkOnOnUpdateEvent; Service.Get().CfPop -= this.NetworkHandlersOnCfPop; diff --git a/Dalamud/Game/ClientState/Conditions/Condition.cs b/Dalamud/Game/ClientState/Conditions/Condition.cs index 4d679a180..597f4725b 100644 --- a/Dalamud/Game/ClientState/Conditions/Condition.cs +++ b/Dalamud/Game/ClientState/Conditions/Condition.cs @@ -2,6 +2,7 @@ using System; using Dalamud.IoC; using Dalamud.IoC.Internal; +using Serilog; namespace Dalamud.Game.ClientState.Conditions { @@ -10,45 +11,61 @@ namespace Dalamud.Game.ClientState.Conditions /// [PluginInterface] [InterfaceVersion("1.0")] - public class Condition + public sealed partial class Condition { /// /// The current max number of conditions. You can get this just by looking at the condition sheet and how many rows it has. /// public const int MaxConditionEntries = 100; + private readonly bool[] cache = new bool[MaxConditionEntries]; + /// /// Initializes a new instance of the class. /// /// The ClientStateAddressResolver instance. internal Condition(ClientStateAddressResolver resolver) { - this.ConditionArrayBase = resolver.ConditionFlags; + this.Address = resolver.ConditionFlags; } /// - /// Gets the condition array base pointer. - /// Would typically be private but is used in /xldata windows. + /// A delegate type used with the event. /// - internal IntPtr ConditionArrayBase { get; private set; } + /// The changed condition. + /// The value the condition is set to. + public delegate void ConditionChangeDelegate(ConditionFlag flag, bool value); + + /// + /// Event that gets fired when a condition is set. + /// Should only get fired for actual changes, so the previous value will always be !value. + /// + public event ConditionChangeDelegate? ConditionChange; + + /// + /// Gets the condition array base pointer. + /// + public IntPtr Address { get; private set; } /// /// Check the value of a specific condition/state flag. /// /// The condition flag to check. - public unsafe bool this[ConditionFlag flag] + public unsafe bool this[int flag] { get { - var idx = (int)flag; - - if (idx < 0 || idx >= MaxConditionEntries) + if (flag < 0 || flag >= MaxConditionEntries) return false; - return *(bool*)(this.ConditionArrayBase + idx); + return *(bool*)(this.Address + flag); } } + /// + public unsafe bool this[ConditionFlag flag] + => this[(int)flag]; + /// /// Check if any condition flags are set. /// @@ -57,8 +74,7 @@ namespace Dalamud.Game.ClientState.Conditions { for (var i = 0; i < MaxConditionEntries; i++) { - var typedCondition = (ConditionFlag)i; - var cond = this[typedCondition]; + var cond = this[i]; if (cond) return true; @@ -66,5 +82,77 @@ namespace Dalamud.Game.ClientState.Conditions return false; } + + /// + /// Enables the hooks of the Condition class function. + /// + public void Enable() + { + // Initialization + for (var i = 0; i < MaxConditionEntries; i++) + this.cache[i] = this[i]; + + Service.Get().Update += this.FrameworkUpdate; + } + + private void FrameworkUpdate(Framework framework) + { + for (var i = 0; i < MaxConditionEntries; i++) + { + var value = this[i]; + + if (value != this.cache[i]) + { + this.cache[i] = value; + + try + { + this.ConditionChange?.Invoke((ConditionFlag)i, value); + } + catch (Exception ex) + { + Log.Error(ex, $"While invoking {nameof(this.ConditionChange)}, an exception was thrown."); + } + } + } + } + } + + /// + /// Provides access to conditions (generally player state). You can check whether a player is in combat, mounted, etc. + /// + public sealed partial class Condition : IDisposable + { + private bool isDisposed; + + /// + /// Finalizes an instance of the class. + /// + ~Condition() + { + this.Dispose(false); + } + + /// + /// Disposes this instance, alongside its hooks. + /// + public void Dispose() + { + GC.SuppressFinalize(this); + this.Dispose(true); + } + + private void Dispose(bool disposing) + { + if (this.isDisposed) + return; + + if (disposing) + { + Service.Get().Update -= this.FrameworkUpdate; + } + + this.isDisposed = true; + } } } diff --git a/Dalamud/Interface/Internal/Windows/DataWindow.cs b/Dalamud/Interface/Internal/Windows/DataWindow.cs index a831511b1..bf7248cfc 100644 --- a/Dalamud/Interface/Internal/Windows/DataWindow.cs +++ b/Dalamud/Interface/Internal/Windows/DataWindow.cs @@ -674,7 +674,7 @@ namespace Dalamud.Interface.Internal.Windows var condition = Service.Get(); #if DEBUG - ImGui.Text($"ptr: 0x{condition.ConditionArrayBase.ToInt64():X}"); + ImGui.Text($"ptr: 0x{condition.Address.ToInt64():X}"); #endif ImGui.Text("Current Conditions:");