diff --git a/Dalamud/Dalamud.cs b/Dalamud/Dalamud.cs index 5717669a9..99b1c08e5 100644 --- a/Dalamud/Dalamud.cs +++ b/Dalamud/Dalamud.cs @@ -110,6 +110,7 @@ namespace Dalamud { } this.Framework.Enable(); + this.ClientState.Enable(); this.BotManager.Start(); @@ -147,7 +148,8 @@ namespace Dalamud { this.InterfaceManager.Dispose(); - Framework.Dispose(); + this.Framework.Dispose(); + this.ClientState.Dispose(); this.BotManager.Dispose(); diff --git a/Dalamud/Game/ClientState/ClientState.cs b/Dalamud/Game/ClientState/ClientState.cs index 7deecca02..0aed29e98 100644 --- a/Dalamud/Game/ClientState/ClientState.cs +++ b/Dalamud/Game/ClientState/ClientState.cs @@ -1,8 +1,12 @@ +using System; using System.ComponentModel; using System.Runtime.InteropServices; using Dalamud.Game.ClientState.Actors; using Dalamud.Game.ClientState.Actors.Types; using Dalamud.Game.Internal; +using Dalamud.Game.Internal.Network; +using Dalamud.Hooking; +using Lumina.Excel.GeneratedSheets; using Serilog; namespace Dalamud.Game.ClientState @@ -10,7 +14,7 @@ namespace Dalamud.Game.ClientState /// /// This class represents the state of the game client at the time of access. /// - public class ClientState : INotifyPropertyChanged { + public class ClientState : INotifyPropertyChanged, IDisposable { public event PropertyChangedEventHandler PropertyChanged; private ClientStateAddressResolver Address { get; } @@ -36,10 +40,35 @@ namespace Dalamud.Game.ClientState } } + #region TerritoryType + + // TODO: The hooking logic for this should go into a separate class. + [UnmanagedFunctionPointer(CallingConvention.ThisCall)] + private delegate IntPtr SetupTerritoryTypeDelegate(IntPtr manager, ushort terriType); + + private readonly Hook setupTerritoryTypeHook; + /// /// The current Territory the player resides in. /// - public uint TerritoryType => (uint) Marshal.ReadInt32(Address.TerritoryType); + public ushort TerritoryType; + + /// + /// Event that gets fired when the current Territory changes. + /// + public EventHandler TerritoryChanged; + + private IntPtr SetupTerritoryTypeDetour(IntPtr manager, ushort terriType) + { + this.TerritoryType = terriType; + this.TerritoryChanged?.Invoke(this, terriType); + + Log.Debug("TerritoryType changed: {0}", terriType); + + return this.setupTerritoryTypeHook.Original(manager, terriType); + } + + #endregion /// /// The content ID of the local character. @@ -69,11 +98,23 @@ namespace Dalamud.Game.ClientState this.JobGauges = new JobGauges(Address); - Log.Verbose("TerritoryType address {TerritoryType}", Address.TerritoryType); + Log.Verbose("SetupTerritoryType address {SetupTerritoryType}", Address.SetupTerritoryType); + + this.setupTerritoryTypeHook = new Hook(Address.SetupTerritoryType, + new SetupTerritoryTypeDelegate(SetupTerritoryTypeDetour), + this); dalamud.Framework.OnUpdateEvent += FrameworkOnOnUpdateEvent; } + public void Enable() { + this.setupTerritoryTypeHook.Enable(); + } + + public void Dispose() { + this.setupTerritoryTypeHook.Dispose(); + } + private void FrameworkOnOnUpdateEvent(Framework framework) { // ignored } diff --git a/Dalamud/Game/ClientState/ClientStateAddressResolver.cs b/Dalamud/Game/ClientState/ClientStateAddressResolver.cs index b3ef8d650..8d6bab2de 100644 --- a/Dalamud/Game/ClientState/ClientStateAddressResolver.cs +++ b/Dalamud/Game/ClientState/ClientStateAddressResolver.cs @@ -4,16 +4,20 @@ using Dalamud.Game.Internal; namespace Dalamud.Game.ClientState { public sealed class ClientStateAddressResolver : BaseAddressResolver { + // Static offsets public IntPtr ActorTable { get; private set; } public IntPtr LocalContentId { get; private set; } public IntPtr JobGaugeData { get; private set; } - public IntPtr TerritoryType { get; private set; } + + // Functions + public IntPtr SetupTerritoryType { get; private set; } protected override void Setup64Bit(SigScanner sig) { ActorTable = sig.GetStaticAddressFromSig("48 8D 0D ?? ?? ?? ?? 85 ED", 0) + 0x148; LocalContentId = sig.GetStaticAddressFromSig("48 8B 05 ?? ?? ?? ?? 48 89 86 ?? ?? ?? ??", 0); JobGaugeData = sig.GetStaticAddressFromSig("E8 ?? ?? ?? ?? FF C6 48 8D 5B 0C", 0xB9) + 0x10; - TerritoryType = sig.GetStaticAddressFromSig("48 83 EC 20 81 3D ?? ?? ?? ?? ?? ?? ?? ?? 49 8B F8", 0); + + SetupTerritoryType = sig.ScanText("48 89 5C 24 ?? 48 89 74 24 ?? 57 48 83 EC 20 48 8B F9 66 89 91 ?? ?? ?? ??"); } } } diff --git a/Dalamud/Game/Internal/Framework.cs b/Dalamud/Game/Internal/Framework.cs index 54e37c224..78250a17b 100644 --- a/Dalamud/Game/Internal/Framework.cs +++ b/Dalamud/Game/Internal/Framework.cs @@ -17,6 +17,9 @@ namespace Dalamud.Game.Internal { public delegate void OnUpdateDelegate(Framework framework); + /// + /// Event that gets fired every time the game framework updates. + /// public event OnUpdateDelegate OnUpdateEvent; private Hook updateHook;