diff --git a/Dalamud/Game/ClientState/Actors/ActorTable.cs b/Dalamud/Game/ClientState/Actors/ActorTable.cs
index 407ce7132..65b874a00 100644
--- a/Dalamud/Game/ClientState/Actors/ActorTable.cs
+++ b/Dalamud/Game/ClientState/Actors/ActorTable.cs
@@ -1,9 +1,7 @@
using System;
using System.Collections;
-using System.Runtime.ExceptionServices;
+using System.Diagnostics;
using System.Runtime.InteropServices;
-using System.Security;
-using System.Windows.Forms;
using Dalamud.Game.ClientState.Actors.Types;
using Dalamud.Game.ClientState.Actors.Types.NonPlayer;
using Dalamud.Hooking;
@@ -14,6 +12,17 @@ namespace Dalamud.Game.ClientState.Actors {
/// This collection represents the currently spawned FFXIV actors.
///
public class ActorTable : ICollection, IDisposable {
+
+ #region temporary imports for crash workaround
+ [DllImport("kernel32.dll", SetLastError = true)]
+ static extern bool ReadProcessMemory(
+ IntPtr hProcess,
+ IntPtr lpBaseAddress,
+ IntPtr lpBuffer,
+ int dwSize,
+ out IntPtr lpNumberOfBytesRead);
+ #endregion
+
private ClientStateAddressResolver Address { get; }
private Dalamud dalamud;
@@ -45,6 +54,8 @@ namespace Dalamud.Game.ClientState.Actors {
public void Dispose() {
if (!this.isReady)
this.someActorTableAccessHook.Dispose();
+
+ this.isReady = false;
}
private IntPtr SomeActorTableAccessDetour(IntPtr manager, IntPtr offset) {
@@ -58,12 +69,8 @@ namespace Dalamud.Game.ClientState.Actors {
///
/// Spawn index.
/// at the specified spawn index.
- public Actor this[int index] => At(index);
-
- [HandleProcessCorruptedStateExceptions]
- [SecurityCritical]
- private Actor At(int index) {
- try {
+ public Actor this[int index] {
+ get {
if (!this.isReady)
return null;
@@ -73,7 +80,7 @@ namespace Dalamud.Game.ClientState.Actors {
this.someActorTableAccessHook = null;
}
- if (index > Length)
+ if (index >= Length)
return null;
var tblIndex = this.realActorTablePtr + 8 + index * 8;
@@ -85,27 +92,27 @@ namespace Dalamud.Game.ClientState.Actors {
if (offset == IntPtr.Zero)
return null;
- try
- {
- var actorStruct = Marshal.PtrToStructure(offset);
-
- //Log.Debug("ActorTable[{0}]: {1} - {2} - {3}", index, tblIndex.ToString("X"), offset.ToString("X"),
- // actorStruct.ObjectKind.ToString());
-
- switch (actorStruct.ObjectKind)
- {
- case ObjectKind.Player: return new PlayerCharacter(actorStruct, this.dalamud);
- case ObjectKind.BattleNpc: return new BattleNpc(actorStruct, this.dalamud);
- default: return new Actor(actorStruct, this.dalamud);
- }
- }
- catch (AccessViolationException)
+ // 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 actorMem = Marshal.AllocHGlobal(sz); // we arguably could just reuse this
+ if (!ReadProcessMemory(Process.GetCurrentProcess().Handle, offset, actorMem, sz, out _))
{
+ Log.Debug("ActorTable - ReadProcessMemory failed: likely player deletion during logout");
return null;
}
- } catch (Exception e) {
- Log.Error(e, "Could not get Actor.");
- return null;
+
+ var actorStruct = Marshal.PtrToStructure(actorMem);
+ Marshal.FreeHGlobal(actorMem);
+
+ //Log.Debug("ActorTable[{0}]: {1} - {2} - {3}", index, tblIndex.ToString("X"), offset.ToString("X"),
+ // actorStruct.ObjectKind.ToString());
+
+ switch (actorStruct.ObjectKind)
+ {
+ case ObjectKind.Player: return new PlayerCharacter(actorStruct, this.dalamud);
+ case ObjectKind.BattleNpc: return new BattleNpc(actorStruct, this.dalamud);
+ default: return new Actor(actorStruct, this.dalamud);
+ }
}
}