feat: new actor table shenanigans

This commit is contained in:
goat 2020-04-24 18:50:20 +02:00
parent 03e4a4d25c
commit f80a4e7432
5 changed files with 26 additions and 52 deletions

View file

@ -43,6 +43,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="CheapLoc" Version="1.1.3" />
<PackageReference Include="JetBrains.Annotations" Version="2020.1.0" />
<PackageReference Include="Lumina" Version="1.1.1" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
<PackageReference Include="PropertyChanged.Fody" Version="2.6.1" />

View file

@ -6,13 +6,16 @@ using System.Runtime.InteropServices;
using Dalamud.Game.ClientState.Actors.Types;
using Dalamud.Game.ClientState.Actors.Types.NonPlayer;
using Dalamud.Hooking;
using JetBrains.Annotations;
using Serilog;
namespace Dalamud.Game.ClientState.Actors {
/// <summary>
/// This collection represents the currently spawned FFXIV actors.
/// </summary>
public class ActorTable : IReadOnlyCollection<Actor>, ICollection, IDisposable {
public class ActorTable : IReadOnlyCollection<Actor>, ICollection {
private const int ActorTableLength = 424;
#region temporary imports for crash workaround
@ -29,14 +32,6 @@ namespace Dalamud.Game.ClientState.Actors {
private ClientStateAddressResolver Address { get; }
private Dalamud dalamud;
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
private delegate IntPtr SomeActorTableAccessDelegate(IntPtr manager, IntPtr offset);
private Hook<SomeActorTableAccessDelegate> someActorTableAccessHook;
private bool isReady = false;
private IntPtr realActorTablePtr;
/// <summary>
/// Set up the actor table collection.
/// </summary>
@ -45,27 +40,7 @@ namespace Dalamud.Game.ClientState.Actors {
Address = addressResolver;
this.dalamud = dalamud;
this.someActorTableAccessHook = new Hook<SomeActorTableAccessDelegate>(
Address.SomeActorTableAccess, new SomeActorTableAccessDelegate(SomeActorTableAccessDetour), this);
Log.Verbose("Actor table address {ActorTable}", Address.ViewportActorTable);
}
public void Enable() {
this.someActorTableAccessHook.Enable();
}
public void Dispose() {
if (!this.isReady)
this.someActorTableAccessHook.Dispose();
this.isReady = false;
}
private IntPtr SomeActorTableAccessDetour(IntPtr manager, IntPtr offset) {
this.realActorTablePtr = offset;
this.isReady = true;
return this.someActorTableAccessHook.Original(manager, offset);
Log.Verbose("Actor table address {ActorTable}", Address.ActorTable);
}
/// <summary>
@ -73,24 +48,17 @@ namespace Dalamud.Game.ClientState.Actors {
/// </summary>
/// <param name="index">Spawn index.</param>
/// <returns><see cref="Actor" /> at the specified spawn index.</returns>
[CanBeNull]
public Actor this[int index] {
get {
if (!this.isReady)
return null;
if (this.someActorTableAccessHook != null) {
this.someActorTableAccessHook.Dispose();
this.someActorTableAccessHook = null;
}
if (index >= Length)
return null;
var tblIndex = this.realActorTablePtr + 8 + index * 8;
var tblIndex = Address.ActorTable + index * 8;
var offset = Marshal.ReadIntPtr(tblIndex);
//Log.Verbose("Actor at {0} for {1}", offset.ToInt64().ToString("X"), index);
Log.Debug($"Reading actor {index} at {tblIndex.ToInt64():X} pointing to {offset.ToInt64():X}");
if (offset == IntPtr.Zero)
return null;
@ -154,7 +122,7 @@ namespace Dalamud.Game.ClientState.Actors {
/// <summary>
/// The amount of currently spawned actors.
/// </summary>
public int Length => !this.isReady ? 0 : Marshal.ReadInt32(this.realActorTablePtr);
public int Length => ActorTableLength;
int IReadOnlyCollection<Actor>.Count => Length;

View file

@ -6,6 +6,7 @@ using Dalamud.Game.ClientState.Actors.Types;
using Dalamud.Game.Internal;
using Dalamud.Game.Internal.Network;
using Dalamud.Hooking;
using JetBrains.Annotations;
using Lumina.Excel.GeneratedSheets;
using Serilog;
@ -29,6 +30,7 @@ namespace Dalamud.Game.ClientState
/// <summary>
/// The local player character, if one is present.
/// </summary>
[CanBeNull]
public PlayerCharacter LocalPlayer {
get {
var actor = this.Actors[0];
@ -122,13 +124,11 @@ namespace Dalamud.Game.ClientState
}
public void Enable() {
this.Actors.Enable();
this.PartyList.Enable();
this.setupTerritoryTypeHook.Enable();
}
public void Dispose() {
this.Actors.Dispose();
this.PartyList.Dispose();
this.setupTerritoryTypeHook.Dispose();
}

View file

@ -5,19 +5,22 @@ namespace Dalamud.Game.ClientState
{
public sealed class ClientStateAddressResolver : BaseAddressResolver {
// Static offsets
public IntPtr ViewportActorTable { get; private set; }
public IntPtr ActorTable { get; private set; }
//public IntPtr ViewportActorTable { get; private set; }
public IntPtr LocalContentId { get; private set; }
public IntPtr JobGaugeData { get; private set; }
public IntPtr KeyboardState { get; private set; }
// Functions
public IntPtr SetupTerritoryType { get; private set; }
public IntPtr SomeActorTableAccess { get; private set; }
//public IntPtr SomeActorTableAccess { get; private set; }
public IntPtr PartyListUpdate { get; private set; }
protected override void Setup64Bit(SigScanner sig) {
ViewportActorTable = sig.GetStaticAddressFromSig("48 8D 0D ?? ?? ?? ?? 85 ED", 0) + 0x148;
SomeActorTableAccess = sig.ScanText("E8 ?? ?? ?? ?? 48 8D 55 A0 48 8D 8E ?? ?? ?? ??");
// We don't need those anymore, but maybe someone else will - let's leave them here for good measure
//ViewportActorTable = sig.GetStaticAddressFromSig("48 8D 0D ?? ?? ?? ?? 85 ED", 0) + 0x148;
//SomeActorTableAccess = sig.ScanText("E8 ?? ?? ?? ?? 48 8D 55 A0 48 8D 8E ?? ?? ?? ??");
ActorTable = sig.GetStaticAddressFromSig("88 91 ?? ?? ?? ?? 48 8D 3D ?? ?? ?? ??", 0x0);
LocalContentId = sig.GetStaticAddressFromSig("48 8B 05 ?? ?? ?? ?? 48 89 86 ?? ?? ?? ??", 0);
JobGaugeData = sig.GetStaticAddressFromSig("E8 ?? ?? ?? ?? FF C6 48 8D 5B 0C", 0xB9) + 0x10;

View file

@ -69,12 +69,11 @@ namespace Dalamud.Interface
var stateString = string.Empty;
// LocalPlayer is null in a number of situations (at least with the current visible-actors list)
// which would crash here.
if (this.dalamud.ClientState.Actors.Length == 0 || this.dalamud.ClientState.LocalPlayer == null)
{
if (this.dalamud.ClientState.Actors.Length == 0) {
ImGui.TextUnformatted("Data not ready.");
}
else
{
} else if (this.dalamud.ClientState.LocalPlayer == null) {
ImGui.TextUnformatted("LocalPlayer null.");
} else {
stateString += $"FrameworkBase: {this.dalamud.Framework.Address.BaseAddress.ToInt64():X}\n";
stateString += $"ActorTableLen: {this.dalamud.ClientState.Actors.Length}\n";
@ -88,6 +87,9 @@ namespace Dalamud.Interface
for (var i = 0; i < this.dalamud.ClientState.Actors.Length; i++) {
var actor = this.dalamud.ClientState.Actors[i];
if (actor == null)
continue;
stateString +=
$"{actor.Address.ToInt64():X}:{actor.ActorId:X}[{i}] - {actor.ObjectKind} - {actor.Name} - {actor.Position.X} {actor.Position.Y} {actor.Position.Z}\n";