Merge pull request #2566 from MidoriKami/AddonLifecycleThreadSafety

IAddonLifecycle Thread Safety
This commit is contained in:
goat 2026-01-10 13:13:36 +01:00 committed by GitHub
commit 55eb7e41d8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -27,7 +27,11 @@ internal unsafe class AddonLifecycle : IInternalDisposableService
private static readonly ModuleLog Log = ModuleLog.Create<AddonLifecycle>(); private static readonly ModuleLog Log = ModuleLog.Create<AddonLifecycle>();
[ServiceManager.ServiceDependency]
private readonly Framework framework = Service<Framework>.Get();
private Hook<AtkUnitBase.Delegates.Initialize>? onInitializeAddonHook; private Hook<AtkUnitBase.Delegates.Initialize>? onInitializeAddonHook;
private bool isInvokingListeners = false;
[ServiceManager.ServiceConstructor] [ServiceManager.ServiceConstructor]
private AddonLifecycle() private AddonLifecycle()
@ -57,6 +61,8 @@ internal unsafe class AddonLifecycle : IInternalDisposableService
/// </summary> /// </summary>
/// <param name="listener">The listener to register.</param> /// <param name="listener">The listener to register.</param>
internal void RegisterListener(AddonLifecycleEventListener listener) internal void RegisterListener(AddonLifecycleEventListener listener)
{
this.framework.RunOnTick(() =>
{ {
if (!this.EventListeners.ContainsKey(listener.EventType)) if (!this.EventListeners.ContainsKey(listener.EventType))
{ {
@ -72,6 +78,7 @@ internal unsafe class AddonLifecycle : IInternalDisposableService
} }
this.EventListeners[listener.EventType][listener.AddonName].Add(listener); this.EventListeners[listener.EventType][listener.AddonName].Add(listener);
}, delayTicks: this.isInvokingListeners ? 1 : 0);
} }
/// <summary> /// <summary>
@ -79,6 +86,8 @@ internal unsafe class AddonLifecycle : IInternalDisposableService
/// </summary> /// </summary>
/// <param name="listener">The listener to unregister.</param> /// <param name="listener">The listener to unregister.</param>
internal void UnregisterListener(AddonLifecycleEventListener listener) internal void UnregisterListener(AddonLifecycleEventListener listener)
{
this.framework.RunOnTick(() =>
{ {
if (this.EventListeners.TryGetValue(listener.EventType, out var addonListeners)) if (this.EventListeners.TryGetValue(listener.EventType, out var addonListeners))
{ {
@ -87,6 +96,7 @@ internal unsafe class AddonLifecycle : IInternalDisposableService
addonListener.Remove(listener); addonListener.Remove(listener);
} }
} }
}, delayTicks: this.isInvokingListeners ? 1 : 0);
} }
/// <summary> /// <summary>
@ -97,6 +107,8 @@ internal unsafe class AddonLifecycle : IInternalDisposableService
/// <param name="blame">What to blame on errors.</param> /// <param name="blame">What to blame on errors.</param>
internal void InvokeListenersSafely(AddonEvent eventType, AddonArgs args, [CallerMemberName] string blame = "") internal void InvokeListenersSafely(AddonEvent eventType, AddonArgs args, [CallerMemberName] string blame = "")
{ {
this.isInvokingListeners = true;
// Early return if we don't have any listeners of this type // Early return if we don't have any listeners of this type
if (!this.EventListeners.TryGetValue(eventType, out var addonListeners)) return; if (!this.EventListeners.TryGetValue(eventType, out var addonListeners)) return;
@ -131,6 +143,8 @@ internal unsafe class AddonLifecycle : IInternalDisposableService
} }
} }
} }
this.isInvokingListeners = false;
} }
/// <summary> /// <summary>