mirror of
https://github.com/goatcorp/Dalamud.git
synced 2026-02-25 06:01:49 +01:00
Fix Addon/Agent Lifecycle Register/Unregister
This commit is contained in:
parent
05969f02ad
commit
a68248fdf8
2 changed files with 116 additions and 77 deletions
|
|
@ -31,7 +31,7 @@ internal unsafe class AddonLifecycle : IInternalDisposableService
|
|||
private readonly Framework framework = Service<Framework>.Get();
|
||||
|
||||
private Hook<AtkUnitBase.Delegates.Initialize>? onInitializeAddonHook;
|
||||
private bool isInvokingListeners = false;
|
||||
private bool isInvokingListeners;
|
||||
|
||||
[ServiceManager.ServiceConstructor]
|
||||
private AddonLifecycle()
|
||||
|
|
@ -56,29 +56,33 @@ internal unsafe class AddonLifecycle : IInternalDisposableService
|
|||
AllocatedTables.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resolves a virtual table address to the original virtual table address.
|
||||
/// </summary>
|
||||
/// <param name="tableAddress">The modified address to resolve.</param>
|
||||
/// <returns>The original address.</returns>
|
||||
internal static AtkUnitBase.AtkUnitBaseVirtualTable* GetOriginalVirtualTable(AtkUnitBase.AtkUnitBaseVirtualTable* tableAddress)
|
||||
{
|
||||
var matchedTable = AllocatedTables.FirstOrDefault(table => table.ModifiedVirtualTable == tableAddress);
|
||||
if (matchedTable == null) return null;
|
||||
|
||||
return matchedTable.OriginalVirtualTable;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Register a listener for the target event and addon.
|
||||
/// </summary>
|
||||
/// <param name="listener">The listener to register.</param>
|
||||
internal void RegisterListener(AddonLifecycleEventListener listener)
|
||||
{
|
||||
this.framework.RunOnTick(() =>
|
||||
if (this.isInvokingListeners)
|
||||
{
|
||||
if (!this.EventListeners.ContainsKey(listener.EventType))
|
||||
{
|
||||
if (!this.EventListeners.TryAdd(listener.EventType, []))
|
||||
return;
|
||||
}
|
||||
|
||||
// Note: string.Empty is a valid addon name, as that will trigger on any addon for this event type
|
||||
if (!this.EventListeners[listener.EventType].ContainsKey(listener.AddonName))
|
||||
{
|
||||
if (!this.EventListeners[listener.EventType].TryAdd(listener.AddonName, []))
|
||||
return;
|
||||
}
|
||||
|
||||
this.EventListeners[listener.EventType][listener.AddonName].Add(listener);
|
||||
}, delayTicks: this.isInvokingListeners ? 1 : 0);
|
||||
this.framework.RunOnTick(() => this.RegisterListenerMethod(listener));
|
||||
}
|
||||
else
|
||||
{
|
||||
this.framework.RunOnFrameworkThread(() => this.RegisterListenerMethod(listener));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -87,16 +91,14 @@ internal unsafe class AddonLifecycle : IInternalDisposableService
|
|||
/// <param name="listener">The listener to unregister.</param>
|
||||
internal void UnregisterListener(AddonLifecycleEventListener listener)
|
||||
{
|
||||
this.framework.RunOnTick(() =>
|
||||
if (this.isInvokingListeners)
|
||||
{
|
||||
if (this.EventListeners.TryGetValue(listener.EventType, out var addonListeners))
|
||||
{
|
||||
if (addonListeners.TryGetValue(listener.AddonName, out var addonListener))
|
||||
{
|
||||
addonListener.Remove(listener);
|
||||
}
|
||||
}
|
||||
}, delayTicks: this.isInvokingListeners ? 1 : 0);
|
||||
this.framework.RunOnTick(() => this.UnregisterListenerMethod(listener));
|
||||
}
|
||||
else
|
||||
{
|
||||
this.framework.RunOnFrameworkThread(() => this.UnregisterListenerMethod(listener));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -147,17 +149,38 @@ internal unsafe class AddonLifecycle : IInternalDisposableService
|
|||
this.isInvokingListeners = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resolves a virtual table address to the original virtual table address.
|
||||
/// </summary>
|
||||
/// <param name="tableAddress">The modified address to resolve.</param>
|
||||
/// <returns>The original address.</returns>
|
||||
internal AtkUnitBase.AtkUnitBaseVirtualTable* GetOriginalVirtualTable(AtkUnitBase.AtkUnitBaseVirtualTable* tableAddress)
|
||||
private void RegisterListenerMethod(AddonLifecycleEventListener listener)
|
||||
{
|
||||
var matchedTable = AllocatedTables.FirstOrDefault(table => table.ModifiedVirtualTable == tableAddress);
|
||||
if (matchedTable == null) return null;
|
||||
if (!this.EventListeners.ContainsKey(listener.EventType))
|
||||
{
|
||||
if (!this.EventListeners.TryAdd(
|
||||
listener.EventType,
|
||||
[
|
||||
])) return;
|
||||
}
|
||||
|
||||
return matchedTable.OriginalVirtualTable;
|
||||
// Note: string.Empty is a valid addon name, as that will trigger on any addon for this event type
|
||||
if (!this.EventListeners[listener.EventType].ContainsKey(listener.AddonName))
|
||||
{
|
||||
if (!this.EventListeners[listener.EventType]
|
||||
.TryAdd(
|
||||
listener.AddonName,
|
||||
[
|
||||
])) return;
|
||||
}
|
||||
|
||||
this.EventListeners[listener.EventType][listener.AddonName].Add(listener);
|
||||
}
|
||||
|
||||
private void UnregisterListenerMethod(AddonLifecycleEventListener listener)
|
||||
{
|
||||
if (this.EventListeners.TryGetValue(listener.EventType, out var addonListeners))
|
||||
{
|
||||
if (addonListeners.TryGetValue(listener.AddonName, out var addonListener))
|
||||
{
|
||||
addonListener.Remove(listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnAddonInitialize(AtkUnitBase* addon)
|
||||
|
|
@ -277,5 +300,5 @@ internal class AddonLifecyclePluginScoped : IInternalDisposableService, IAddonLi
|
|||
|
||||
/// <inheritdoc/>
|
||||
public unsafe nint GetOriginalVirtualTable(nint virtualTableAddress)
|
||||
=> (nint)this.addonLifecycleService.GetOriginalVirtualTable((AtkUnitBase.AtkUnitBaseVirtualTable*)virtualTableAddress);
|
||||
=> (nint)AddonLifecycle.GetOriginalVirtualTable((AtkUnitBase.AtkUnitBaseVirtualTable*)virtualTableAddress);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,30 +69,33 @@ internal unsafe class AgentLifecycle : IInternalDisposableService
|
|||
AllocatedTables.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resolves a virtual table address to the original virtual table address.
|
||||
/// </summary>
|
||||
/// <param name="tableAddress">The modified address to resolve.</param>
|
||||
/// <returns>The original address.</returns>
|
||||
internal static AgentInterface.AgentInterfaceVirtualTable* GetOriginalVirtualTable(AgentInterface.AgentInterfaceVirtualTable* tableAddress)
|
||||
{
|
||||
var matchedTable = AllocatedTables.FirstOrDefault(table => table.ModifiedVirtualTable == tableAddress);
|
||||
if (matchedTable == null) return null;
|
||||
|
||||
return matchedTable.OriginalVirtualTable;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Register a listener for the target event and agent.
|
||||
/// </summary>
|
||||
/// <param name="listener">The listener to register.</param>
|
||||
internal void RegisterListener(AgentLifecycleEventListener listener)
|
||||
{
|
||||
this.framework.RunOnTick(() =>
|
||||
if (this.isInvokingListeners)
|
||||
{
|
||||
if (!this.EventListeners.ContainsKey(listener.EventType))
|
||||
{
|
||||
if (!this.EventListeners.TryAdd(listener.EventType, []))
|
||||
return;
|
||||
}
|
||||
|
||||
// Note: uint.MaxValue is a valid agent id, as that will trigger on any agent for this event type
|
||||
if (!this.EventListeners[listener.EventType].ContainsKey(listener.AgentId))
|
||||
{
|
||||
if (!this.EventListeners[listener.EventType].TryAdd(listener.AgentId, []))
|
||||
return;
|
||||
}
|
||||
|
||||
this.EventListeners[listener.EventType][listener.AgentId].Add(listener);
|
||||
},
|
||||
delayTicks: this.isInvokingListeners ? 1 : 0);
|
||||
this.framework.RunOnTick(() => this.RegisterListenerMethod(listener));
|
||||
}
|
||||
else
|
||||
{
|
||||
this.framework.RunOnFrameworkThread(() => this.RegisterListenerMethod(listener));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -101,17 +104,14 @@ internal unsafe class AgentLifecycle : IInternalDisposableService
|
|||
/// <param name="listener">The listener to unregister.</param>
|
||||
internal void UnregisterListener(AgentLifecycleEventListener listener)
|
||||
{
|
||||
this.framework.RunOnTick(() =>
|
||||
if (this.isInvokingListeners)
|
||||
{
|
||||
if (this.EventListeners.TryGetValue(listener.EventType, out var agentListeners))
|
||||
{
|
||||
if (agentListeners.TryGetValue(listener.AgentId, out var agentListener))
|
||||
{
|
||||
agentListener.Remove(listener);
|
||||
}
|
||||
}
|
||||
},
|
||||
delayTicks: this.isInvokingListeners ? 1 : 0);
|
||||
this.framework.RunOnTick(() => this.UnregisterListenerMethod(listener));
|
||||
}
|
||||
else
|
||||
{
|
||||
this.framework.RunOnFrameworkThread(() => this.UnregisterListenerMethod(listener));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -162,19 +162,6 @@ internal unsafe class AgentLifecycle : IInternalDisposableService
|
|||
this.isInvokingListeners = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resolves a virtual table address to the original virtual table address.
|
||||
/// </summary>
|
||||
/// <param name="tableAddress">The modified address to resolve.</param>
|
||||
/// <returns>The original address.</returns>
|
||||
internal AgentInterface.AgentInterfaceVirtualTable* GetOriginalVirtualTable(AgentInterface.AgentInterfaceVirtualTable* tableAddress)
|
||||
{
|
||||
var matchedTable = AllocatedTables.FirstOrDefault(table => table.ModifiedVirtualTable == tableAddress);
|
||||
if (matchedTable == null) return null;
|
||||
|
||||
return matchedTable.OriginalVirtualTable;
|
||||
}
|
||||
|
||||
private void OnAgentModuleInitialize(AgentModule* thisPtr, UIModule* uiModule)
|
||||
{
|
||||
this.onInitializeAgentsHook!.Original(thisPtr, uiModule);
|
||||
|
|
@ -193,6 +180,35 @@ internal unsafe class AgentLifecycle : IInternalDisposableService
|
|||
}
|
||||
}
|
||||
|
||||
private void RegisterListenerMethod(AgentLifecycleEventListener listener)
|
||||
{
|
||||
if (!this.EventListeners.ContainsKey(listener.EventType))
|
||||
{
|
||||
if (!this.EventListeners.TryAdd(listener.EventType, []))
|
||||
return;
|
||||
}
|
||||
|
||||
// Note: uint.MaxValue is a valid agent id, as that will trigger on any agent for this event type
|
||||
if (!this.EventListeners[listener.EventType].ContainsKey(listener.AgentId))
|
||||
{
|
||||
if (!this.EventListeners[listener.EventType].TryAdd(listener.AgentId, []))
|
||||
return;
|
||||
}
|
||||
|
||||
this.EventListeners[listener.EventType][listener.AgentId].Add(listener);
|
||||
}
|
||||
|
||||
private void UnregisterListenerMethod(AgentLifecycleEventListener listener)
|
||||
{
|
||||
if (this.EventListeners.TryGetValue(listener.EventType, out var agentListeners))
|
||||
{
|
||||
if (agentListeners.TryGetValue(listener.AgentId, out var agentListener))
|
||||
{
|
||||
agentListener.Remove(listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ReplaceVirtualTables(AgentModule* agentModule)
|
||||
{
|
||||
foreach (uint index in Enumerable.Range(0, agentModule->Agents.Length))
|
||||
|
|
@ -311,5 +327,5 @@ internal class AgentLifecyclePluginScoped : IInternalDisposableService, IAgentLi
|
|||
|
||||
/// <inheritdoc/>
|
||||
public unsafe nint GetOriginalVirtualTable(nint virtualTableAddress)
|
||||
=> (nint)this.agentLifecycleService.GetOriginalVirtualTable((AgentInterface.AgentInterfaceVirtualTable*)virtualTableAddress);
|
||||
=> (nint)AgentLifecycle.GetOriginalVirtualTable((AgentInterface.AgentInterfaceVirtualTable*)virtualTableAddress);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue