init
This commit is contained in:
38 files changed
+2187
No files matched your search
@@ -0,0 +1,42 @@
|
||||
using System;
|
||||
|
||||
namespace ShrinkEventBus
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class CancelableAttribute : Attribute { }
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class HasResultAttribute : Attribute { }
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class EventBusSubscriberAttribute : Attribute { }
|
||||
|
||||
[AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = true)]
|
||||
public class EventSubscribeAttribute : Attribute
|
||||
{
|
||||
public EventPriority Priority { get; set; }
|
||||
public bool ReceiveCanceled { get; set; }
|
||||
public int NumericPriority { get; set; }
|
||||
|
||||
public EventSubscribeAttribute()
|
||||
{
|
||||
Priority = EventPriority.NORMAL;
|
||||
ReceiveCanceled = false;
|
||||
NumericPriority = 0;
|
||||
}
|
||||
|
||||
public EventSubscribeAttribute(EventPriority priority, bool receiveCanceled = false)
|
||||
{
|
||||
Priority = priority;
|
||||
ReceiveCanceled = receiveCanceled;
|
||||
NumericPriority = 0;
|
||||
}
|
||||
|
||||
public EventSubscribeAttribute(int priority)
|
||||
{
|
||||
NumericPriority = priority;
|
||||
Priority = PriorityHelper.ConvertToEventPriority(priority);
|
||||
ReceiveCanceled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9bb9d82b04a04f3085b9e68ab4f1ba60
|
||||
timeCreated: 1760098802
|
||||
@@ -0,0 +1,136 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ShrinkEventBus
|
||||
{
|
||||
public static class EventAutoRegHelper
|
||||
{
|
||||
private static readonly ConcurrentDictionary<Type, bool> SubscriberTypes = new();
|
||||
private static readonly object InitLock = new();
|
||||
public static bool IsInitialized { get; private set; }
|
||||
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
|
||||
private static void PreInitializeReflection()
|
||||
{
|
||||
if (SubscriberTypes.Count == 0) ScanEventBusSubscribers();
|
||||
}
|
||||
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)]
|
||||
private static void InitializeAfterSceneLoad()
|
||||
{
|
||||
EnsureInitialized();
|
||||
}
|
||||
|
||||
public static void EnsureInitialized()
|
||||
{
|
||||
if (IsInitialized) return;
|
||||
lock (InitLock)
|
||||
{
|
||||
if (IsInitialized) return;
|
||||
ScanEventBusSubscribers();
|
||||
ScanExistingObjects();
|
||||
IsInitialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
private static void ScanExistingObjects()
|
||||
{
|
||||
if (SubscriberTypes.Count == 0)
|
||||
{
|
||||
#if UNITY_2023_1_OR_NEWER
|
||||
var allMonoBehaviours =
|
||||
UnityEngine.Object.FindObjectsByType<MonoBehaviour>(UnityEngine.FindObjectsInactive.Include,
|
||||
UnityEngine.FindObjectsSortMode.None);
|
||||
#else
|
||||
var allMonoBehaviours = UnityEngine.Object.FindObjectsOfType<MonoBehaviour>(true);
|
||||
#endif
|
||||
foreach (var mb in allMonoBehaviours) ProcessNodeRegistration(mb);
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var targetType in SubscriberTypes.Keys)
|
||||
{
|
||||
#if UNITY_2023_1_OR_NEWER
|
||||
var objects = UnityEngine.Object.FindObjectsByType(targetType, UnityEngine.FindObjectsInactive.Include,
|
||||
UnityEngine.FindObjectsSortMode.None);
|
||||
#else
|
||||
var objects = UnityEngine.Object.FindObjectsOfType(targetType, true);
|
||||
#endif
|
||||
foreach (var obj in objects) ProcessNodeRegistration(obj);
|
||||
}
|
||||
}
|
||||
|
||||
private static void ScanEventBusSubscribers()
|
||||
{
|
||||
if (SubscriberTypes.Count > 0) return;
|
||||
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
|
||||
foreach (var assembly in assemblies)
|
||||
{
|
||||
if (IsSystemAssembly(assembly)) continue;
|
||||
try
|
||||
{
|
||||
foreach (var type in assembly.GetTypes())
|
||||
{
|
||||
if (type.GetCustomAttribute<EventBusSubscriberAttribute>() != null &&
|
||||
typeof(MonoBehaviour).IsAssignableFrom(type))
|
||||
SubscriberTypes.TryAdd(type, true);
|
||||
}
|
||||
}
|
||||
catch (ReflectionTypeLoadException ex)
|
||||
{
|
||||
foreach (var type in ex.Types)
|
||||
{
|
||||
if (type?.GetCustomAttribute<EventBusSubscriberAttribute>() != null &&
|
||||
typeof(MonoBehaviour).IsAssignableFrom(type))
|
||||
SubscriberTypes.TryAdd(type, true);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsSystemAssembly(Assembly assembly)
|
||||
{
|
||||
var name = assembly.FullName ?? "";
|
||||
return name.StartsWith("System.") || name.StartsWith("Microsoft.") || name.StartsWith("mscorlib") ||
|
||||
name.StartsWith("UnityEngine.") || name.StartsWith("UnityEditor.");
|
||||
}
|
||||
|
||||
private static bool ProcessNodeRegistration(object node)
|
||||
{
|
||||
if (node == null) return false;
|
||||
var nodeType = node.GetType();
|
||||
|
||||
if (SubscriberTypes.Count == 0 && nodeType.GetCustomAttribute<EventBusSubscriberAttribute>() != null)
|
||||
SubscriberTypes.TryAdd(nodeType, true);
|
||||
|
||||
if (!SubscriberTypes.ContainsKey(nodeType)) return false;
|
||||
if (EventBus.IsInstanceRegistered(node)) return false;
|
||||
|
||||
EventBus.AutoRegister(node);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void UnregisterNode(object node)
|
||||
{
|
||||
if (node == null) return;
|
||||
EventBus.UnregisterInstance(node);
|
||||
}
|
||||
|
||||
public static void ForceScanCurrentScene() => ScanExistingObjects();
|
||||
|
||||
public static void Cleanup()
|
||||
{
|
||||
lock (InitLock)
|
||||
{
|
||||
SubscriberTypes.Clear();
|
||||
IsInitialized = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f4d79f65274145cab7614950a64a92f5
|
||||
timeCreated: 1760099405
|
||||
@@ -0,0 +1,84 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
namespace ShrinkEventBus
|
||||
{
|
||||
public abstract class EventBase : IDisposable
|
||||
{
|
||||
private readonly ListenerList _listenerList = new();
|
||||
private bool _isCanceled;
|
||||
private EventResult _result = EventResult.DEFAULT;
|
||||
|
||||
public EventHandlerInfo? CurrentHandler { get; internal set; }
|
||||
public DateTime EventTime { get; private set; } = DateTime.UtcNow;
|
||||
public Guid EventId { get; private set; } = Guid.NewGuid();
|
||||
|
||||
public bool IsCancelable { get; }
|
||||
public bool HasResult { get; }
|
||||
public EventPriority? Phase { get; private set; }
|
||||
|
||||
internal bool IsInPool { get; set; }
|
||||
internal Action<EventBase> ReleaseAction { get; set; }
|
||||
|
||||
protected EventBase()
|
||||
{
|
||||
IsCancelable = GetType().GetCustomAttribute<CancelableAttribute>() != null;
|
||||
HasResult = GetType().GetCustomAttribute<HasResultAttribute>() != null;
|
||||
Setup();
|
||||
}
|
||||
|
||||
protected virtual void Setup() { }
|
||||
|
||||
protected virtual void OnReset() { }
|
||||
|
||||
internal void ResetInternal()
|
||||
{
|
||||
_isCanceled = false;
|
||||
_result = EventResult.DEFAULT;
|
||||
CurrentHandler = null;
|
||||
Phase = null;
|
||||
EventTime = DateTime.UtcNow;
|
||||
EventId = Guid.NewGuid();
|
||||
_listenerList.Clear();
|
||||
OnReset();
|
||||
}
|
||||
|
||||
public bool IsCanceled
|
||||
{
|
||||
get => _isCanceled;
|
||||
set
|
||||
{
|
||||
if (!IsCancelable) throw new UnsupportedOperationException();
|
||||
_isCanceled = value;
|
||||
}
|
||||
}
|
||||
|
||||
public EventResult Result
|
||||
{
|
||||
get => _result;
|
||||
set
|
||||
{
|
||||
if (!HasResult) throw new InvalidOperationException();
|
||||
_result = value;
|
||||
}
|
||||
}
|
||||
|
||||
internal void SetPhase(EventPriority value)
|
||||
{
|
||||
if (Phase == value) return;
|
||||
if (Phase != null && Phase.Value.CompareTo(value) > 0)
|
||||
throw new ArgumentException();
|
||||
Phase = value;
|
||||
}
|
||||
|
||||
public void SetCanceled(bool canceled) => IsCanceled = canceled;
|
||||
public void SetResult(EventResult result) => Result = result;
|
||||
public ListenerList GetListenerList() => _listenerList;
|
||||
public EventHandlerInfo[] GetSubscribers() => _listenerList.GetHandlers();
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
ReleaseAction?.Invoke(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0b978c5174cf44d893a41950e7a504e3
|
||||
timeCreated: 1760098714
|
||||
@@ -0,0 +1,451 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ShrinkEventBus
|
||||
{
|
||||
public static class EventBus
|
||||
{
|
||||
public static bool EnableDebugRecord { get; set; }
|
||||
|
||||
#if UNITY_EDITOR
|
||||
public static event Action<EventBase, string, string> OnEventTriggeredForEditor;
|
||||
#endif
|
||||
|
||||
private static readonly Dictionary<Type, ListenerList> EventHandlers = new();
|
||||
private static readonly HashSet<object> RegisteredInstances = new();
|
||||
private static readonly object InstanceLock = new();
|
||||
|
||||
static EventBus()
|
||||
{
|
||||
EventBusRegHelper.RegStaticEventHandler();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static void EnsureAutoManagerInitialized() => EventAutoRegHelper.EnsureInitialized();
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void RegisterEvent<TEvent>(Action<TEvent> handler, string methodName, Type declaringType,
|
||||
EventPriority priority = EventPriority.NORMAL, bool receiveCanceled = false) where TEvent : EventBase
|
||||
{
|
||||
var methodInfo = declaringType.GetMethod(methodName,
|
||||
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
|
||||
RegisterEventInternal(typeof(TEvent), handler, priority, 0, receiveCanceled,
|
||||
$"Manual Sync Handler (Priority: {priority})", methodInfo);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void RegisterEvent<TEvent>(Func<TEvent, UniTask> handler, int priority = 0)
|
||||
where TEvent : EventBase
|
||||
{
|
||||
var eventPriority = PriorityHelper.ConvertToEventPriority(priority);
|
||||
RegisterEventInternal(typeof(TEvent), handler, eventPriority, priority, false,
|
||||
$"Manual Async Handler (Priority: {priority})");
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void RegisterEvent<TEvent>(Action<TEvent> handler, EventPriority priority = EventPriority.NORMAL,
|
||||
bool receiveCanceled = false) where TEvent : EventBase
|
||||
{
|
||||
RegisterEventInternal(typeof(TEvent), handler, priority, 0, receiveCanceled,
|
||||
$"Manual Sync Handler (Priority: {priority})", handler.Method);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void RegisterEvent<TEvent>(Action<TEvent> handler, int priority = 0) where TEvent : EventBase
|
||||
{
|
||||
var eventPriority = PriorityHelper.ConvertToEventPriority(priority);
|
||||
RegisterEventInternal(typeof(TEvent), handler, eventPriority, priority, false,
|
||||
$"Manual Sync Handler (Priority: {priority})", handler.Method);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void RegisterEvent<TEvent>(Func<TEvent, UniTask> handler,
|
||||
EventPriority priority = EventPriority.NORMAL, bool receiveCanceled = false) where TEvent : EventBase
|
||||
{
|
||||
RegisterEventInternal(typeof(TEvent), handler, priority, 0, receiveCanceled,
|
||||
$"Manual Async Handler (Priority: {priority})");
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static void RegisterEventInternal(Type eventType, Delegate handler, EventPriority priority,
|
||||
int numericPriority, bool receiveCanceled, string debugInfo = "", MethodInfo originalMethod = null)
|
||||
{
|
||||
lock (EventHandlers)
|
||||
{
|
||||
if (!EventHandlers.TryGetValue(eventType, out var collection))
|
||||
{
|
||||
collection = new ListenerList();
|
||||
EventHandlers[eventType] = collection;
|
||||
var cacheType = typeof(EventCache<>).MakeGenericType(eventType);
|
||||
cacheType.GetField("List", BindingFlags.Static | BindingFlags.Public)?.SetValue(null, collection);
|
||||
}
|
||||
|
||||
collection.Add(handler, priority, numericPriority, receiveCanceled, debugInfo, originalMethod);
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void UnregisterEvent<TEvent>(Func<TEvent, UniTask> handler) where TEvent : EventBase
|
||||
{
|
||||
var eventType = typeof(TEvent);
|
||||
lock (EventHandlers)
|
||||
{
|
||||
if (!EventHandlers.TryGetValue(eventType, out var collection)) return;
|
||||
collection.Remove(handler);
|
||||
if (collection.Count == 0)
|
||||
{
|
||||
EventHandlers.Remove(eventType);
|
||||
EventCache<TEvent>.List = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void UnregisterEvent<TEvent>(Action<TEvent> handler) where TEvent : EventBase
|
||||
{
|
||||
var eventType = typeof(TEvent);
|
||||
lock (EventHandlers)
|
||||
{
|
||||
if (!EventHandlers.TryGetValue(eventType, out var collection)) return;
|
||||
collection.Remove(handler);
|
||||
if (collection.Count == 0)
|
||||
{
|
||||
EventHandlers.Remove(eventType);
|
||||
EventCache<TEvent>.List = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void ClearAllSubscribersForEvent<TEvent>() where TEvent : EventBase
|
||||
{
|
||||
var eventType = typeof(TEvent);
|
||||
lock (EventHandlers)
|
||||
{
|
||||
if (EventHandlers.Remove(eventType))
|
||||
{
|
||||
EventCache<TEvent>.List = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void UnregisterAllEventsForObject(object targetObject)
|
||||
{
|
||||
if (targetObject is null) return;
|
||||
lock (EventHandlers)
|
||||
{
|
||||
var eventTypesToRemove = new List<Type>();
|
||||
foreach (var kvp in EventHandlers)
|
||||
{
|
||||
kvp.Value.RemoveTarget(targetObject);
|
||||
if (kvp.Value.Count == 0) eventTypesToRemove.Add(kvp.Key);
|
||||
}
|
||||
|
||||
foreach (var eventType in eventTypesToRemove)
|
||||
{
|
||||
EventHandlers.Remove(eventType);
|
||||
var cacheType = typeof(EventCache<>).MakeGenericType(eventType);
|
||||
cacheType.GetField("List", BindingFlags.Static | BindingFlags.Public)?.SetValue(null, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void UnregisterInstance(object targetObject)
|
||||
{
|
||||
if (targetObject is null) return;
|
||||
lock (InstanceLock)
|
||||
{
|
||||
RegisteredInstances.Remove(targetObject);
|
||||
}
|
||||
|
||||
UnregisterAllEventsForObject(targetObject);
|
||||
if (targetObject is not MonoBehaviour mb || !mb) return;
|
||||
try
|
||||
{
|
||||
if (!mb.gameObject ||
|
||||
!mb.gameObject.TryGetComponent<EventBusDestroyListener>(out var listener)) return;
|
||||
if (listener)
|
||||
{
|
||||
UnityEngine.Object.Destroy(listener);
|
||||
}
|
||||
}
|
||||
catch (MissingReferenceException)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void UnregisterAllEvents()
|
||||
{
|
||||
lock (EventHandlers)
|
||||
{
|
||||
foreach (var type in EventHandlers.Keys)
|
||||
{
|
||||
var cacheType = typeof(EventCache<>).MakeGenericType(type);
|
||||
cacheType.GetField("List", BindingFlags.Static | BindingFlags.Public).SetValue(null, null);
|
||||
}
|
||||
|
||||
EventHandlers.Clear();
|
||||
}
|
||||
|
||||
lock (InstanceLock)
|
||||
{
|
||||
RegisteredInstances.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static async UniTask<bool> TriggerEventAsync<TEvent>(TEvent eventArgs) where TEvent : EventBase
|
||||
{
|
||||
EnsureAutoManagerInitialized();
|
||||
|
||||
var collection = EventCache<TEvent>.List;
|
||||
if (collection == null) return false;
|
||||
|
||||
var handlers = collection.GetHandlers();
|
||||
var wasHandled = false;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
RecordEditorTrace(handlers, eventArgs, typeof(TEvent));
|
||||
#endif
|
||||
|
||||
for (var i = 0; i < handlers.Length; i++)
|
||||
{
|
||||
var handlerInfo = handlers[i];
|
||||
eventArgs.CurrentHandler = handlerInfo;
|
||||
eventArgs.SetPhase(handlerInfo.Priority);
|
||||
|
||||
if (eventArgs is { IsCancelable: true, IsCanceled: true } && !handlerInfo.ReceiveCanceled) continue;
|
||||
|
||||
try
|
||||
{
|
||||
if (handlerInfo.Handler is Action<TEvent> syncHandler)
|
||||
{
|
||||
syncHandler(eventArgs);
|
||||
wasHandled = true;
|
||||
}
|
||||
else if (handlerInfo.Handler is Func<TEvent, UniTask> asyncHandler)
|
||||
{
|
||||
await asyncHandler(eventArgs);
|
||||
wasHandled = true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogException(ex);
|
||||
Debug.LogError(
|
||||
$"[EventBus] {typeof(TEvent).Name} Async Handler {handlerInfo.DisplayDeclaringType.Name}.{handlerInfo.DisplayMethodName} Exception: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
eventArgs.CurrentHandler = null;
|
||||
return wasHandled;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool TriggerEvent<TEvent>(TEvent eventArgs) where TEvent : EventBase
|
||||
{
|
||||
EnsureAutoManagerInitialized();
|
||||
|
||||
var collection = EventCache<TEvent>.List;
|
||||
if (collection == null) return false;
|
||||
|
||||
var handlers = collection.GetHandlers();
|
||||
var wasHandled = false;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
RecordEditorTrace(handlers, eventArgs, typeof(TEvent));
|
||||
#endif
|
||||
|
||||
for (var i = 0; i < handlers.Length; i++)
|
||||
{
|
||||
var handlerInfo = handlers[i];
|
||||
eventArgs.CurrentHandler = handlerInfo;
|
||||
eventArgs.SetPhase(handlerInfo.Priority);
|
||||
|
||||
if (eventArgs is { IsCancelable: true, IsCanceled: true } && !handlerInfo.ReceiveCanceled) continue;
|
||||
|
||||
try
|
||||
{
|
||||
if (handlerInfo.Handler is Action<TEvent> syncHandler)
|
||||
{
|
||||
syncHandler(eventArgs);
|
||||
wasHandled = true;
|
||||
}
|
||||
else if (handlerInfo.Handler is Func<TEvent, UniTask> asyncHandler)
|
||||
{
|
||||
FireAndForgetSafe(() => asyncHandler(eventArgs),
|
||||
$"{handlerInfo.DisplayDeclaringType.Name}.{handlerInfo.DisplayMethodName}");
|
||||
wasHandled = true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogException(ex);
|
||||
Debug.LogError(
|
||||
$"[EventBus] {typeof(TEvent).Name} Sync Handler {handlerInfo.DisplayDeclaringType.Name}.{handlerInfo.DisplayMethodName} Exception: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
eventArgs.CurrentHandler = null;
|
||||
return wasHandled;
|
||||
}
|
||||
|
||||
private static void FireAndForgetSafe(Func<UniTask> action, string handlerName)
|
||||
{
|
||||
action().Forget(e =>
|
||||
{
|
||||
Debug.LogException(e);
|
||||
Debug.LogError($"[EventBus] Async Handler {handlerName} threw exception: {e.Message}");
|
||||
});
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
private static void RecordEditorTrace<TEvent>(EventHandlerInfo[] handlers, TEvent eventArgs, Type eventType)
|
||||
where TEvent : EventBase
|
||||
{
|
||||
if (!EnableDebugRecord) return;
|
||||
for (var i = 0; i < handlers.Length; i++)
|
||||
{
|
||||
var handler = handlers[i];
|
||||
MethodInfo originalMethod = null;
|
||||
var type = handler.GetType();
|
||||
var prop = type.GetProperty("OriginalMethod");
|
||||
if (prop != null) originalMethod = prop.GetValue(handler) as MethodInfo;
|
||||
else
|
||||
{
|
||||
var field = type.GetField("OriginalMethod");
|
||||
if (field != null) originalMethod = field.GetValue(handler) as MethodInfo;
|
||||
}
|
||||
|
||||
eventArgs.GetListenerList().Add(handler.Handler, handler.Priority, handler.NumericPriority,
|
||||
handler.ReceiveCanceled, handler.DebugInfo, originalMethod);
|
||||
}
|
||||
|
||||
OnEventTriggeredForEditor?.Invoke(eventArgs, eventType.Name, GetSenderInfo());
|
||||
}
|
||||
|
||||
private static string GetSenderInfo()
|
||||
{
|
||||
var senderInfo = "Unknown";
|
||||
try
|
||||
{
|
||||
var trace = new System.Diagnostics.StackTrace(0, false);
|
||||
for (var i = 0; i < trace.FrameCount; i++)
|
||||
{
|
||||
var method = trace.GetFrame(i)?.GetMethod();
|
||||
var declaringType = method?.DeclaringType;
|
||||
|
||||
if (declaringType == null) continue;
|
||||
if (declaringType == typeof(EventBus) ||
|
||||
declaringType.DeclaringType == typeof(EventBus)) continue;
|
||||
var ns = declaringType.Namespace ?? "";
|
||||
if (ns.StartsWith("System") || ns.StartsWith("Cysharp") || ns.StartsWith("UnityEngine"))
|
||||
continue;
|
||||
|
||||
var className = declaringType.Name;
|
||||
var methodName = method.Name;
|
||||
|
||||
if (declaringType.DeclaringType != null && className.StartsWith("<") &&
|
||||
className.Contains(">"))
|
||||
{
|
||||
className = declaringType.DeclaringType.Name;
|
||||
var startIndex = declaringType.Name.IndexOf('<') + 1;
|
||||
var endIndex = declaringType.Name.IndexOf('>');
|
||||
if (startIndex > 0 && endIndex > startIndex)
|
||||
methodName = declaringType.Name.Substring(startIndex, endIndex - startIndex);
|
||||
}
|
||||
|
||||
return $"{className}.{methodName}()";
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
|
||||
return senderInfo;
|
||||
}
|
||||
#endif
|
||||
|
||||
public static EventHandlerInfo[] GetEventSubscribers<TEvent>() where TEvent : EventBase
|
||||
{
|
||||
var eventType = typeof(TEvent);
|
||||
lock (EventHandlers)
|
||||
{
|
||||
return EventHandlers.TryGetValue(eventType, out var collection)
|
||||
? collection.GetHandlers()
|
||||
: Array.Empty<EventHandlerInfo>();
|
||||
}
|
||||
}
|
||||
|
||||
public static ListenerList GetListenerList<TEvent>() where TEvent : EventBase
|
||||
{
|
||||
var eventType = typeof(TEvent);
|
||||
lock (EventHandlers)
|
||||
{
|
||||
if (EventHandlers.TryGetValue(eventType, out var collection)) return collection;
|
||||
return new ListenerList();
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void AutoRegister(object target)
|
||||
{
|
||||
if (target == null) return;
|
||||
|
||||
if (IsInstanceRegistered(target)) return;
|
||||
|
||||
EventBusRegHelper.RegisterEventHandlers(target);
|
||||
|
||||
lock (InstanceLock)
|
||||
{
|
||||
if (!RegisteredInstances.Add(target)) return;
|
||||
}
|
||||
|
||||
if (target is MonoBehaviour mb && mb && mb.gameObject)
|
||||
{
|
||||
if (!mb.gameObject.TryGetComponent<EventBusDestroyListener>(out _))
|
||||
{
|
||||
var listener = mb.gameObject.AddComponent<EventBusDestroyListener>();
|
||||
listener.Target = target;
|
||||
listener.hideFlags = HideFlags.HideAndDontSave;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool IsInstanceRegistered(object target)
|
||||
{
|
||||
if (target == null) return false;
|
||||
lock (InstanceLock)
|
||||
{
|
||||
return RegisteredInstances.Contains(target);
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static int GetRegisteredInstanceCount()
|
||||
{
|
||||
lock (InstanceLock)
|
||||
{
|
||||
return RegisteredInstances.Count;
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static int GetRegisteredEventTypeCount()
|
||||
{
|
||||
lock (EventHandlers)
|
||||
{
|
||||
return EventHandlers.Count;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b995a65fd1324255a5ade1ae1f0adf32
|
||||
timeCreated: 1760099076
|
||||
@@ -0,0 +1,18 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace ShrinkEventBus
|
||||
{
|
||||
[DisallowMultipleComponent]
|
||||
public class EventBusDestroyListener : MonoBehaviour
|
||||
{
|
||||
public object Target { get; set; }
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
if (Target != null)
|
||||
{
|
||||
EventBus.UnregisterInstance(Target);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0fd1c9ba32a842199e4285383d83b3b3
|
||||
timeCreated: 1772889501
|
||||
@@ -0,0 +1,162 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading.Tasks;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ShrinkEventBus
|
||||
{
|
||||
public static class EventBusRegHelper
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void RegStaticEventHandler() => RegisterEventHandlersInternal(null);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void RegisterEventHandlers(object target) => RegisterEventHandlersInternal(target);
|
||||
|
||||
private static void RegisterEventHandlersInternal(object target)
|
||||
{
|
||||
var isStatic = target == null;
|
||||
|
||||
if (isStatic)
|
||||
{
|
||||
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
|
||||
foreach (var assembly in assemblies)
|
||||
{
|
||||
try
|
||||
{
|
||||
foreach (var type in assembly.GetTypes())
|
||||
{
|
||||
if (type.GetCustomAttributes(typeof(EventBusSubscriberAttribute), false).Length == 0)
|
||||
continue;
|
||||
ScanMethodsAndRegister(null,
|
||||
type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic));
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var type = target.GetType();
|
||||
if (type.GetCustomAttributes(typeof(EventBusSubscriberAttribute), false).Length == 0) return;
|
||||
ScanMethodsAndRegister(target,
|
||||
type.GetMethods(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public));
|
||||
}
|
||||
}
|
||||
|
||||
private static void ScanMethodsAndRegister(object target, MethodInfo[] methods)
|
||||
{
|
||||
foreach (var method in methods)
|
||||
{
|
||||
if (target != null && method.IsStatic) continue;
|
||||
|
||||
var attributes = method.GetCustomAttributes(typeof(EventSubscribeAttribute), false);
|
||||
if (attributes.Length == 0) continue;
|
||||
|
||||
var subscribeAttr = (EventSubscribeAttribute)attributes[0];
|
||||
var parameters = method.GetParameters();
|
||||
|
||||
if (parameters.Length != 1) continue;
|
||||
var parameterType = parameters[0].ParameterType;
|
||||
if (!typeof(EventBase).IsAssignableFrom(parameterType)) continue;
|
||||
|
||||
ProcessMethodRegistration(target, method, subscribeAttr, parameterType);
|
||||
}
|
||||
}
|
||||
|
||||
private static void ProcessMethodRegistration(object target, MethodInfo method,
|
||||
EventSubscribeAttribute subscribeAttr, Type parameterType)
|
||||
{
|
||||
try
|
||||
{
|
||||
string scope = target == null ? "Static" : "Instance";
|
||||
string typeName = target == null ? method.DeclaringType?.Name : target.GetType().Name;
|
||||
|
||||
if (method.ReturnType == typeof(UniTask))
|
||||
{
|
||||
var funcType = typeof(Func<,>).MakeGenericType(parameterType, typeof(UniTask));
|
||||
var handlerDelegate = target == null
|
||||
? Delegate.CreateDelegate(funcType, method)
|
||||
: Delegate.CreateDelegate(funcType, target, method);
|
||||
EventBus.RegisterEventInternal(parameterType, handlerDelegate, subscribeAttr.Priority,
|
||||
subscribeAttr.NumericPriority, subscribeAttr.ReceiveCanceled,
|
||||
$"{scope} {typeName}.{method.Name} (UniTask)", method);
|
||||
}
|
||||
else if (method.ReturnType == typeof(Task))
|
||||
{
|
||||
var funcType = typeof(Func<,>).MakeGenericType(parameterType, typeof(Task));
|
||||
var handlerDelegate = target == null
|
||||
? Delegate.CreateDelegate(funcType, method)
|
||||
: Delegate.CreateDelegate(funcType, target, method);
|
||||
var wrappedHandler = WrapTaskHandlerWithMethodInfo(parameterType, handlerDelegate, method);
|
||||
EventBus.RegisterEventInternal(parameterType, wrappedHandler, subscribeAttr.Priority,
|
||||
subscribeAttr.NumericPriority, subscribeAttr.ReceiveCanceled,
|
||||
$"{scope} {typeName}.{method.Name} (Task->UniTask)", method);
|
||||
}
|
||||
else if (method.ReturnType == typeof(void))
|
||||
{
|
||||
var actionType = typeof(Action<>).MakeGenericType(parameterType);
|
||||
var actionDelegate = target == null
|
||||
? Delegate.CreateDelegate(actionType, method)
|
||||
: Delegate.CreateDelegate(actionType, target, method);
|
||||
EventBus.RegisterEventInternal(parameterType, actionDelegate, subscribeAttr.Priority,
|
||||
subscribeAttr.NumericPriority, subscribeAttr.ReceiveCanceled,
|
||||
$"{scope} {typeName}.{method.Name} (Sync)", method);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
Debug.LogWarning($"[EventBus] Registration failed for {method.Name}: {ex.Message}");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
private static Delegate WrapTaskHandlerWithMethodInfo(Type eventType, Delegate taskHandler,
|
||||
MethodInfo originalMethod)
|
||||
{
|
||||
var method = typeof(EventBusRegHelper)
|
||||
.GetMethod(nameof(WrapTaskActionWithMethodInfo), BindingFlags.NonPublic | BindingFlags.Static)
|
||||
?.MakeGenericMethod(eventType);
|
||||
return (Delegate)method.Invoke(null, new object[] { taskHandler, originalMethod })!;
|
||||
}
|
||||
|
||||
private static Func<T, UniTask> WrapTaskActionWithMethodInfo<T>(Delegate actionDelegate,
|
||||
MethodInfo originalMethod)
|
||||
{
|
||||
var typedAction = (Func<T, Task>)actionDelegate;
|
||||
var wrapper = new MethodInfoPreservingTaskWrapper<T>(typedAction, originalMethod);
|
||||
return wrapper.ExecuteAsync;
|
||||
}
|
||||
|
||||
private class MethodInfoPreservingTaskWrapper<T>
|
||||
{
|
||||
private readonly Func<T, Task> _originalAction;
|
||||
public readonly MethodInfo OriginalMethod;
|
||||
|
||||
public MethodInfoPreservingTaskWrapper(Func<T, Task> originalAction, MethodInfo originalMethod)
|
||||
{
|
||||
_originalAction = originalAction;
|
||||
OriginalMethod = originalMethod;
|
||||
}
|
||||
|
||||
public async UniTask ExecuteAsync(T arg)
|
||||
{
|
||||
try
|
||||
{
|
||||
await _originalAction(arg);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogException(ex);
|
||||
Debug.LogError($"[EventBus] Task {OriginalMethod.Name}: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a237a407a3a42394eba27bc8e4dbdce2
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace ShrinkEventBus
|
||||
{
|
||||
internal static class EventCache<TEvent> where TEvent : EventBase
|
||||
{
|
||||
public static ListenerList List;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0c41a516998341adbddce082cec09938
|
||||
timeCreated: 1772889485
|
||||
@@ -0,0 +1,78 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
#pragma warning disable CS8632 // 只能在 "#nullable" 注释上下文内的代码中使用可为 null 的引用类型的注释。
|
||||
|
||||
namespace ShrinkEventBus
|
||||
{
|
||||
public class EventHandlerInfo
|
||||
{
|
||||
public Delegate Handler { get; }
|
||||
public EventPriority Priority { get; }
|
||||
public int NumericPriority { get; }
|
||||
public bool ReceiveCanceled { get; }
|
||||
public object? Target { get; }
|
||||
public MethodInfo Method { get; }
|
||||
public string DebugInfo { get; }
|
||||
public Type DeclaringType { get; }
|
||||
public string MethodName { get; }
|
||||
public MethodInfo? OriginalMethod { get; }
|
||||
public string OriginalMethodName { get; }
|
||||
public Type? OriginalDeclaringType { get; }
|
||||
|
||||
public EventHandlerInfo(Delegate handler, EventPriority priority, int numericPriority,
|
||||
bool receiveCanceled, string debugInfo = "", MethodInfo? originalMethod = null)
|
||||
{
|
||||
Handler = handler;
|
||||
Priority = priority;
|
||||
NumericPriority = numericPriority;
|
||||
ReceiveCanceled = receiveCanceled;
|
||||
Target = handler.Target;
|
||||
Method = handler.Method;
|
||||
DebugInfo = debugInfo;
|
||||
DeclaringType = Method.DeclaringType ?? typeof(object);
|
||||
MethodName = Method.Name;
|
||||
|
||||
OriginalMethod = ExtractOriginalMethodFromWrapper(handler) ?? originalMethod;
|
||||
|
||||
if (OriginalMethod != null)
|
||||
{
|
||||
OriginalMethodName = OriginalMethod.Name;
|
||||
OriginalDeclaringType = OriginalMethod.DeclaringType;
|
||||
}
|
||||
else
|
||||
{
|
||||
OriginalMethodName = MethodName;
|
||||
OriginalDeclaringType = DeclaringType;
|
||||
}
|
||||
}
|
||||
|
||||
private static MethodInfo? ExtractOriginalMethodFromWrapper(Delegate handler)
|
||||
{
|
||||
if (handler.Target == null) return null;
|
||||
|
||||
var targetType = handler.Target.GetType();
|
||||
if (!targetType.Name.Contains("MethodInfoPreserving")) return null;
|
||||
|
||||
try
|
||||
{
|
||||
var field = targetType.GetField("OriginalMethod",
|
||||
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
if (field != null) return field.GetValue(handler.Target) as MethodInfo;
|
||||
|
||||
var prop = targetType.GetProperty("OriginalMethod",
|
||||
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
if (prop != null) return prop.GetValue(handler.Target) as MethodInfo;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public string DisplayMethodName => OriginalMethodName;
|
||||
public Type DisplayDeclaringType => OriginalDeclaringType ?? DeclaringType;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 19972a32cbf54c7f94d6214fde5635c2
|
||||
timeCreated: 1760098840
|
||||
@@ -0,0 +1,41 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace ShrinkEventBus
|
||||
{
|
||||
public static class EventPool<T> where T : EventBase, new()
|
||||
{
|
||||
private static readonly Stack<T> Pool = new(32);
|
||||
private static readonly object Lock = new();
|
||||
|
||||
public static T Get()
|
||||
{
|
||||
lock (Lock)
|
||||
{
|
||||
if (Pool.Count > 0)
|
||||
{
|
||||
var evt = Pool.Pop();
|
||||
evt.IsInPool = false;
|
||||
return evt;
|
||||
}
|
||||
}
|
||||
|
||||
var newEvt = new T();
|
||||
newEvt.ReleaseAction = e => Release((T)e);
|
||||
return newEvt;
|
||||
}
|
||||
|
||||
public static void Release(T evt)
|
||||
{
|
||||
if (evt == null || evt.IsInPool) return;
|
||||
|
||||
evt.ResetInternal();
|
||||
evt.IsInPool = true;
|
||||
|
||||
lock (Lock)
|
||||
{
|
||||
Pool.Push(evt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c59d817792dd40f08ffed2f1a8d65cb8
|
||||
timeCreated: 1772891540
|
||||
@@ -0,0 +1,27 @@
|
||||
namespace ShrinkEventBus
|
||||
{
|
||||
public enum EventPriority
|
||||
{
|
||||
HIGHEST = 0,
|
||||
HIGH = 1,
|
||||
NORMAL = 2,
|
||||
LOW = 3,
|
||||
LOWEST = 4,
|
||||
MONITOR = 5
|
||||
}
|
||||
|
||||
internal static class PriorityHelper
|
||||
{
|
||||
public static EventPriority ConvertToEventPriority(int numericPriority)
|
||||
{
|
||||
return numericPriority switch
|
||||
{
|
||||
>= 100 => EventPriority.HIGHEST,
|
||||
>= 50 => EventPriority.HIGH,
|
||||
> 0 => EventPriority.NORMAL,
|
||||
>= -50 => EventPriority.LOW,
|
||||
_ => EventPriority.LOWEST
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c77c5178c66948f29a7c87c9ae203004
|
||||
timeCreated: 1760098774
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace ShrinkEventBus
|
||||
{
|
||||
public enum EventResult
|
||||
{
|
||||
DEFAULT,
|
||||
ALLOW,
|
||||
DENY
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d5213a68ce8f433a98f272904a5d7bd2
|
||||
timeCreated: 1760098791
|
||||
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
|
||||
namespace ShrinkEventBus
|
||||
{
|
||||
public class UnsupportedOperationException : InvalidOperationException
|
||||
{
|
||||
public UnsupportedOperationException() : base()
|
||||
{
|
||||
}
|
||||
|
||||
public UnsupportedOperationException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public UnsupportedOperationException(string message, Exception innerException)
|
||||
: base(message, innerException)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 893fdc450e7a4a8e8e1b675f0ce084a7
|
||||
timeCreated: 1760098825
|
||||
@@ -0,0 +1,96 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
namespace ShrinkEventBus
|
||||
{
|
||||
public class ListenerList
|
||||
{
|
||||
private readonly object _lock = new();
|
||||
private EventHandlerInfo[] _handlers = Array.Empty<EventHandlerInfo>();
|
||||
|
||||
public void Add(Delegate handler, EventPriority priority, int numericPriority,
|
||||
bool receiveCanceled, string debugInfo = "", MethodInfo? originalMethod = null)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
var newInfo = new EventHandlerInfo(handler, priority, numericPriority,
|
||||
receiveCanceled, debugInfo, originalMethod);
|
||||
var newArray = new EventHandlerInfo[_handlers.Length + 1];
|
||||
Array.Copy(_handlers, newArray, _handlers.Length);
|
||||
newArray[^1] = newInfo;
|
||||
Array.Sort(newArray, CompareHandlers);
|
||||
_handlers = newArray;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Remove(Delegate handler)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
var index = -1;
|
||||
for (var i = 0; i < _handlers.Length; i++)
|
||||
{
|
||||
if (_handlers[i].Handler.Equals(handler))
|
||||
{
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (index == -1) return false;
|
||||
|
||||
var newArray = new EventHandlerInfo[_handlers.Length - 1];
|
||||
if (index > 0) Array.Copy(_handlers, 0, newArray, 0, index);
|
||||
if (index < _handlers.Length - 1)
|
||||
Array.Copy(_handlers, index + 1, newArray, index, _handlers.Length - index - 1);
|
||||
_handlers = newArray;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveTarget(object target)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
var removeCount = 0;
|
||||
for (var i = 0; i < _handlers.Length; i++)
|
||||
{
|
||||
if (_handlers[i].Target == target) removeCount++;
|
||||
}
|
||||
|
||||
if (removeCount == 0) return;
|
||||
|
||||
var newArray = new EventHandlerInfo[_handlers.Length - removeCount];
|
||||
var dst = 0;
|
||||
for (var i = 0; i < _handlers.Length; i++)
|
||||
{
|
||||
if (_handlers[i].Target != target)
|
||||
{
|
||||
newArray[dst++] = _handlers[i];
|
||||
}
|
||||
}
|
||||
|
||||
_handlers = newArray;
|
||||
}
|
||||
}
|
||||
|
||||
public EventHandlerInfo[] GetHandlers() => _handlers;
|
||||
|
||||
public int Count => _handlers.Length;
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
_handlers = Array.Empty<EventHandlerInfo>();
|
||||
}
|
||||
}
|
||||
|
||||
private static int CompareHandlers(EventHandlerInfo a, EventHandlerInfo b)
|
||||
{
|
||||
var priorityCompare = a.Priority.CompareTo(b.Priority);
|
||||
return priorityCompare != 0 ? priorityCompare : b.NumericPriority.CompareTo(a.NumericPriority);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 864eb3e7bf8f443c86472995e408c580
|
||||
timeCreated: 1760098877
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "ShrinkEventBus.Runtime",
|
||||
"rootNamespace": "ShrinkEventBus",
|
||||
"references": [
|
||||
"UniTask"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"autoReferenced": true
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f9a7e109b2ecd4946ba9202d2288af15
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in new issue
Block a user