Better unload

This commit is contained in:
MidoriKami 2025-11-30 10:08:40 -08:00
parent b8724f7a59
commit c51e65e0bd
2 changed files with 14 additions and 34 deletions

View file

@ -19,13 +19,13 @@ namespace Dalamud.Game.Addon.Lifecycle;
[ServiceManager.EarlyLoadedService]
internal unsafe class AddonLifecycle : IInternalDisposableService
{
/// <summary>
/// Gets a list of all allocated addon virtual tables.
/// </summary>
public static readonly List<AddonVirtualTable> AllocatedTables = [];
private static readonly ModuleLog Log = new("AddonLifecycle");
[ServiceManager.ServiceDependency]
private readonly Framework framework = Service<Framework>.Get();
private readonly Dictionary<string, AddonVirtualTable> modifiedTables = [];
private Hook<AtkUnitBase.Delegates.Initialize>? onInitializeAddonHook;
[ServiceManager.ServiceConstructor]
@ -47,13 +47,8 @@ internal unsafe class AddonLifecycle : IInternalDisposableService
this.onInitializeAddonHook?.Dispose();
this.onInitializeAddonHook = null;
this.framework.RunOnFrameworkThread(() =>
{
foreach (var virtualTable in this.modifiedTables.Values)
{
virtualTable.Dispose();
}
});
AllocatedTables.ForEach(entry => entry.Dispose());
AllocatedTables.Clear();
}
/// <summary>
@ -141,18 +136,8 @@ internal unsafe class AddonLifecycle : IInternalDisposableService
{
this.LogInitialize(addon->NameString);
if (!this.modifiedTables.ContainsKey(addon->NameString))
{
// AddonVirtualTable class handles creating the virtual table, and overriding each of the tracked virtual functions
var managedVirtualTableEntry = new AddonVirtualTable(addon, this)
{
// This event is invoked when the game itself has disposed of an addon
// We can use this to know when to remove our virtual table entry
OnAddonFinalized = () => this.modifiedTables.Remove(addon->NameString),
};
this.modifiedTables.Add(addon->NameString, managedVirtualTableEntry);
}
// AddonVirtualTable class handles creating the virtual table, and overriding each of the tracked virtual functions
AllocatedTables.Add(new AddonVirtualTable(addon, this));
}
catch (Exception e)
{

View file

@ -1,6 +1,7 @@
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading;
using Dalamud.Game.Addon.Lifecycle.AddonArgTypes;
using Dalamud.Logging.Internal;
@ -108,17 +109,11 @@ internal unsafe class AddonVirtualTable : IDisposable
this.modifiedVirtualTable->Hide = (delegate* unmanaged<AtkUnitBase*, bool, bool, uint, void>)Marshal.GetFunctionPointerForDelegate(this.hideFunction);
}
/// <summary>
/// Gets an event that is invoked when this addon's Finalize method is called from native.
/// </summary>
public required Action OnAddonFinalized { get; init; }
/// <summary>
/// <em>WARNING!</em> This should not be called at any time except during dalamud unload.
/// </summary>
/// <inheritdoc/>
public void Dispose()
{
this.atkUnitBase->VirtualTable = this.originalVirtualTable;
// Ensure restoration is done atomically.
Interlocked.Exchange(ref *(nint*)&this.atkUnitBase->VirtualTable, (nint)this.originalVirtualTable);
IMemorySpace.Free(this.modifiedVirtualTable, 0x8 * VirtualTableEntryCount);
}
@ -131,7 +126,7 @@ internal unsafe class AddonVirtualTable : IDisposable
if ((freeFlags & 1) == 1)
{
IMemorySpace.Free(this.modifiedVirtualTable, 0x8 * VirtualTableEntryCount);
this.OnAddonFinalized();
AddonLifecycle.AllocatedTables.Remove(this);
}
return result;