From 5cc3a381f5cef9d57a4a356fcca041f4ac526b31 Mon Sep 17 00:00:00 2001 From: Anna Date: Tue, 13 Apr 2021 09:22:50 -0400 Subject: [PATCH] feat: add examine --- XivCommon/Functions/Examine.cs | 69 ++++++++++++++++++++++++++++++++++ XivCommon/GameFunctions.cs | 6 +++ 2 files changed, 75 insertions(+) create mode 100755 XivCommon/Functions/Examine.cs diff --git a/XivCommon/Functions/Examine.cs b/XivCommon/Functions/Examine.cs new file mode 100755 index 0000000..d7f25a3 --- /dev/null +++ b/XivCommon/Functions/Examine.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using Dalamud.Game; +using Dalamud.Game.ClientState.Actors.Types; + +namespace XivCommon.Functions { + /// + /// Class containing examine functions + /// + public class Examine { + private GameFunctions Functions { get; } + + private delegate IntPtr GetListDelegate(IntPtr basePtr); + + private delegate long RequestCharInfoDelegate(IntPtr ptr); + + private RequestCharInfoDelegate RequestCharacterInfo { get; } + + internal Examine(GameFunctions functions, SigScanner scanner) { + this.Functions = functions; + + // got this by checking what accesses rciData below + var rciPtr = scanner.ScanText("48 89 5C 24 ?? 57 48 83 EC 40 BA ?? ?? ?? ?? 48 8B D9 E8 ?? ?? ?? ?? 48 8B F8 48 85 C0 74 16"); + this.RequestCharacterInfo = Marshal.GetDelegateForFunctionPointer(rciPtr); + } + + private static IntPtr FollowPtrChain(IntPtr start, IEnumerable offsets) { + foreach (var offset in offsets) { + start = Marshal.ReadIntPtr(start, offset); + if (start == IntPtr.Zero) { + break; + } + } + + return start; + } + + /// + /// Opens the Examine window for the specified actor. + /// + /// Actor to open window for + public void OpenExamineWindow(Actor actor) { + // NOTES LAST UPDATED: 5.45 + + // offsets and stuff come from the beginning of case 0x2c (around line 621 in IDA) + // if 29f8 ever changes, I'd just scan for it in old binary and find what it is in the new binary at the same spot + // 40 55 53 57 41 54 41 55 41 56 48 8D 6C 24 ?? + var uiModule = this.Functions.GetUiModule(); + var getListPtr = FollowPtrChain(uiModule, new[] {0, 0x110}); + var getList = Marshal.GetDelegateForFunctionPointer(getListPtr); + var list = getList(uiModule); + var rciData = Marshal.ReadIntPtr(list + 0x1A0); + + unsafe { + // offsets at sig E8 ?? ?? ?? ?? 33 C0 EB 4C + // this is called at the end of the 2c case + var raw = (int*) rciData; + *(raw + 10) = actor.ActorId; + *(raw + 11) = actor.ActorId; + *(raw + 12) = actor.ActorId; + *(raw + 13) = -536870912; + *(raw + 311) = 0; + } + + this.RequestCharacterInfo(rciData); + } + } +} diff --git a/XivCommon/GameFunctions.cs b/XivCommon/GameFunctions.cs index f412790..b0d39ed 100755 --- a/XivCommon/GameFunctions.cs +++ b/XivCommon/GameFunctions.cs @@ -23,12 +23,18 @@ namespace XivCommon { /// BattleTalk functions and events /// public BattleTalk BattleTalk { get; } + /// + /// Examine functions + /// + public Examine Examine { get; } internal GameFunctions(Hooks hooks, DalamudPluginInterface @interface) { this.Interface = @interface; + this.Chat = new Chat(this, @interface.TargetModuleScanner); this.PartyFinder = new PartyFinder(@interface.TargetModuleScanner, hooks.HasFlag(Hooks.PartyFinder)); this.BattleTalk = new BattleTalk(this, @interface.TargetModuleScanner, @interface.SeStringManager, hooks.HasFlag(Hooks.BattleTalk)); + this.Examine = new Examine(this, @interface.TargetModuleScanner); } ///