From 1c165ae3e1f55c3d699aebc8f4e6ebc1ca04e09b Mon Sep 17 00:00:00 2001 From: Anna Date: Sun, 11 Apr 2021 09:24:56 -0400 Subject: [PATCH] feat: allow cherry-picking hooks --- XivCommon/Functions/BattleTalk.cs | 19 ++++++++++++++----- XivCommon/Functions/PartyFinder.cs | 21 ++++++++++++++++----- XivCommon/GameFunctions.cs | 6 +++--- XivCommon/Hooks.cs | 14 ++++++++++++++ XivCommon/XivCommonBase.cs | 6 ++---- 5 files changed, 49 insertions(+), 17 deletions(-) create mode 100755 XivCommon/Hooks.cs diff --git a/XivCommon/Functions/BattleTalk.cs b/XivCommon/Functions/BattleTalk.cs index aa76d23..f55b5a3 100755 --- a/XivCommon/Functions/BattleTalk.cs +++ b/XivCommon/Functions/BattleTalk.cs @@ -1,5 +1,4 @@ using System; -using System.Text; using Dalamud.Game; using Dalamud.Game.Text.SeStringHandling; using Dalamud.Hooking; @@ -9,6 +8,7 @@ namespace XivCommon.Functions { public class BattleTalk : IDisposable { private GameFunctions Functions { get; } private SeStringManager SeStringManager { get; } + private bool Enabled { get; } public delegate void BattleTalkEventDelegate(ref SeString sender, ref SeString message, ref BattleTalkOptions options, ref bool isHandled); @@ -16,11 +16,16 @@ namespace XivCommon.Functions { private delegate byte AddBattleTalkDelegate(IntPtr uiModule, IntPtr sender, IntPtr message, float duration, byte style); - private Hook AddBattleTextHook { get; } + private Hook? AddBattleTextHook { get; } - internal BattleTalk(GameFunctions functions, SigScanner scanner, SeStringManager seStringManager) { + internal BattleTalk(GameFunctions functions, SigScanner scanner, SeStringManager seStringManager, bool hook) { this.Functions = functions; this.SeStringManager = seStringManager; + this.Enabled = hook; + + if (!hook) { + return; + } var addBattleTextPtr = scanner.ScanText("48 89 5C 24 ?? 57 48 83 EC 50 48 8B 01 49 8B D8 0F 29 74 24 ?? 48 8B FA 0F 28 F3 FF 50 40 C7 44 24 ?? ?? ?? ?? ??"); this.AddBattleTextHook = new Hook(addBattleTextPtr, new AddBattleTalkDelegate(this.AddBattleTalkDetour)); @@ -28,7 +33,7 @@ namespace XivCommon.Functions { } public void Dispose() { - this.AddBattleTextHook.Dispose(); + this.AddBattleTextHook?.Dispose(); } private unsafe byte AddBattleTalkDetour(IntPtr uiModule, IntPtr senderPtr, IntPtr messagePtr, float duration, byte style) { @@ -58,7 +63,7 @@ namespace XivCommon.Functions { var finalMessage = message.Encode().Terminate(); fixed (byte* fSenderPtr = finalSender, fMessagePtr = finalMessage) { - return this.AddBattleTextHook.Original(uiModule, (IntPtr) fSenderPtr, (IntPtr) fMessagePtr, options.Duration, (byte) options.Style); + return this.AddBattleTextHook!.Original(uiModule, (IntPtr) fSenderPtr, (IntPtr) fMessagePtr, options.Duration, (byte) options.Style); } } @@ -67,6 +72,10 @@ namespace XivCommon.Functions { } private void Show(byte[] sender, byte[] message, BattleTalkOptions? options) { + if (!this.Enabled) { + throw new InvalidOperationException("BattleTalk hooks are not enabled"); + } + if (sender.Length == 0) { throw new ArgumentException("sender cannot be empty", nameof(sender)); } diff --git a/XivCommon/Functions/PartyFinder.cs b/XivCommon/Functions/PartyFinder.cs index 7c34bb2..808d6c4 100755 --- a/XivCommon/Functions/PartyFinder.cs +++ b/XivCommon/Functions/PartyFinder.cs @@ -1,7 +1,6 @@ using System; using System.Runtime.InteropServices; using Dalamud.Game; -using Dalamud.Game.Internal.Gui; using Dalamud.Hooking; namespace XivCommon.Functions { @@ -9,28 +8,40 @@ namespace XivCommon.Functions { private delegate byte RequestPartyFinderListingsDelegate(IntPtr agent, byte categoryIdx); private RequestPartyFinderListingsDelegate RequestPartyFinderListings { get; } - private Hook RequestPfListingsHook { get; } + private Hook? RequestPfListingsHook { get; } + private bool Enabled { get; } private IntPtr PartyFinderAgent { get; set; } = IntPtr.Zero; - internal PartyFinder(SigScanner scanner) { + internal PartyFinder(SigScanner scanner, bool hook) { var requestPfPtr = scanner.ScanText("48 89 5C 24 ?? 48 89 74 24 ?? 57 48 83 EC 40 0F 10 81 ?? ?? ?? ??"); this.RequestPartyFinderListings = Marshal.GetDelegateForFunctionPointer(requestPfPtr); + + this.Enabled = hook; + + if (!hook) { + return; + } + this.RequestPfListingsHook = new Hook(requestPfPtr, new RequestPartyFinderListingsDelegate(this.OnRequestPartyFinderListings)); this.RequestPfListingsHook.Enable(); } public void Dispose() { - this.RequestPfListingsHook.Dispose(); + this.RequestPfListingsHook?.Dispose(); } private byte OnRequestPartyFinderListings(IntPtr agent, byte categoryIdx) { this.PartyFinderAgent = agent; - return this.RequestPfListingsHook.Original(agent, categoryIdx); + return this.RequestPfListingsHook!.Original(agent, categoryIdx); } public void RefreshListings() { + if (!this.Enabled) { + throw new InvalidOperationException("PartyFinder hooks are not enabled"); + } + // Updated 5.41 const int categoryOffset = 10_655; diff --git a/XivCommon/GameFunctions.cs b/XivCommon/GameFunctions.cs index 0fdc0ca..96b2300 100755 --- a/XivCommon/GameFunctions.cs +++ b/XivCommon/GameFunctions.cs @@ -16,15 +16,15 @@ namespace XivCommon { public PartyFinder PartyFinder { get; } public BattleTalk BattleTalk { get; } - internal GameFunctions(SigScanner scanner, SeStringManager seStringManager) { + internal GameFunctions(Hooks hooks, SigScanner scanner, SeStringManager seStringManager) { this.UiModulePtr = scanner.GetStaticAddressFromSig("48 8B 0D ?? ?? ?? ?? 48 8D 54 24 ?? 48 83 C1 10 E8 ?? ?? ?? ??"); var getUiModulePtr = scanner.ScanText("E8 ?? ?? ?? ?? 83 3B 01"); this.InternalGetUiModule = Marshal.GetDelegateForFunctionPointer(getUiModulePtr); this.Chat = new Chat(this, scanner); - this.PartyFinder = new PartyFinder(scanner); - this.BattleTalk = new BattleTalk(this, scanner, seStringManager); + this.PartyFinder = new PartyFinder(scanner, hooks.HasFlag(Hooks.PartyFinder)); + this.BattleTalk = new BattleTalk(this, scanner, seStringManager, hooks.HasFlag(Hooks.BattleTalk)); } public void Dispose() { diff --git a/XivCommon/Hooks.cs b/XivCommon/Hooks.cs new file mode 100755 index 0000000..6ebcfd4 --- /dev/null +++ b/XivCommon/Hooks.cs @@ -0,0 +1,14 @@ +using System; + +namespace XivCommon { + [Flags] + public enum Hooks { + None, + BattleTalk, + PartyFinder, + } + + internal static class HooksExt { + internal const Hooks DefaultHooks = Hooks.None; + } +} diff --git a/XivCommon/XivCommonBase.cs b/XivCommon/XivCommonBase.cs index a3e5f9c..ba0721b 100755 --- a/XivCommon/XivCommonBase.cs +++ b/XivCommon/XivCommonBase.cs @@ -1,14 +1,12 @@ using System; -using Dalamud.Game; -using Dalamud.Game.Text.SeStringHandling; using Dalamud.Plugin; namespace XivCommon { public class XivCommonBase : IDisposable { public GameFunctions Functions { get; } - public XivCommonBase(DalamudPluginInterface @interface) { - this.Functions = new GameFunctions(@interface.TargetModuleScanner, @interface.SeStringManager); + public XivCommonBase(DalamudPluginInterface @interface, Hooks hooks = HooksExt.DefaultHooks) { + this.Functions = new GameFunctions(hooks, @interface.TargetModuleScanner, @interface.SeStringManager); } public void Dispose() {