using System; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; namespace Dalamud.Game { /// /// Base memory address resolver. /// public abstract class BaseAddressResolver { /// /// Gets a list of memory addresses that were found, to list in /xldata. /// public static Dictionary> DebugScannedValues { get; } = new(); /// /// Gets or sets a value indicating whether the resolver has successfully run or . /// protected bool IsResolved { get; set; } /// /// Setup the resolver, calling the appopriate method based on the process architecture. /// public void Setup() { var scanner = Service.Get(); this.Setup(scanner); } /// /// Setup the resolver, calling the appopriate method based on the process architecture. /// /// The SigScanner instance. public void Setup(SigScanner scanner) { // Because C# don't allow to call virtual function while in ctor // we have to do this shit :\ if (this.IsResolved) { return; } if (scanner.Is32BitProcess) { this.Setup32Bit(scanner); } else { this.Setup64Bit(scanner); } this.SetupInternal(scanner); var className = this.GetType().Name; DebugScannedValues[className] = new List<(string, IntPtr)>(); foreach (var property in this.GetType().GetProperties().Where(x => x.PropertyType == typeof(IntPtr))) { DebugScannedValues[className].Add((property.Name, (IntPtr)property.GetValue(this))); } this.IsResolved = true; } /// /// Fetch vfunc N from a pointer to the vtable and return a delegate function pointer. /// /// The delegate to marshal the function pointer to. /// The address of the virtual table. /// The offset from address to the vtable pointer. /// The vfunc index. /// A delegate function pointer that can be invoked. public T GetVirtualFunction(IntPtr address, int vtableOffset, int count) where T : class { // Get vtable var vtable = Marshal.ReadIntPtr(address, vtableOffset); // Get an address to the function var functionAddress = Marshal.ReadIntPtr(vtable, IntPtr.Size * count); return Marshal.GetDelegateForFunctionPointer(functionAddress); } /// /// Setup the resolver by finding any necessary memory addresses. /// /// The SigScanner instance. protected virtual void Setup32Bit(SigScanner scanner) { throw new NotSupportedException("32 bit version is not supported."); } /// /// Setup the resolver by finding any necessary memory addresses. /// /// The SigScanner instance. protected virtual void Setup64Bit(SigScanner scanner) { throw new NotSupportedException("64 bit version is not supported."); } /// /// Setup the resolver by finding any necessary memory addresses. /// /// The SigScanner instance. protected virtual void SetupInternal(SigScanner scanner) { // Do nothing } } }