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
}
}
}