diff --git a/Dalamud/Game/Addon/Events/AddonEventListener.cs b/Dalamud/Game/Addon/Events/AddonEventListener.cs index ceac38108..a2498d5a7 100644 --- a/Dalamud/Game/Addon/Events/AddonEventListener.cs +++ b/Dalamud/Game/Addon/Events/AddonEventListener.cs @@ -67,7 +67,10 @@ internal unsafe class AddonEventListener : IDisposable { if (node is null) return; - node->AddEvent(eventType, param, this.eventListener, (AtkResNode*)addon, false); + Service.Get().RunOnFrameworkThread(() => + { + node->AddEvent(eventType, param, this.eventListener, (AtkResNode*)addon, false); + }); } /// @@ -80,7 +83,10 @@ internal unsafe class AddonEventListener : IDisposable { if (node is null) return; - node->RemoveEvent(eventType, param, this.eventListener, false); + Service.Get().RunOnFrameworkThread(() => + { + node->RemoveEvent(eventType, param, this.eventListener, false); + }); } [UnmanagedCallersOnly] diff --git a/Dalamud/Game/Addon/Events/AddonEventManager.cs b/Dalamud/Game/Addon/Events/AddonEventManager.cs index af713a771..4231b0d09 100644 --- a/Dalamud/Game/Addon/Events/AddonEventManager.cs +++ b/Dalamud/Game/Addon/Events/AddonEventManager.cs @@ -1,5 +1,4 @@ -using System.Collections.Generic; -using System.Linq; +using System.Collections.Concurrent; using Dalamud.Game.Addon.Lifecycle; using Dalamud.Game.Addon.Lifecycle.AddonArgTypes; @@ -9,7 +8,6 @@ using Dalamud.IoC.Internal; using Dalamud.Logging.Internal; using Dalamud.Plugin.Internal.Types; using Dalamud.Plugin.Services; -using Dalamud.Utility; using FFXIVClientStructs.FFXIV.Client.UI; using FFXIVClientStructs.FFXIV.Component.GUI; @@ -26,22 +24,19 @@ internal unsafe class AddonEventManager : IDisposable, IServiceType /// /// PluginName for Dalamud Internal use. /// - public const string DalamudInternalKey = "Dalamud.Internal"; + public static readonly Guid DalamudInternalKey = Guid.NewGuid(); private static readonly ModuleLog Log = new("AddonEventManager"); [ServiceManager.ServiceDependency] private readonly AddonLifecycle addonLifecycle = Service.Get(); - [ServiceManager.ServiceDependency] - private readonly Framework framework = Service.Get(); - private readonly AddonLifecycleEventListener finalizeEventListener; private readonly AddonEventManagerAddressResolver address; private readonly Hook onUpdateCursor; - private readonly List pluginEventControllers; + private readonly ConcurrentDictionary pluginEventControllers; private AddonCursorType? cursorOverride; @@ -51,10 +46,8 @@ internal unsafe class AddonEventManager : IDisposable, IServiceType this.address = new AddonEventManagerAddressResolver(); this.address.Setup(sigScanner); - this.pluginEventControllers = new List - { - new(DalamudInternalKey), // Create entry for Dalamud's Internal Use. - }; + this.pluginEventControllers = new ConcurrentDictionary(); + this.pluginEventControllers.TryAdd(DalamudInternalKey, new PluginEventController()); this.cursorOverride = null; @@ -73,7 +66,7 @@ internal unsafe class AddonEventManager : IDisposable, IServiceType { this.onUpdateCursor.Dispose(); - foreach (var pluginEventController in this.pluginEventControllers) + foreach (var (_, pluginEventController) in this.pluginEventControllers) { pluginEventController.Dispose(); } @@ -90,16 +83,17 @@ internal unsafe class AddonEventManager : IDisposable, IServiceType /// The event type for this event. /// The handler to call when event is triggered. /// IAddonEventHandle used to remove the event. - internal IAddonEventHandle? AddEvent(string pluginId, IntPtr atkUnitBase, IntPtr atkResNode, AddonEventType eventType, IAddonEventManager.AddonEventHandler eventHandler) + internal IAddonEventHandle? AddEvent(Guid pluginId, IntPtr atkUnitBase, IntPtr atkResNode, AddonEventType eventType, IAddonEventManager.AddonEventHandler eventHandler) { - if (!ThreadSafety.IsMainThread) throw new InvalidOperationException("This should be done only from the main thread. Modifying active native code on non-main thread is not supported."); - - if (this.pluginEventControllers.FirstOrDefault(entry => entry.PluginId == pluginId) is { } eventController) + if (this.pluginEventControllers.TryGetValue(pluginId, out var controller)) { - return eventController.AddEvent(atkUnitBase, atkResNode, eventType, eventHandler); + return controller.AddEvent(atkUnitBase, atkResNode, eventType, eventHandler); + } + else + { + Log.Verbose($"Unable to locate controller for {pluginId}. No event was added."); } - Log.Verbose($"Unable to locate controller for {pluginId}. No event was added."); return null; } @@ -108,13 +102,11 @@ internal unsafe class AddonEventManager : IDisposable, IServiceType /// /// Unique ID for this plugin. /// The Unique Id for this event. - internal void RemoveEvent(string pluginId, IAddonEventHandle eventHandle) + internal void RemoveEvent(Guid pluginId, IAddonEventHandle eventHandle) { - if (!ThreadSafety.IsMainThread) throw new InvalidOperationException("This should be done only from the main thread. Modifying active native code on non-main thread is not supported."); - - if (this.pluginEventControllers.FirstOrDefault(entry => entry.PluginId == pluginId) is { } eventController) + if (this.pluginEventControllers.TryGetValue(pluginId, out var controller)) { - eventController.RemoveEvent(eventHandle); + controller.RemoveEvent(eventHandle); } else { @@ -137,33 +129,28 @@ internal unsafe class AddonEventManager : IDisposable, IServiceType /// Adds a new managed event controller if one doesn't already exist for this pluginId. /// /// Unique ID for this plugin. - internal void AddPluginEventController(string pluginId) + internal void AddPluginEventController(Guid pluginId) { - this.framework.RunOnFrameworkThread(() => - { - if (this.pluginEventControllers.All(entry => entry.PluginId != pluginId)) + this.pluginEventControllers.GetOrAdd( + pluginId, + key => { - Log.Verbose($"Creating new PluginEventController for: {pluginId}"); - this.pluginEventControllers.Add(new PluginEventController(pluginId)); - } - }); + Log.Verbose($"Creating new PluginEventController for: {key}"); + return new PluginEventController(); + }); } /// /// Removes an existing managed event controller for the specified plugin. /// /// Unique ID for this plugin. - internal void RemovePluginEventController(string pluginId) + internal void RemovePluginEventController(Guid pluginId) { - this.framework.RunOnFrameworkThread(() => + if (this.pluginEventControllers.TryRemove(pluginId, out var controller)) { - if (this.pluginEventControllers.FirstOrDefault(entry => entry.PluginId == pluginId) is { } controller) - { - Log.Verbose($"Removing PluginEventController for: {pluginId}"); - this.pluginEventControllers.Remove(controller); - controller.Dispose(); - } - }); + Log.Verbose($"Removing PluginEventController for: {pluginId}"); + controller.Dispose(); + } } /// @@ -178,7 +165,7 @@ internal unsafe class AddonEventManager : IDisposable, IServiceType foreach (var pluginList in this.pluginEventControllers) { - pluginList.RemoveForAddon(addonInfo.AddonName); + pluginList.Value.RemoveForAddon(addonInfo.AddonName); } } @@ -234,7 +221,7 @@ internal class AddonEventManagerPluginScoped : IDisposable, IServiceType, IAddon { this.plugin = plugin; - this.eventManagerService.AddPluginEventController(plugin.Manifest.WorkingPluginId.ToString()); + this.eventManagerService.AddPluginEventController(plugin.Manifest.WorkingPluginId); } /// @@ -246,16 +233,16 @@ internal class AddonEventManagerPluginScoped : IDisposable, IServiceType, IAddon this.eventManagerService.ResetCursor(); } - this.eventManagerService.RemovePluginEventController(this.plugin.Manifest.WorkingPluginId.ToString()); + this.eventManagerService.RemovePluginEventController(this.plugin.Manifest.WorkingPluginId); } /// public IAddonEventHandle? AddEvent(IntPtr atkUnitBase, IntPtr atkResNode, AddonEventType eventType, IAddonEventManager.AddonEventHandler eventHandler) - => this.eventManagerService.AddEvent(this.plugin.Manifest.WorkingPluginId.ToString(), atkUnitBase, atkResNode, eventType, eventHandler); + => this.eventManagerService.AddEvent(this.plugin.Manifest.WorkingPluginId, atkUnitBase, atkResNode, eventType, eventHandler); /// public void RemoveEvent(IAddonEventHandle eventHandle) - => this.eventManagerService.RemoveEvent(this.plugin.Manifest.WorkingPluginId.ToString(), eventHandle); + => this.eventManagerService.RemoveEvent(this.plugin.Manifest.WorkingPluginId, eventHandle); /// public void SetCursor(AddonCursorType cursor) diff --git a/Dalamud/Game/Addon/Events/PluginEventController.cs b/Dalamud/Game/Addon/Events/PluginEventController.cs index 7847dd482..3ba067a6d 100644 --- a/Dalamud/Game/Addon/Events/PluginEventController.cs +++ b/Dalamud/Game/Addon/Events/PluginEventController.cs @@ -19,19 +19,11 @@ internal unsafe class PluginEventController : IDisposable /// /// Initializes a new instance of the class. /// - /// The Unique ID for this plugin. - public PluginEventController(string pluginId) + public PluginEventController() { - this.PluginId = pluginId; - this.EventListener = new AddonEventListener(this.PluginEventListHandler); } - /// - /// Gets the unique ID for this PluginEventList. - /// - public string PluginId { get; init; } - private AddonEventListener EventListener { get; init; } private List Events { get; } = new(); @@ -125,7 +117,7 @@ internal unsafe class PluginEventController : IDisposable if (this.Events.All(registeredEvent => registeredEvent.ParamKey != i)) return i; } - throw new OverflowException($"uint.MaxValue number of ParamKeys used for {this.PluginId}"); + throw new OverflowException($"uint.MaxValue number of ParamKeys used for this event controller."); } ///