feat(sdk): migrate to EventBus 2.0
Replace the legacy EventBase runtime with generated multi-bus bindings and explicit scheduling. Migrate app, data, network, demo, and mod consumers; add generated network-event registration and owner-scoped mod content overrides.
This commit is contained in:
@@ -1,129 +1,196 @@
|
||||
#nullable enable
|
||||
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
using Cysharp.Threading.Tasks;
|
||||
|
||||
namespace ShrinkEventBus
|
||||
{
|
||||
internal readonly struct ShrinkEventTrace
|
||||
{
|
||||
public ShrinkEventTrace(DateTime timestampUtc, Type eventType, ShrinkBusKey busKey,
|
||||
ShrinkBusOptions options, int threadId, long elapsedTimestampTicks,
|
||||
ShrinkPostResult result, bool isAsync)
|
||||
{
|
||||
TimestampUtc = timestampUtc;
|
||||
EventType = eventType;
|
||||
BusKey = busKey;
|
||||
Scheduler = options.Scheduler;
|
||||
DispatchMode = options.DispatchMode;
|
||||
ThreadId = threadId;
|
||||
ElapsedTimestampTicks = elapsedTimestampTicks;
|
||||
Result = result;
|
||||
IsAsync = isAsync;
|
||||
}
|
||||
|
||||
public DateTime TimestampUtc { get; }
|
||||
public Type EventType { get; }
|
||||
public ShrinkBusKey BusKey { get; }
|
||||
public ShrinkBusSchedulerKind Scheduler { get; }
|
||||
public ShrinkDispatchMode DispatchMode { get; }
|
||||
public int ThreadId { get; }
|
||||
public long ElapsedTimestampTicks { get; }
|
||||
public ShrinkPostResult Result { get; }
|
||||
public bool IsAsync { get; }
|
||||
}
|
||||
|
||||
public static class EventBus
|
||||
{
|
||||
private sealed class GlobalBusResolver : IShrinkBusResolver
|
||||
{
|
||||
public IShrinkEventBus GetBus(ShrinkBusKey key)
|
||||
{
|
||||
if (TryGetBus(key, out var bus))
|
||||
return bus;
|
||||
throw new KeyNotFoundException($"Bus '{key}' is not registered.");
|
||||
}
|
||||
|
||||
public bool TryGetBus(ShrinkBusKey key, out IShrinkEventBus bus) =>
|
||||
EventBus.TryGetBus(key, out bus);
|
||||
}
|
||||
|
||||
private static readonly ConcurrentDictionary<ShrinkBusKey, IShrinkEventBus> Buses = new();
|
||||
internal static readonly IShrinkBusResolver Resolver = new GlobalBusResolver();
|
||||
private static readonly IShrinkEventBus DefaultBus = CreateDefaultBus();
|
||||
private static Action<IShrinkEvent, Type, ShrinkBusKey>? _posted;
|
||||
private static Action<ShrinkEventTrace>? _detailedPosted;
|
||||
|
||||
internal static event Action<IShrinkEvent, Type, ShrinkBusKey> Posted
|
||||
{
|
||||
add
|
||||
{
|
||||
_posted += value;
|
||||
}
|
||||
remove
|
||||
{
|
||||
_posted -= value;
|
||||
}
|
||||
}
|
||||
|
||||
internal static bool HasPostedObservers
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => Volatile.Read(ref _posted) != null;
|
||||
}
|
||||
|
||||
internal static event Action<ShrinkEventTrace> DetailedPosted
|
||||
{
|
||||
add => _detailedPosted += value;
|
||||
remove => _detailedPosted -= value;
|
||||
}
|
||||
|
||||
internal static bool HasDetailedPostedObservers
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => Volatile.Read(ref _detailedPosted) != null;
|
||||
}
|
||||
|
||||
public static IShrinkEventBus Default => DefaultBus;
|
||||
|
||||
public static event Action<EventBase, Type> OnEventTriggered
|
||||
public static IShrinkEventBus CreateBus(ShrinkBusKey key, ShrinkBusOptions options)
|
||||
{
|
||||
add => DefaultBus.OnEventTriggered += value;
|
||||
remove => DefaultBus.OnEventTriggered -= value;
|
||||
if (options == null)
|
||||
throw new ArgumentNullException(nameof(options));
|
||||
|
||||
var bus = BuildBus(key, options);
|
||||
if (!Buses.TryAdd(key, bus))
|
||||
{
|
||||
bus.Dispose();
|
||||
throw new InvalidOperationException($"Bus '{key}' is already registered.");
|
||||
}
|
||||
ShrinkStaticBindingRegistry.AttachForBus(key, Resolver);
|
||||
return bus;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
public static bool EnableDebugRecord
|
||||
public static IShrinkEventBus GetOrCreateBus(ShrinkBusKey key, ShrinkBusOptions options)
|
||||
{
|
||||
get => DefaultBus.EnableDebugRecord;
|
||||
set => DefaultBus.EnableDebugRecord = value;
|
||||
if (options == null)
|
||||
throw new ArgumentNullException(nameof(options));
|
||||
var bus = Buses.GetOrAdd(key, busKey => BuildBus(busKey, options));
|
||||
ShrinkStaticBindingRegistry.AttachForBus(key, Resolver);
|
||||
return bus;
|
||||
}
|
||||
|
||||
public static event Action<EventBase, string, string, EventHandlerInfo[]> OnEventTriggeredForEditor
|
||||
{
|
||||
add => DefaultBus.OnEventTriggeredForEditor += value;
|
||||
remove => DefaultBus.OnEventTriggeredForEditor -= value;
|
||||
}
|
||||
#endif
|
||||
public static bool TryGetBus(ShrinkBusKey key, out IShrinkEventBus bus) =>
|
||||
Buses.TryGetValue(key, out bus!);
|
||||
|
||||
public static ShrinkEventBusBuilder Builder() => new();
|
||||
|
||||
public static IShrinkEventBus CreateBus(Action<ShrinkEventBusBuilder>? configure = null)
|
||||
public static bool RemoveBus(ShrinkBusKey key)
|
||||
{
|
||||
var builder = new ShrinkEventBusBuilder();
|
||||
configure?.Invoke(builder);
|
||||
return builder.Build();
|
||||
if (key == ShrinkBusKey.Game || !Buses.TryRemove(key, out var bus))
|
||||
return false;
|
||||
ShrinkStaticBindingRegistry.DetachBus(key);
|
||||
bus.Dispose();
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void Start() => DefaultBus.Start();
|
||||
public static void AutoRegister(object target) => DefaultBus.AutoRegister(target);
|
||||
public static void Register(object target) => DefaultBus.Register(target);
|
||||
public static void Unregister(object target) => DefaultBus.Unregister(target);
|
||||
public static ShrinkPostResult Post<TEvent>(in TEvent eventData)
|
||||
where TEvent : IShrinkEvent => DefaultBus.Post(in eventData);
|
||||
|
||||
public static void RegisterEvent<TEvent>(Func<TEvent, UniTask> handler, int priority)
|
||||
where TEvent : EventBase => DefaultBus.RegisterEvent(handler, priority);
|
||||
public static UniTask<ShrinkPostResult> PostAsync<TEvent>(TEvent eventData,
|
||||
CancellationToken cancellationToken = default)
|
||||
where TEvent : IShrinkEvent => DefaultBus.PostAsync(eventData, cancellationToken);
|
||||
|
||||
public static void RegisterEvent<TEvent>(Action<TEvent> handler,
|
||||
EventPriority priority = EventPriority.NORMAL, bool receiveCanceled = false)
|
||||
where TEvent : EventBase => DefaultBus.RegisterEvent(handler, priority, receiveCanceled);
|
||||
public static IDisposable Attach(object target, ShrinkBusKey? defaultBus = null)
|
||||
{
|
||||
if (target == null)
|
||||
throw new ArgumentNullException(nameof(target));
|
||||
if (target is not IShrinkGeneratedSubscriber generated)
|
||||
throw new InvalidOperationException(
|
||||
$"Type {target.GetType().FullName} has no generated [ShrinkSubscribe] binding.");
|
||||
return generated.AttachGenerated(Resolver, defaultBus ?? ShrinkBusKey.Game);
|
||||
}
|
||||
|
||||
public static void RegisterEvent<TEvent>(Action<TEvent> handler, int priority)
|
||||
where TEvent : EventBase => DefaultBus.RegisterEvent(handler, priority);
|
||||
|
||||
public static void RegisterEvent<TEvent>(Func<TEvent, UniTask> handler,
|
||||
EventPriority priority = EventPriority.NORMAL, bool receiveCanceled = false)
|
||||
where TEvent : EventBase => DefaultBus.RegisterEvent(handler, priority, receiveCanceled);
|
||||
|
||||
public static IShrinkEventSubscription SubscribeEvent<TEvent>(Action<TEvent> handler,
|
||||
EventPriority priority = EventPriority.NORMAL, bool receiveCanceled = false)
|
||||
where TEvent : EventBase => DefaultBus.SubscribeEvent(handler, priority, receiveCanceled);
|
||||
|
||||
public static IShrinkEventSubscription SubscribeEvent<TEvent>(Action<TEvent> handler, int priority)
|
||||
where TEvent : EventBase => DefaultBus.SubscribeEvent(handler, priority);
|
||||
|
||||
public static IShrinkEventSubscription SubscribeEvent<TEvent>(Func<TEvent, UniTask> handler,
|
||||
EventPriority priority = EventPriority.NORMAL, bool receiveCanceled = false)
|
||||
where TEvent : EventBase => DefaultBus.SubscribeEvent(handler, priority, receiveCanceled);
|
||||
|
||||
public static IShrinkEventSubscription SubscribeEvent<TEvent>(Func<TEvent, UniTask> handler, int priority)
|
||||
where TEvent : EventBase => DefaultBus.SubscribeEvent(handler, priority);
|
||||
|
||||
public static void UnregisterEvent<TEvent>(Func<TEvent, UniTask> handler) where TEvent : EventBase =>
|
||||
DefaultBus.UnregisterEvent(handler);
|
||||
|
||||
public static void UnregisterEvent<TEvent>(Action<TEvent> handler) where TEvent : EventBase =>
|
||||
DefaultBus.UnregisterEvent(handler);
|
||||
|
||||
public static void ClearAllSubscribersForEvent<TEvent>() where TEvent : EventBase =>
|
||||
DefaultBus.ClearAllSubscribersForEvent<TEvent>();
|
||||
|
||||
public static void UnregisterAllEventsForObject(object targetObject) =>
|
||||
DefaultBus.UnregisterAllEventsForObject(targetObject);
|
||||
|
||||
public static void UnregisterInstance(object targetObject) => DefaultBus.Unregister(targetObject);
|
||||
public static void UnregisterAllEvents() => DefaultBus.UnregisterAllEvents();
|
||||
|
||||
public static UniTask<bool> TriggerEventAsync<TEvent>(TEvent eventArgs) where TEvent : EventBase =>
|
||||
DefaultBus.TriggerEventAsync(eventArgs);
|
||||
|
||||
public static UniTask<bool> TriggerEventAsync<TEvent>(EventPriority phase, TEvent eventArgs)
|
||||
where TEvent : EventBase => DefaultBus.TriggerEventAsync(phase, eventArgs);
|
||||
|
||||
public static bool TriggerEvent<TEvent>(TEvent eventArgs) where TEvent : EventBase =>
|
||||
DefaultBus.TriggerEvent(eventArgs);
|
||||
|
||||
public static bool TriggerEvent<TEvent>(EventPriority phase, TEvent eventArgs) where TEvent : EventBase =>
|
||||
DefaultBus.TriggerEvent(phase, eventArgs);
|
||||
|
||||
public static EventHandlerInfo[] GetEventSubscribers<TEvent>() where TEvent : EventBase =>
|
||||
DefaultBus.GetEventSubscribers<TEvent>();
|
||||
|
||||
public static ListenerList GetListenerList<TEvent>() where TEvent : EventBase =>
|
||||
DefaultBus.GetListenerList<TEvent>();
|
||||
|
||||
public static IReadOnlyDictionary<Type, EventHandlerInfo[]> GetAllSubscribersSnapshot() =>
|
||||
DefaultBus.GetAllSubscribersSnapshot();
|
||||
|
||||
public static IReadOnlyList<ShrinkEventSubscriptionSnapshot> GetActiveSubscriptionsSnapshot() =>
|
||||
DefaultBus.GetActiveSubscriptionsSnapshot();
|
||||
|
||||
public static bool IsInstanceRegistered(object target) => DefaultBus.IsInstanceRegistered(target);
|
||||
public static int GetRegisteredInstanceCount() => DefaultBus.GetRegisteredInstanceCount();
|
||||
public static int GetRegisteredEventTypeCount() => DefaultBus.GetRegisteredEventTypeCount();
|
||||
internal static IReadOnlyList<(ShrinkBusKey Key, ShrinkBusOptions Options, int Subscribers)> Snapshot()
|
||||
{
|
||||
var snapshot = new List<(ShrinkBusKey, ShrinkBusOptions, int)>(Buses.Count);
|
||||
foreach (var pair in Buses)
|
||||
{
|
||||
var subscribers = pair.Value is ShrinkEventBusInstance instance
|
||||
? instance.SubscriberCount
|
||||
: 0;
|
||||
snapshot.Add((pair.Key, pair.Value.Options, subscribers));
|
||||
}
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
private static IShrinkEventBus CreateDefaultBus()
|
||||
{
|
||||
var bus = (ShrinkEventBusInstance)new ShrinkEventBusBuilder()
|
||||
.SetExceptionHandlingMode(ShrinkEventExceptionHandlingMode.LogAndContinue)
|
||||
.AllowPerPhaseDispatch()
|
||||
.Build();
|
||||
EventBusRegHelper.RegStaticEventHandler(bus);
|
||||
var bus = BuildBus(ShrinkBusKey.Game, ShrinkBusOptions.MainThread());
|
||||
Buses[ShrinkBusKey.Game] = bus;
|
||||
ShrinkStaticBindingRegistry.AttachForBus(ShrinkBusKey.Game, Resolver);
|
||||
return bus;
|
||||
}
|
||||
|
||||
private static IShrinkEventBus BuildBus(ShrinkBusKey key, ShrinkBusOptions options) =>
|
||||
new ShrinkEventBusBuilder()
|
||||
.WithKey(key)
|
||||
.WithOptions(options)
|
||||
.WithPostObserver(NotifyPostedObject)
|
||||
.Build();
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static void NotifyPostedObject(IShrinkEvent eventData, Type eventType, ShrinkBusKey key)
|
||||
{
|
||||
_posted?.Invoke(eventData, eventType, key);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static void NotifyDetailedPosted(ShrinkEventTrace trace)
|
||||
{
|
||||
var observers = Volatile.Read(ref _detailedPosted);
|
||||
if (observers == null)
|
||||
return;
|
||||
try
|
||||
{
|
||||
observers(trace);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
UnityEngine.Debug.LogException(exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user