diff --git a/Torch/Managers/EventManager/EventHandlerAttribute.cs b/Torch.API/Managers/Event/EventHandlerAttribute.cs similarity index 87% rename from Torch/Managers/EventManager/EventHandlerAttribute.cs rename to Torch.API/Managers/Event/EventHandlerAttribute.cs index 362e27c..58e3bb4 100644 --- a/Torch/Managers/EventManager/EventHandlerAttribute.cs +++ b/Torch.API/Managers/Event/EventHandlerAttribute.cs @@ -1,10 +1,6 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace Torch.Managers.EventManager +namespace Torch.API.Managers.Event { /// /// Attribute indicating that a method should be invoked when the event occurs. diff --git a/Torch/Managers/EventManager/IEvent.cs b/Torch.API/Managers/Event/IEvent.cs similarity index 63% rename from Torch/Managers/EventManager/IEvent.cs rename to Torch.API/Managers/Event/IEvent.cs index 0226c36..27537d8 100644 --- a/Torch/Managers/EventManager/IEvent.cs +++ b/Torch.API/Managers/Event/IEvent.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Torch.Managers.EventManager +namespace Torch.API.Managers.Event { public interface IEvent { diff --git a/Torch.API/Managers/Event/IEventHandler.cs b/Torch.API/Managers/Event/IEventHandler.cs new file mode 100644 index 0000000..58dee25 --- /dev/null +++ b/Torch.API/Managers/Event/IEventHandler.cs @@ -0,0 +1,9 @@ +namespace Torch.API.Managers.Event +{ + /// + /// Interface used to tag an event handler. This does not register it with the event manager. + /// + public interface IEventHandler + { + } +} diff --git a/Torch.API/Managers/Event/IEventManager.cs b/Torch.API/Managers/Event/IEventManager.cs new file mode 100644 index 0000000..6daef0c --- /dev/null +++ b/Torch.API/Managers/Event/IEventManager.cs @@ -0,0 +1,27 @@ +using System.Runtime.CompilerServices; + +namespace Torch.API.Managers.Event +{ + /// + /// Manager class responsible for registration of event handlers. + /// + public interface IEventManager + { + /// + /// Registers all event handler methods contained in the given instance + /// + /// Instance to register + /// true if added, false otherwise + [MethodImpl(MethodImplOptions.NoInlining)] + bool RegisterHandler(IEventHandler handler); + + + /// + /// Unregisters all event handler methods contained in the given instance + /// + /// Instance to unregister + /// true if removed, false otherwise + [MethodImpl(MethodImplOptions.NoInlining)] + bool UnregisterHandler(IEventHandler handler); + } +} diff --git a/Torch/Managers/EventManager/EventList.cs b/Torch/Managers/Event/EventList.cs similarity index 95% rename from Torch/Managers/EventManager/EventList.cs rename to Torch/Managers/Event/EventList.cs index a463b9a..977e5b0 100644 --- a/Torch/Managers/EventManager/EventList.cs +++ b/Torch/Managers/Event/EventList.cs @@ -1,13 +1,12 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; -using System.Text; using System.Threading; -using System.Threading.Tasks; +using Torch.API.Managers.Event; +using Torch.Managers.EventManager; -namespace Torch.Managers.EventManager +namespace Torch.Managers.Event { /// /// Represents an ordered list of callbacks. @@ -49,7 +48,7 @@ namespace Torch.Managers.EventManager private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion); /// - public void AddHandler(MethodInfo method, object instance) + public void AddHandler(MethodInfo method, IEventHandler instance) { try { @@ -64,7 +63,7 @@ namespace Torch.Managers.EventManager } /// - public int RemoveHandlers(object instance) + public int RemoveHandlers(IEventHandler instance) { try { diff --git a/Torch/Managers/EventManager/EventManager.cs b/Torch/Managers/Event/EventManager.cs similarity index 52% rename from Torch/Managers/EventManager/EventManager.cs rename to Torch/Managers/Event/EventManager.cs index f6bdd5e..2c54a4b 100644 --- a/Torch/Managers/EventManager/EventManager.cs +++ b/Torch/Managers/Event/EventManager.cs @@ -3,23 +3,21 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; -using System.Text; -using System.Threading.Tasks; using NLog; using Torch.API; -using Torch.API.Managers; -using VRage.Game.ModAPI; +using Torch.API.Managers.Event; +using Torch.Managers.EventManager; -namespace Torch.Managers.EventManager +namespace Torch.Managers.Event { /// /// Manager class responsible for managing registration and dispatching of events. /// - public class EventManager : Manager + public class EventManager : Manager, IEventManager { private static readonly Logger _log = LogManager.GetCurrentClassLogger(); - private static Dictionary _eventLists = new Dictionary(); + private static readonly Dictionary _eventLists = new Dictionary(); static EventManager() { @@ -41,11 +39,7 @@ namespace Torch.Managers.EventManager } } - /// - /// Finds all event handlers in the given type, and its base types - /// - /// Type to explore - /// All event handlers + /// private static IEnumerable EventHandlers(Type exploreType) { IEnumerable enumerable = exploreType.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance) @@ -62,11 +56,8 @@ namespace Torch.Managers.EventManager return exploreType.BaseType != null ? enumerable.Concat(EventHandlers(exploreType.BaseType)) : enumerable; } - /// - /// Registers all handlers the given instance owns. - /// - /// Instance to register handlers from - private static void RegisterHandler(object instance) + /// + private static void RegisterHandlerInternal(IEventHandler instance) { foreach (MethodInfo handler in EventHandlers(instance.GetType())) { @@ -96,15 +87,86 @@ namespace Torch.Managers.EventManager /// Unregisters all handlers owned by the given instance /// /// Instance - private static void UnregisterHandlers(object instance) + private static void UnregisterHandlerInternal(IEventHandler instance) { foreach (IEventList list in _eventLists.Values) list.RemoveHandlers(instance); } + private Dictionary> _registeredHandlers = new Dictionary>(); + /// public EventManager(ITorchBase torchInstance) : base(torchInstance) { } + + /// + /// Registers all event handler methods contained in the given instance + /// + /// Instance to register + /// true if added, false otherwise + [MethodImpl(MethodImplOptions.NoInlining)] + public bool RegisterHandler(IEventHandler handler) + { + Assembly caller = Assembly.GetCallingAssembly(); + lock (_registeredHandlers) + { + if (!_registeredHandlers.TryGetValue(caller, out HashSet handlers)) + _registeredHandlers.Add(caller, handlers = new HashSet()); + if (handlers.Add(handler)) + { + RegisterHandlerInternal(handler); + return true; + } + return false; + } + } + + + /// + /// Unregisters all event handler methods contained in the given instance + /// + /// Instance to unregister + /// true if removed, false otherwise + [MethodImpl(MethodImplOptions.NoInlining)] + public bool UnregisterHandler(IEventHandler handler) + { + Assembly caller = Assembly.GetCallingAssembly(); + lock (_registeredHandlers) + { + if (!_registeredHandlers.TryGetValue(caller, out HashSet handlers)) + return false; + if (handlers.Remove(handler)) + { + UnregisterHandlerInternal(handler); + return true; + } + return false; + } + } + + /// + /// Unregisters all handlers owned by the given assembly. + /// + /// Assembly to unregister + /// Optional callback invoked for every registered handler in the assembly. Ignored if null + /// the number of handlers that were unregistered + internal int UnregisterAllHandlers(Assembly asm, Func callback = null) + { + lock (_registeredHandlers) + { + if (!_registeredHandlers.TryGetValue(asm, out HashSet handlers)) + return 0; + foreach (IEventHandler k in handlers) + { + callback?.Invoke(); + UnregisterHandlerInternal(k); + } + int count = handlers.Count; + handlers.Clear(); + _registeredHandlers.Remove(asm); + return count; + } + } } } diff --git a/Torch/Managers/EventManager/EventShimProgrammableBlock.cs b/Torch/Managers/Event/EventShimProgrammableBlock.cs similarity index 98% rename from Torch/Managers/EventManager/EventShimProgrammableBlock.cs rename to Torch/Managers/Event/EventShimProgrammableBlock.cs index 1285483..87632d1 100644 --- a/Torch/Managers/EventManager/EventShimProgrammableBlock.cs +++ b/Torch/Managers/Event/EventShimProgrammableBlock.cs @@ -6,6 +6,8 @@ using System.Text; using System.Threading.Tasks; using Sandbox.Game.Entities; using Sandbox.Game.Entities.Blocks; +using Torch.API.Managers.Event; +using Torch.Managers.Event; using Torch.Managers.PatchManager; using Torch.Utils; diff --git a/Torch/Managers/EventManager/IEventList.cs b/Torch/Managers/Event/IEventList.cs similarity index 70% rename from Torch/Managers/EventManager/IEventList.cs rename to Torch/Managers/Event/IEventList.cs index 3769295..2e0a3f4 100644 --- a/Torch/Managers/EventManager/IEventList.cs +++ b/Torch/Managers/Event/IEventList.cs @@ -1,11 +1,7 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Text; -using System.Threading.Tasks; +using System.Reflection; +using Torch.API.Managers.Event; -namespace Torch.Managers.EventManager +namespace Torch.Managers.Event { /// /// Represents the interface for adding and removing from an ordered list of callbacks. @@ -17,13 +13,13 @@ namespace Torch.Managers.EventManager /// /// Handler method /// Instance to invoke the handler on - void AddHandler(MethodInfo method, object instance); + void AddHandler(MethodInfo method, IEventHandler instance); /// /// Removes all event handlers invoked on the given instance. /// /// Instance to remove event handlers for /// The number of event handlers removed - int RemoveHandlers(object instance); + int RemoveHandlers(IEventHandler instance); } }