mirror of
https://github.com/goatcorp/Dalamud.git
synced 2025-12-13 12:14:16 +01:00
Merge pull request #92 from karashiiro/minor-tweaks
Implement IReadOnlyCollection<Actor> on the ActorTable to allow foreach without casting
This commit is contained in:
commit
37d6243248
1 changed files with 26 additions and 14 deletions
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using Dalamud.Game.ClientState.Actors.Types;
|
using Dalamud.Game.ClientState.Actors.Types;
|
||||||
|
|
@ -11,9 +12,10 @@ namespace Dalamud.Game.ClientState.Actors {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This collection represents the currently spawned FFXIV actors.
|
/// This collection represents the currently spawned FFXIV actors.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class ActorTable : ICollection, IDisposable {
|
public class ActorTable : IReadOnlyCollection<Actor>, ICollection, IDisposable {
|
||||||
|
|
||||||
#region temporary imports for crash workaround
|
#region temporary imports for crash workaround
|
||||||
|
|
||||||
[DllImport("kernel32.dll", SetLastError = true)]
|
[DllImport("kernel32.dll", SetLastError = true)]
|
||||||
static extern bool ReadProcessMemory(
|
static extern bool ReadProcessMemory(
|
||||||
IntPtr hProcess,
|
IntPtr hProcess,
|
||||||
|
|
@ -21,6 +23,7 @@ namespace Dalamud.Game.ClientState.Actors {
|
||||||
IntPtr lpBuffer,
|
IntPtr lpBuffer,
|
||||||
int dwSize,
|
int dwSize,
|
||||||
out IntPtr lpNumberOfBytesRead);
|
out IntPtr lpNumberOfBytesRead);
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
private ClientStateAddressResolver Address { get; }
|
private ClientStateAddressResolver Address { get; }
|
||||||
|
|
@ -42,7 +45,8 @@ namespace Dalamud.Game.ClientState.Actors {
|
||||||
Address = addressResolver;
|
Address = addressResolver;
|
||||||
this.dalamud = dalamud;
|
this.dalamud = dalamud;
|
||||||
|
|
||||||
this.someActorTableAccessHook = new Hook<SomeActorTableAccessDelegate>(Address.SomeActorTableAccess, new SomeActorTableAccessDelegate(SomeActorTableAccessDetour), this);
|
this.someActorTableAccessHook = new Hook<SomeActorTableAccessDelegate>(
|
||||||
|
Address.SomeActorTableAccess, new SomeActorTableAccessDelegate(SomeActorTableAccessDetour), this);
|
||||||
|
|
||||||
Log.Verbose("Actor table address {ActorTable}", Address.ViewportActorTable);
|
Log.Verbose("Actor table address {ActorTable}", Address.ViewportActorTable);
|
||||||
}
|
}
|
||||||
|
|
@ -74,15 +78,14 @@ namespace Dalamud.Game.ClientState.Actors {
|
||||||
if (!this.isReady)
|
if (!this.isReady)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
if (this.someActorTableAccessHook != null)
|
if (this.someActorTableAccessHook != null) {
|
||||||
{
|
|
||||||
this.someActorTableAccessHook.Dispose();
|
this.someActorTableAccessHook.Dispose();
|
||||||
this.someActorTableAccessHook = null;
|
this.someActorTableAccessHook = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (index >= Length)
|
if (index >= Length)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
var tblIndex = this.realActorTablePtr + 8 + index * 8;
|
var tblIndex = this.realActorTablePtr + 8 + index * 8;
|
||||||
|
|
||||||
var offset = Marshal.ReadIntPtr(tblIndex);
|
var offset = Marshal.ReadIntPtr(tblIndex);
|
||||||
|
|
@ -94,9 +97,8 @@ namespace Dalamud.Game.ClientState.Actors {
|
||||||
|
|
||||||
// FIXME: hack workaround for trying to access the player on logout, after the main object has been deleted
|
// FIXME: hack workaround for trying to access the player on logout, after the main object has been deleted
|
||||||
var sz = Marshal.SizeOf(typeof(Structs.Actor));
|
var sz = Marshal.SizeOf(typeof(Structs.Actor));
|
||||||
var actorMem = Marshal.AllocHGlobal(sz); // we arguably could just reuse this
|
var actorMem = Marshal.AllocHGlobal(sz); // we arguably could just reuse this
|
||||||
if (!ReadProcessMemory(Process.GetCurrentProcess().Handle, offset, actorMem, sz, out _))
|
if (!ReadProcessMemory(Process.GetCurrentProcess().Handle, offset, actorMem, sz, out _)) {
|
||||||
{
|
|
||||||
Log.Debug("ActorTable - ReadProcessMemory failed: likely player deletion during logout");
|
Log.Debug("ActorTable - ReadProcessMemory failed: likely player deletion during logout");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
@ -106,9 +108,8 @@ namespace Dalamud.Game.ClientState.Actors {
|
||||||
|
|
||||||
//Log.Debug("ActorTable[{0}]: {1} - {2} - {3}", index, tblIndex.ToString("X"), offset.ToString("X"),
|
//Log.Debug("ActorTable[{0}]: {1} - {2} - {3}", index, tblIndex.ToString("X"), offset.ToString("X"),
|
||||||
// actorStruct.ObjectKind.ToString());
|
// actorStruct.ObjectKind.ToString());
|
||||||
|
|
||||||
switch (actorStruct.ObjectKind)
|
switch (actorStruct.ObjectKind) {
|
||||||
{
|
|
||||||
case ObjectKind.Player: return new PlayerCharacter(offset, actorStruct, this.dalamud);
|
case ObjectKind.Player: return new PlayerCharacter(offset, actorStruct, this.dalamud);
|
||||||
case ObjectKind.BattleNpc: return new BattleNpc(offset, actorStruct, this.dalamud);
|
case ObjectKind.BattleNpc: return new BattleNpc(offset, actorStruct, this.dalamud);
|
||||||
default: return new Actor(offset, actorStruct, this.dalamud);
|
default: return new Actor(offset, actorStruct, this.dalamud);
|
||||||
|
|
@ -116,7 +117,7 @@ namespace Dalamud.Game.ClientState.Actors {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ActorTableEnumerator : IEnumerator {
|
private class ActorTableEnumerator : IEnumerator<Actor> {
|
||||||
private readonly ActorTable table;
|
private readonly ActorTable table;
|
||||||
|
|
||||||
private int currentIndex;
|
private int currentIndex;
|
||||||
|
|
@ -134,18 +135,29 @@ namespace Dalamud.Game.ClientState.Actors {
|
||||||
this.currentIndex = 0;
|
this.currentIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public object Current => this.table[this.currentIndex];
|
public Actor Current => this.table[this.currentIndex];
|
||||||
|
|
||||||
|
object IEnumerator.Current => Current;
|
||||||
|
|
||||||
|
// Required by IEnumerator<T> even though we have nothing we want to dispose here.
|
||||||
|
public void Dispose() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerator GetEnumerator() {
|
public IEnumerator<Actor> GetEnumerator() {
|
||||||
return new ActorTableEnumerator(this);
|
return new ActorTableEnumerator(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IEnumerator IEnumerable.GetEnumerator() {
|
||||||
|
return GetEnumerator();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The amount of currently spawned actors.
|
/// The amount of currently spawned actors.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int Length => !this.isReady ? 0 : Marshal.ReadInt32(this.realActorTablePtr);
|
public int Length => !this.isReady ? 0 : Marshal.ReadInt32(this.realActorTablePtr);
|
||||||
|
|
||||||
|
int IReadOnlyCollection<Actor>.Count => Length;
|
||||||
|
|
||||||
int ICollection.Count => Length;
|
int ICollection.Count => Length;
|
||||||
|
|
||||||
bool ICollection.IsSynchronized => false;
|
bool ICollection.IsSynchronized => false;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue