优化EventBus
This commit is contained in:
parent
e7a4150495
commit
9cb3b1e511
@ -170,7 +170,7 @@ namespace AlicizaX.Editor
|
|||||||
EditorGUILayout.EndHorizontal();
|
EditorGUILayout.EndHorizontal();
|
||||||
|
|
||||||
EditorGUILayout.HelpBox(
|
EditorGUILayout.HelpBox(
|
||||||
"这是仅编辑器可用的事件监视器。事件派发期间如果发生订阅、取消订阅、清空或扩容操作,会在编辑器中立即抛出异常。",
|
"这是仅编辑器可用的事件监视器。事件派发期间如果发生订阅、取消订阅、清空或扩容操作,会抛出 InvalidOperationException,Player 中也同样生效。",
|
||||||
MessageType.Info);
|
MessageType.Info);
|
||||||
|
|
||||||
if (_snapshotEntries.Count > 0)
|
if (_snapshotEntries.Count > 0)
|
||||||
@ -269,9 +269,9 @@ namespace AlicizaX.Editor
|
|||||||
string capacityText = row.Initialized ? row.Summary.Capacity.ToString() : row.InitialCapacity.ToString();
|
string capacityText = row.Initialized ? row.Summary.Capacity.ToString() : row.InitialCapacity.ToString();
|
||||||
string status = row.Initialized ? "已初始化" : "未初始化";
|
string status = row.Initialized ? "已初始化" : "未初始化";
|
||||||
EditorGUILayout.LabelField(
|
EditorGUILayout.LabelField(
|
||||||
$"订阅 {row.Summary.SubscriberCount} | 峰值 {row.Summary.PeakSubscriberCount} | 容量 {capacityText} | 发布 {row.Summary.PublishCount}",
|
$"订阅 {row.Summary.SubscriberCount} | in {row.Summary.InSubscriberCount} / 值 {row.Summary.ValueSubscriberCount} | 容量 {capacityText} | 发布 {row.Summary.PublishCount}",
|
||||||
EditorStyles.miniLabel);
|
EditorStyles.miniLabel);
|
||||||
EditorGUILayout.LabelField(status, EditorStyles.miniLabel);
|
EditorGUILayout.LabelField($"{status} | 初始容量 {row.InitialCapacity}", EditorStyles.miniLabel);
|
||||||
|
|
||||||
EditorGUILayout.EndVertical();
|
EditorGUILayout.EndVertical();
|
||||||
}
|
}
|
||||||
@ -301,7 +301,7 @@ namespace AlicizaX.Editor
|
|||||||
}
|
}
|
||||||
|
|
||||||
EventDebugRegistry.TryGetDetails(_selectedEventType, out _, out EventDebugSubscriberInfo[] subscribers);
|
EventDebugRegistry.TryGetDetails(_selectedEventType, out _, out EventDebugSubscriberInfo[] subscribers);
|
||||||
DrawSummary(summary);
|
DrawSummary(summary, GetInitialCapacity(_selectedEventType));
|
||||||
DrawAlerts(summary, subscribers);
|
DrawAlerts(summary, subscribers);
|
||||||
DrawSnapshotDiff(_selectedEventType, summary, subscribers);
|
DrawSnapshotDiff(_selectedEventType, summary, subscribers);
|
||||||
DrawSubscribers(subscribers);
|
DrawSubscribers(subscribers);
|
||||||
@ -310,18 +310,22 @@ namespace AlicizaX.Editor
|
|||||||
EditorGUILayout.EndVertical();
|
EditorGUILayout.EndVertical();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void DrawSummary(EventDebugSummary summary)
|
private static void DrawSummary(EventDebugSummary summary, int initialCapacity)
|
||||||
{
|
{
|
||||||
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
|
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
|
||||||
GUILayout.Label("摘要", EditorStyles.boldLabel);
|
GUILayout.Label("摘要", EditorStyles.boldLabel);
|
||||||
|
EditorGUILayout.LabelField("初始容量", initialCapacity.ToString());
|
||||||
EditorGUILayout.LabelField("当前订阅数", summary.SubscriberCount.ToString());
|
EditorGUILayout.LabelField("当前订阅数", summary.SubscriberCount.ToString());
|
||||||
|
EditorGUILayout.LabelField("当前派发模式", $"in {summary.InSubscriberCount} | 值 {summary.ValueSubscriberCount}");
|
||||||
EditorGUILayout.LabelField("峰值订阅数", summary.PeakSubscriberCount.ToString());
|
EditorGUILayout.LabelField("峰值订阅数", summary.PeakSubscriberCount.ToString());
|
||||||
EditorGUILayout.LabelField("当前容量", summary.Capacity.ToString());
|
EditorGUILayout.LabelField("当前容量", summary.Capacity.ToString());
|
||||||
|
EditorGUILayout.LabelField("容量利用率", FormatRatio(summary.SubscriberCount, summary.Capacity));
|
||||||
EditorGUILayout.LabelField("发布次数", summary.PublishCount.ToString());
|
EditorGUILayout.LabelField("发布次数", summary.PublishCount.ToString());
|
||||||
EditorGUILayout.LabelField("订阅次数", summary.SubscribeCount.ToString());
|
EditorGUILayout.LabelField("订阅次数", summary.SubscribeCount.ToString());
|
||||||
EditorGUILayout.LabelField("取消订阅次数", summary.UnsubscribeCount.ToString());
|
EditorGUILayout.LabelField("取消订阅次数", summary.UnsubscribeCount.ToString());
|
||||||
EditorGUILayout.LabelField("扩容次数", summary.ResizeCount.ToString());
|
EditorGUILayout.LabelField("扩容次数", summary.ResizeCount.ToString());
|
||||||
EditorGUILayout.LabelField("清空次数", summary.ClearCount.ToString());
|
EditorGUILayout.LabelField("清空次数", summary.ClearCount.ToString());
|
||||||
|
EditorGUILayout.LabelField("发布期非法变更", summary.MutationRejectedCount.ToString());
|
||||||
EditorGUILayout.LabelField("最后操作帧", summary.LastOperationFrame.ToString());
|
EditorGUILayout.LabelField("最后操作帧", summary.LastOperationFrame.ToString());
|
||||||
EditorGUILayout.LabelField("最后操作时间", FormatTicks(summary.LastOperationTicksUtc));
|
EditorGUILayout.LabelField("最后操作时间", FormatTicks(summary.LastOperationTicksUtc));
|
||||||
EditorGUILayout.EndVertical();
|
EditorGUILayout.EndVertical();
|
||||||
@ -365,14 +369,20 @@ namespace AlicizaX.Editor
|
|||||||
long unsubscribeDelta = currentSummary.UnsubscribeCount - snapshot.Summary.UnsubscribeCount;
|
long unsubscribeDelta = currentSummary.UnsubscribeCount - snapshot.Summary.UnsubscribeCount;
|
||||||
int resizeDelta = currentSummary.ResizeCount - snapshot.Summary.ResizeCount;
|
int resizeDelta = currentSummary.ResizeCount - snapshot.Summary.ResizeCount;
|
||||||
int capacityDelta = currentSummary.Capacity - snapshot.Summary.Capacity;
|
int capacityDelta = currentSummary.Capacity - snapshot.Summary.Capacity;
|
||||||
|
int valueSubscriberDelta = currentSummary.ValueSubscriberCount - snapshot.Summary.ValueSubscriberCount;
|
||||||
|
int inSubscriberDelta = currentSummary.InSubscriberCount - snapshot.Summary.InSubscriberCount;
|
||||||
|
long mutationRejectedDelta = currentSummary.MutationRejectedCount - snapshot.Summary.MutationRejectedCount;
|
||||||
|
|
||||||
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
|
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
|
||||||
EditorGUILayout.LabelField("订阅数变化", FormatSigned(subscriberDelta));
|
EditorGUILayout.LabelField("订阅数变化", FormatSigned(subscriberDelta));
|
||||||
|
EditorGUILayout.LabelField("in 订阅变化", FormatSigned(inSubscriberDelta));
|
||||||
|
EditorGUILayout.LabelField("值传参订阅变化", FormatSigned(valueSubscriberDelta));
|
||||||
EditorGUILayout.LabelField("发布次数变化", FormatSigned(publishDelta));
|
EditorGUILayout.LabelField("发布次数变化", FormatSigned(publishDelta));
|
||||||
EditorGUILayout.LabelField("订阅次数变化", FormatSigned(subscribeDelta));
|
EditorGUILayout.LabelField("订阅次数变化", FormatSigned(subscribeDelta));
|
||||||
EditorGUILayout.LabelField("取消订阅次数变化", FormatSigned(unsubscribeDelta));
|
EditorGUILayout.LabelField("取消订阅次数变化", FormatSigned(unsubscribeDelta));
|
||||||
EditorGUILayout.LabelField("扩容次数变化", FormatSigned(resizeDelta));
|
EditorGUILayout.LabelField("扩容次数变化", FormatSigned(resizeDelta));
|
||||||
EditorGUILayout.LabelField("容量变化", FormatSigned(capacityDelta));
|
EditorGUILayout.LabelField("容量变化", FormatSigned(capacityDelta));
|
||||||
|
EditorGUILayout.LabelField("非法变更变化", FormatSigned(mutationRejectedDelta));
|
||||||
|
|
||||||
List<string> addedSubscribers = GetSubscriberDiff(currentSubscribers, snapshot.Subscribers);
|
List<string> addedSubscribers = GetSubscriberDiff(currentSubscribers, snapshot.Subscribers);
|
||||||
List<string> removedSubscribers = GetSubscriberDiff(snapshot.Subscribers, currentSubscribers);
|
List<string> removedSubscribers = GetSubscriberDiff(snapshot.Subscribers, currentSubscribers);
|
||||||
@ -444,10 +454,13 @@ namespace AlicizaX.Editor
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (summary.SubscriberCount != snapshot.Summary.SubscriberCount ||
|
if (summary.SubscriberCount != snapshot.Summary.SubscriberCount ||
|
||||||
|
summary.ValueSubscriberCount != snapshot.Summary.ValueSubscriberCount ||
|
||||||
|
summary.InSubscriberCount != snapshot.Summary.InSubscriberCount ||
|
||||||
summary.PublishCount != snapshot.Summary.PublishCount ||
|
summary.PublishCount != snapshot.Summary.PublishCount ||
|
||||||
summary.SubscribeCount != snapshot.Summary.SubscribeCount ||
|
summary.SubscribeCount != snapshot.Summary.SubscribeCount ||
|
||||||
summary.UnsubscribeCount != snapshot.Summary.UnsubscribeCount ||
|
summary.UnsubscribeCount != snapshot.Summary.UnsubscribeCount ||
|
||||||
summary.ResizeCount != snapshot.Summary.ResizeCount ||
|
summary.ResizeCount != snapshot.Summary.ResizeCount ||
|
||||||
|
summary.MutationRejectedCount != snapshot.Summary.MutationRejectedCount ||
|
||||||
summary.Capacity != snapshot.Summary.Capacity)
|
summary.Capacity != snapshot.Summary.Capacity)
|
||||||
{
|
{
|
||||||
changedCount++;
|
changedCount++;
|
||||||
@ -465,12 +478,18 @@ namespace AlicizaX.Editor
|
|||||||
EditorGUILayout.LabelField("版本", subscriber.Version.ToString());
|
EditorGUILayout.LabelField("版本", subscriber.Version.ToString());
|
||||||
EditorGUILayout.LabelField("目标", subscriber.TargetTypeName);
|
EditorGUILayout.LabelField("目标", subscriber.TargetTypeName);
|
||||||
EditorGUILayout.LabelField("类型", subscriber.IsStatic ? "静态方法" : "实例方法");
|
EditorGUILayout.LabelField("类型", subscriber.IsStatic ? "静态方法" : "实例方法");
|
||||||
|
EditorGUILayout.LabelField("派发方式", subscriber.UsesInParameter ? "in" : "按值复制");
|
||||||
|
|
||||||
if (subscriber.IsUnityObjectDestroyed)
|
if (subscriber.IsUnityObjectDestroyed)
|
||||||
{
|
{
|
||||||
EditorGUILayout.HelpBox("Unity 目标对象已经被销毁,但委托仍然存在。", MessageType.Warning);
|
EditorGUILayout.HelpBox("Unity 目标对象已经被销毁,但委托仍然存在。", MessageType.Warning);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (subscriber.IsCompilerGeneratedTarget || subscriber.IsCompilerGeneratedMethod)
|
||||||
|
{
|
||||||
|
EditorGUILayout.HelpBox("该订阅者看起来来自 lambda 或闭包,可能带来额外分配或生命周期问题。", MessageType.Info);
|
||||||
|
}
|
||||||
|
|
||||||
if (subscriber.UnityTarget != null && !subscriber.IsUnityObjectDestroyed)
|
if (subscriber.UnityTarget != null && !subscriber.IsUnityObjectDestroyed)
|
||||||
{
|
{
|
||||||
if (GUILayout.Button("定位目标", GUILayout.Width(90f)))
|
if (GUILayout.Button("定位目标", GUILayout.Width(90f)))
|
||||||
@ -531,7 +550,7 @@ namespace AlicizaX.Editor
|
|||||||
bool initialized = summaries.TryGetValue(eventType, out EventDebugSummary summary);
|
bool initialized = summaries.TryGetValue(eventType, out EventDebugSummary summary);
|
||||||
EventDebugSummary rowSummary = initialized
|
EventDebugSummary rowSummary = initialized
|
||||||
? summary
|
? summary
|
||||||
: new EventDebugSummary(eventType, false, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
|
: new EventDebugSummary(eventType, false, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
|
||||||
|
|
||||||
EventRow row = new EventRow(eventType, initialized, rowSummary, GetInitialCapacity(eventType));
|
EventRow row = new EventRow(eventType, initialized, rowSummary, GetInitialCapacity(eventType));
|
||||||
if (MatchesFilter(row))
|
if (MatchesFilter(row))
|
||||||
@ -658,6 +677,17 @@ namespace AlicizaX.Editor
|
|||||||
return new DateTime(ticksUtc, DateTimeKind.Utc).ToLocalTime().ToString("HH:mm:ss");
|
return new DateTime(ticksUtc, DateTimeKind.Utc).ToLocalTime().ToString("HH:mm:ss");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static string FormatRatio(int value, int capacity)
|
||||||
|
{
|
||||||
|
if (capacity <= 0)
|
||||||
|
{
|
||||||
|
return "-";
|
||||||
|
}
|
||||||
|
|
||||||
|
float percent = value / (float)capacity * 100f;
|
||||||
|
return $"{percent:F1}% ({value}/{capacity})";
|
||||||
|
}
|
||||||
|
|
||||||
private static string FormatSigned(int value)
|
private static string FormatSigned(int value)
|
||||||
{
|
{
|
||||||
if (value > 0)
|
if (value > 0)
|
||||||
@ -682,12 +712,18 @@ namespace AlicizaX.Editor
|
|||||||
{
|
{
|
||||||
List<EventAlert> alerts = new();
|
List<EventAlert> alerts = new();
|
||||||
int destroyedTargetCount = 0;
|
int destroyedTargetCount = 0;
|
||||||
|
int compilerGeneratedCount = 0;
|
||||||
for (int i = 0; i < subscribers.Length; i++)
|
for (int i = 0; i < subscribers.Length; i++)
|
||||||
{
|
{
|
||||||
if (subscribers[i].IsUnityObjectDestroyed)
|
if (subscribers[i].IsUnityObjectDestroyed)
|
||||||
{
|
{
|
||||||
destroyedTargetCount++;
|
destroyedTargetCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (subscribers[i].IsCompilerGeneratedMethod || subscribers[i].IsCompilerGeneratedTarget)
|
||||||
|
{
|
||||||
|
compilerGeneratedCount++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (destroyedTargetCount > 0)
|
if (destroyedTargetCount > 0)
|
||||||
@ -695,6 +731,11 @@ namespace AlicizaX.Editor
|
|||||||
alerts.Add(new EventAlert(MessageType.Warning, $"发现 {destroyedTargetCount} 个订阅者的 Unity 目标对象已经被销毁。"));
|
alerts.Add(new EventAlert(MessageType.Warning, $"发现 {destroyedTargetCount} 个订阅者的 Unity 目标对象已经被销毁。"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (summary.MutationRejectedCount > 0)
|
||||||
|
{
|
||||||
|
alerts.Add(new EventAlert(MessageType.Warning, $"派发期间发生了 {summary.MutationRejectedCount} 次非法变更尝试,运行时会直接抛异常。"));
|
||||||
|
}
|
||||||
|
|
||||||
if (summary.ResizeCount > 0)
|
if (summary.ResizeCount > 0)
|
||||||
{
|
{
|
||||||
alerts.Add(new EventAlert(MessageType.Warning, $"容器已经扩容 {summary.ResizeCount} 次,当前事件的 Prewarm 可能偏小。"));
|
alerts.Add(new EventAlert(MessageType.Warning, $"容器已经扩容 {summary.ResizeCount} 次,当前事件的 Prewarm 可能偏小。"));
|
||||||
@ -705,6 +746,16 @@ namespace AlicizaX.Editor
|
|||||||
alerts.Add(new EventAlert(MessageType.Info, $"当前容量 {summary.Capacity} 远大于峰值订阅数 {summary.PeakSubscriberCount},Prewarm 可能偏大。"));
|
alerts.Add(new EventAlert(MessageType.Info, $"当前容量 {summary.Capacity} 远大于峰值订阅数 {summary.PeakSubscriberCount},Prewarm 可能偏大。"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (summary.ValueSubscriberCount > 0)
|
||||||
|
{
|
||||||
|
alerts.Add(new EventAlert(MessageType.Info, $"当前仍有 {summary.ValueSubscriberCount} 个订阅者使用按值传参;事件体较大时建议改成 in 处理器。"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (compilerGeneratedCount > 0)
|
||||||
|
{
|
||||||
|
alerts.Add(new EventAlert(MessageType.Info, $"检测到 {compilerGeneratedCount} 个编译器生成的订阅者,通常意味着 lambda 或闭包。"));
|
||||||
|
}
|
||||||
|
|
||||||
long churn = summary.SubscribeCount + summary.UnsubscribeCount;
|
long churn = summary.SubscribeCount + summary.UnsubscribeCount;
|
||||||
if (churn > 0 && summary.PublishCount == 0)
|
if (churn > 0 && summary.PublishCount == 0)
|
||||||
{
|
{
|
||||||
@ -769,6 +820,7 @@ namespace AlicizaX.Editor
|
|||||||
{
|
{
|
||||||
builder.Append(" [static]");
|
builder.Append(" [static]");
|
||||||
}
|
}
|
||||||
|
builder.Append(subscriber.UsesInParameter ? " [in]" : " [value]");
|
||||||
|
|
||||||
return builder.ToString();
|
return builder.ToString();
|
||||||
}
|
}
|
||||||
@ -782,6 +834,7 @@ namespace AlicizaX.Editor
|
|||||||
EventDebugOperationKind.Publish => "发布",
|
EventDebugOperationKind.Publish => "发布",
|
||||||
EventDebugOperationKind.Resize => "扩容",
|
EventDebugOperationKind.Resize => "扩容",
|
||||||
EventDebugOperationKind.Clear => "清空",
|
EventDebugOperationKind.Clear => "清空",
|
||||||
|
EventDebugOperationKind.MutationRejected => "非法变更",
|
||||||
_ => kind.ToString()
|
_ => kind.ToString()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,6 +15,15 @@ namespace AlicizaX
|
|||||||
return EventContainer<T>.Subscribe(handler);
|
return EventContainer<T>.Subscribe(handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Il2CppSetOption(Option.NullChecks, false)]
|
||||||
|
[Il2CppSetOption(Option.DivideByZeroChecks, false)]
|
||||||
|
[Il2CppSetOption(Option.ArrayBoundsChecks, false)]
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static EventRuntimeHandle Subscribe<T>(InEventHandler<T> handler) where T : struct, IEventArgs
|
||||||
|
{
|
||||||
|
return EventContainer<T>.Subscribe(handler);
|
||||||
|
}
|
||||||
|
|
||||||
[Il2CppSetOption(Option.NullChecks, false)]
|
[Il2CppSetOption(Option.NullChecks, false)]
|
||||||
[Il2CppSetOption(Option.DivideByZeroChecks, false)]
|
[Il2CppSetOption(Option.DivideByZeroChecks, false)]
|
||||||
[Il2CppSetOption(Option.ArrayBoundsChecks, false)]
|
[Il2CppSetOption(Option.ArrayBoundsChecks, false)]
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using Unity.IL2CPP.CompilerServices;
|
using Unity.IL2CPP.CompilerServices;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
@ -14,26 +13,31 @@ namespace AlicizaX
|
|||||||
private static readonly int InitialSize = EventInitialSize<TPayload>.Size;
|
private static readonly int InitialSize = EventInitialSize<TPayload>.Size;
|
||||||
private static readonly int TypeId;
|
private static readonly int TypeId;
|
||||||
|
|
||||||
private static Action<TPayload>[] _callbacks;
|
private static Action<TPayload>[] _valueCallbacks;
|
||||||
|
private static InEventHandler<TPayload>[] _inCallbacks;
|
||||||
private static int[] _versions;
|
private static int[] _versions;
|
||||||
private static int[] _activeSlots;
|
private static int[] _activeSlots;
|
||||||
|
|
||||||
private static int[] _freeSlots;
|
private static int[] _freeSlots;
|
||||||
private static int _freeCount;
|
|
||||||
private static int[] _activeIndices;
|
private static int[] _activeIndices;
|
||||||
|
|
||||||
|
private static int _freeCount;
|
||||||
private static int _activeCount;
|
private static int _activeCount;
|
||||||
|
private static int _valueSubscriberCount;
|
||||||
|
private static int _inSubscriberCount;
|
||||||
private static int _version;
|
private static int _version;
|
||||||
|
private static int _publishDepth;
|
||||||
|
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
private static int _publishDepth;
|
private static System.Collections.Generic.HashSet<Action<TPayload>> _activeValueHandlers;
|
||||||
private static System.Collections.Generic.HashSet<Action<TPayload>> _activeHandlers;
|
private static System.Collections.Generic.HashSet<InEventHandler<TPayload>> _activeInHandlers;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static EventContainer()
|
static EventContainer()
|
||||||
{
|
{
|
||||||
TypeId = UnsubscribeRegistry.Register(Unsubscribe);
|
TypeId = UnsubscribeRegistry.Register(Unsubscribe);
|
||||||
|
|
||||||
_callbacks = new Action<TPayload>[InitialSize];
|
_valueCallbacks = new Action<TPayload>[InitialSize];
|
||||||
|
_inCallbacks = new InEventHandler<TPayload>[InitialSize];
|
||||||
_versions = new int[InitialSize];
|
_versions = new int[InitialSize];
|
||||||
_activeSlots = new int[InitialSize];
|
_activeSlots = new int[InitialSize];
|
||||||
_freeSlots = new int[InitialSize];
|
_freeSlots = new int[InitialSize];
|
||||||
@ -46,47 +50,100 @@ namespace AlicizaX
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
_activeHandlers = new System.Collections.Generic.HashSet<Action<TPayload>>();
|
_activeValueHandlers = new System.Collections.Generic.HashSet<Action<TPayload>>();
|
||||||
EventDebugRegistry.RegisterContainer<TPayload>(GetDebugSubscriberCount, GetDebugCapacity, GetDebugSubscribers);
|
_activeInHandlers = new System.Collections.Generic.HashSet<InEventHandler<TPayload>>();
|
||||||
|
EventDebugRegistry.RegisterContainer<TPayload>(
|
||||||
|
GetDebugSubscriberCount,
|
||||||
|
GetDebugCapacity,
|
||||||
|
GetDebugValueSubscriberCount,
|
||||||
|
GetDebugInSubscriberCount,
|
||||||
|
GetDebugSubscribers);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static EventRuntimeHandle Subscribe(Action<TPayload> callback)
|
public static EventRuntimeHandle Subscribe(Action<TPayload> callback)
|
||||||
{
|
{
|
||||||
#if UNITY_EDITOR
|
if (callback == null) throw new ArgumentNullException(nameof(callback));
|
||||||
|
|
||||||
ThrowIfMutatingDuringPublish("subscribe");
|
ThrowIfMutatingDuringPublish("subscribe");
|
||||||
if (_activeHandlers.Contains(callback))
|
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
if (_activeValueHandlers.Contains(callback))
|
||||||
{
|
{
|
||||||
Log.Warning($"重复订阅事件处理程序: {callback.Method.Name}");
|
Log.Warning($"重复订阅事件处理程序: {callback.Method.Name}");
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
|
|
||||||
_activeHandlers.Add(callback);
|
_activeValueHandlers.Add(callback);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int handlerIndex = GetFreeSlot();
|
return SubscribeCore(callback, null);
|
||||||
|
}
|
||||||
|
|
||||||
if (_activeCount >= _activeIndices.Length)
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static EventRuntimeHandle Subscribe(InEventHandler<TPayload> callback)
|
||||||
|
{
|
||||||
|
if (callback == null) throw new ArgumentNullException(nameof(callback));
|
||||||
|
|
||||||
|
ThrowIfMutatingDuringPublish("subscribe");
|
||||||
|
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
if (_activeInHandlers.Contains(callback))
|
||||||
{
|
{
|
||||||
Array.Resize(ref _activeIndices, _activeIndices.Length << 1);
|
Log.Warning($"重复订阅事件处理程序: {callback.Method.Name}");
|
||||||
|
return default;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_activeInHandlers.Add(callback);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return SubscribeCore(null, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private static EventRuntimeHandle SubscribeCore(Action<TPayload> valueCallback, InEventHandler<TPayload> inCallback)
|
||||||
|
{
|
||||||
|
int handlerIndex = GetFreeSlot();
|
||||||
|
EnsureActiveIndicesCapacity();
|
||||||
|
|
||||||
int activeIndex = _activeCount++;
|
int activeIndex = _activeCount++;
|
||||||
_activeIndices[activeIndex] = handlerIndex;
|
_activeIndices[activeIndex] = handlerIndex;
|
||||||
|
|
||||||
int version = ++_version;
|
int version = ++_version;
|
||||||
_callbacks[handlerIndex] = callback;
|
_valueCallbacks[handlerIndex] = valueCallback;
|
||||||
|
_inCallbacks[handlerIndex] = inCallback;
|
||||||
_versions[handlerIndex] = version;
|
_versions[handlerIndex] = version;
|
||||||
_activeSlots[handlerIndex] = activeIndex;
|
_activeSlots[handlerIndex] = activeIndex;
|
||||||
|
|
||||||
|
if (inCallback != null)
|
||||||
|
{
|
||||||
|
_inSubscriberCount++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_valueSubscriberCount++;
|
||||||
|
}
|
||||||
|
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
EventDebugRegistry.RecordSubscribe<TPayload>(_activeCount, _callbacks.Length);
|
EventDebugRegistry.RecordSubscribe<TPayload>(_activeCount, _valueCallbacks.Length);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return new EventRuntimeHandle(TypeId, handlerIndex, version);
|
return new EventRuntimeHandle(TypeId, handlerIndex, version);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private static void EnsureActiveIndicesCapacity()
|
||||||
|
{
|
||||||
|
if (_activeCount < _activeIndices.Length)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int newSize = _activeIndices.Length == 0 ? 64 : _activeIndices.Length << 1;
|
||||||
|
Array.Resize(ref _activeIndices, newSize);
|
||||||
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private static int GetFreeSlot()
|
private static int GetFreeSlot()
|
||||||
{
|
{
|
||||||
@ -95,10 +152,11 @@ namespace AlicizaX
|
|||||||
return _freeSlots[--_freeCount];
|
return _freeSlots[--_freeCount];
|
||||||
}
|
}
|
||||||
|
|
||||||
int oldLen = _callbacks.Length;
|
int oldLen = _valueCallbacks.Length;
|
||||||
int newSize = oldLen == 0 ? 64 : oldLen << 1;
|
int newSize = oldLen == 0 ? 64 : oldLen << 1;
|
||||||
|
|
||||||
Array.Resize(ref _callbacks, newSize);
|
Array.Resize(ref _valueCallbacks, newSize);
|
||||||
|
Array.Resize(ref _inCallbacks, newSize);
|
||||||
Array.Resize(ref _versions, newSize);
|
Array.Resize(ref _versions, newSize);
|
||||||
Array.Resize(ref _activeSlots, newSize);
|
Array.Resize(ref _activeSlots, newSize);
|
||||||
Array.Resize(ref _freeSlots, newSize);
|
Array.Resize(ref _freeSlots, newSize);
|
||||||
@ -109,7 +167,7 @@ namespace AlicizaX
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
EventDebugRegistry.RecordResize<TPayload>(_activeCount, _callbacks.Length);
|
EventDebugRegistry.RecordResize<TPayload>(_activeCount, _valueCallbacks.Length);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return _freeSlots[--_freeCount];
|
return _freeSlots[--_freeCount];
|
||||||
@ -118,95 +176,106 @@ namespace AlicizaX
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private static void Unsubscribe(int handlerIndex, int version)
|
private static void Unsubscribe(int handlerIndex, int version)
|
||||||
{
|
{
|
||||||
#if UNITY_EDITOR
|
|
||||||
ThrowIfMutatingDuringPublish("unsubscribe");
|
ThrowIfMutatingDuringPublish("unsubscribe");
|
||||||
#endif
|
|
||||||
|
|
||||||
|
if ((uint)handlerIndex >= (uint)_versions.Length) return;
|
||||||
if (_versions[handlerIndex] != version) return;
|
if (_versions[handlerIndex] != version) return;
|
||||||
|
|
||||||
int lastActiveIndex = --_activeCount;
|
|
||||||
int lastHandlerIndex = _activeIndices[lastActiveIndex];
|
|
||||||
int currentActiveIndex = _activeSlots[handlerIndex];
|
int currentActiveIndex = _activeSlots[handlerIndex];
|
||||||
|
int lastActiveIndex = --_activeCount;
|
||||||
|
|
||||||
|
if (currentActiveIndex != lastActiveIndex)
|
||||||
_activeIndices[currentActiveIndex] = lastHandlerIndex;
|
|
||||||
_activeSlots[lastHandlerIndex] = currentActiveIndex;
|
|
||||||
|
|
||||||
#if UNITY_EDITOR
|
|
||||||
_activeHandlers.Remove(_callbacks[handlerIndex]);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
_callbacks[handlerIndex] = null;
|
|
||||||
_versions[handlerIndex] = 0;
|
|
||||||
|
|
||||||
if (_freeCount >= _freeSlots.Length)
|
|
||||||
{
|
{
|
||||||
Array.Resize(ref _freeSlots, _freeSlots.Length << 1);
|
int lastHandlerIndex = _activeIndices[lastActiveIndex];
|
||||||
|
_activeIndices[currentActiveIndex] = lastHandlerIndex;
|
||||||
|
_activeSlots[lastHandlerIndex] = currentActiveIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
RemoveActiveHandler(handlerIndex);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (_inCallbacks[handlerIndex] != null)
|
||||||
|
{
|
||||||
|
_inSubscriberCount--;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_valueSubscriberCount--;
|
||||||
|
}
|
||||||
|
|
||||||
|
_valueCallbacks[handlerIndex] = null;
|
||||||
|
_inCallbacks[handlerIndex] = null;
|
||||||
|
_versions[handlerIndex] = 0;
|
||||||
|
_activeSlots[handlerIndex] = 0;
|
||||||
|
_activeIndices[lastActiveIndex] = 0;
|
||||||
_freeSlots[_freeCount++] = handlerIndex;
|
_freeSlots[_freeCount++] = handlerIndex;
|
||||||
|
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
EventDebugRegistry.RecordUnsubscribe<TPayload>(_activeCount, _callbacks.Length);
|
EventDebugRegistry.RecordUnsubscribe<TPayload>(_activeCount, _valueCallbacks.Length);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static void Publish(in TPayload payload)
|
public static void Publish(in TPayload payload)
|
||||||
{
|
{
|
||||||
#if UNITY_EDITOR
|
|
||||||
_publishDepth++;
|
_publishDepth++;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
#endif
|
int count = _activeCount;
|
||||||
int count = _activeCount;
|
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
EventDebugRegistry.RecordPublish<TPayload>(count, _callbacks.Length);
|
EventDebugRegistry.RecordPublish<TPayload>(count, _valueCallbacks.Length);
|
||||||
#endif
|
#endif
|
||||||
if (count == 0) return;
|
if (count == 0) return;
|
||||||
|
|
||||||
int[] indices = _activeIndices;
|
int[] indices = _activeIndices;
|
||||||
Action<TPayload>[] callbacks = _callbacks;
|
Action<TPayload>[] valueCallbacks = _valueCallbacks;
|
||||||
|
InEventHandler<TPayload>[] inCallbacks = _inCallbacks;
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
int unrolled = count & ~3; // count - (count % 4)
|
int unrolled = count & ~3;
|
||||||
|
|
||||||
for (; i < unrolled; i += 4)
|
for (; i < unrolled; i += 4)
|
||||||
{
|
{
|
||||||
int idx0 = indices[i];
|
InvokeHandler(valueCallbacks, inCallbacks, indices[i], in payload);
|
||||||
int idx1 = indices[i + 1];
|
InvokeHandler(valueCallbacks, inCallbacks, indices[i + 1], in payload);
|
||||||
int idx2 = indices[i + 2];
|
InvokeHandler(valueCallbacks, inCallbacks, indices[i + 2], in payload);
|
||||||
int idx3 = indices[i + 3];
|
InvokeHandler(valueCallbacks, inCallbacks, indices[i + 3], in payload);
|
||||||
|
}
|
||||||
|
|
||||||
callbacks[idx0](payload);
|
switch (count - i)
|
||||||
callbacks[idx1](payload);
|
{
|
||||||
callbacks[idx2](payload);
|
case 3:
|
||||||
callbacks[idx3](payload);
|
InvokeHandler(valueCallbacks, inCallbacks, indices[i], in payload);
|
||||||
}
|
InvokeHandler(valueCallbacks, inCallbacks, indices[i + 1], in payload);
|
||||||
|
InvokeHandler(valueCallbacks, inCallbacks, indices[i + 2], in payload);
|
||||||
switch (count - i)
|
break;
|
||||||
{
|
case 2:
|
||||||
case 3:
|
InvokeHandler(valueCallbacks, inCallbacks, indices[i], in payload);
|
||||||
callbacks[indices[i]](payload);
|
InvokeHandler(valueCallbacks, inCallbacks, indices[i + 1], in payload);
|
||||||
callbacks[indices[i + 1]](payload);
|
break;
|
||||||
callbacks[indices[i + 2]](payload);
|
case 1:
|
||||||
break;
|
InvokeHandler(valueCallbacks, inCallbacks, indices[i], in payload);
|
||||||
case 2:
|
break;
|
||||||
callbacks[indices[i]](payload);
|
}
|
||||||
callbacks[indices[i + 1]](payload);
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
callbacks[indices[i]](payload);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
#if UNITY_EDITOR
|
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
_publishDepth--;
|
_publishDepth--;
|
||||||
}
|
}
|
||||||
#endif
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private static void InvokeHandler(Action<TPayload>[] valueCallbacks, InEventHandler<TPayload>[] inCallbacks, int handlerIndex, in TPayload payload)
|
||||||
|
{
|
||||||
|
InEventHandler<TPayload> inCallback = inCallbacks[handlerIndex];
|
||||||
|
if (inCallback != null)
|
||||||
|
{
|
||||||
|
inCallback(in payload);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
valueCallbacks[handlerIndex](payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int SubscriberCount
|
public static int SubscriberCount
|
||||||
@ -217,14 +286,15 @@ namespace AlicizaX
|
|||||||
|
|
||||||
public static void EnsureCapacity(int capacity)
|
public static void EnsureCapacity(int capacity)
|
||||||
{
|
{
|
||||||
#if UNITY_EDITOR
|
if (capacity < 0) throw new ArgumentOutOfRangeException(nameof(capacity));
|
||||||
|
|
||||||
ThrowIfMutatingDuringPublish("ensure capacity");
|
ThrowIfMutatingDuringPublish("ensure capacity");
|
||||||
#endif
|
|
||||||
|
|
||||||
if (_callbacks.Length >= capacity) return;
|
if (_valueCallbacks.Length >= capacity) return;
|
||||||
|
|
||||||
int oldLen = _callbacks.Length;
|
int oldLen = _valueCallbacks.Length;
|
||||||
Array.Resize(ref _callbacks, capacity);
|
Array.Resize(ref _valueCallbacks, capacity);
|
||||||
|
Array.Resize(ref _inCallbacks, capacity);
|
||||||
Array.Resize(ref _versions, capacity);
|
Array.Resize(ref _versions, capacity);
|
||||||
Array.Resize(ref _activeSlots, capacity);
|
Array.Resize(ref _activeSlots, capacity);
|
||||||
Array.Resize(ref _freeSlots, capacity);
|
Array.Resize(ref _freeSlots, capacity);
|
||||||
@ -236,48 +306,83 @@ namespace AlicizaX
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
EventDebugRegistry.RecordResize<TPayload>(_activeCount, _callbacks.Length);
|
EventDebugRegistry.RecordResize<TPayload>(_activeCount, _valueCallbacks.Length);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Clear()
|
public static void Clear()
|
||||||
{
|
{
|
||||||
#if UNITY_EDITOR
|
|
||||||
ThrowIfMutatingDuringPublish("clear");
|
ThrowIfMutatingDuringPublish("clear");
|
||||||
#endif
|
|
||||||
|
|
||||||
for (int i = 0; i < _activeCount; i++)
|
for (int i = 0; i < _activeCount; i++)
|
||||||
{
|
{
|
||||||
int idx = _activeIndices[i];
|
int idx = _activeIndices[i];
|
||||||
_callbacks[idx] = null;
|
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
RemoveActiveHandler(idx);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
_valueCallbacks[idx] = null;
|
||||||
|
_inCallbacks[idx] = null;
|
||||||
_versions[idx] = 0;
|
_versions[idx] = 0;
|
||||||
|
_activeSlots[idx] = 0;
|
||||||
_freeSlots[_freeCount++] = idx;
|
_freeSlots[_freeCount++] = idx;
|
||||||
|
_activeIndices[i] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
_activeCount = 0;
|
_activeCount = 0;
|
||||||
|
_valueSubscriberCount = 0;
|
||||||
|
_inSubscriberCount = 0;
|
||||||
|
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
EventDebugRegistry.RecordClear<TPayload>(_activeCount, _callbacks.Length);
|
EventDebugRegistry.RecordClear<TPayload>(_activeCount, _valueCallbacks.Length);
|
||||||
_activeHandlers.Clear();
|
_activeValueHandlers.Clear();
|
||||||
|
_activeInHandlers.Clear();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#if UNITY_EDITOR
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private static void ThrowIfMutatingDuringPublish(string operation)
|
private static void ThrowIfMutatingDuringPublish(string operation)
|
||||||
{
|
{
|
||||||
if (_publishDepth <= 0) return;
|
if (_publishDepth <= 0) return;
|
||||||
|
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
EventDebugRegistry.RecordMutationRejected<TPayload>(_activeCount, _valueCallbacks.Length);
|
||||||
|
#endif
|
||||||
throw new InvalidOperationException(
|
throw new InvalidOperationException(
|
||||||
$"EventContainer<{typeof(TPayload).Name}> cannot {operation} while publishing. " +
|
$"EventContainer<{typeof(TPayload).Name}> cannot {operation} while publishing. " +
|
||||||
"Supporting dispatch-time mutations would require slower publish semantics.");
|
"This bus guarantees a stable subscriber set during dispatch. Apply the mutation after publish completes.");
|
||||||
|
}
|
||||||
|
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private static void RemoveActiveHandler(int handlerIndex)
|
||||||
|
{
|
||||||
|
Action<TPayload> valueCallback = _valueCallbacks[handlerIndex];
|
||||||
|
if (valueCallback != null)
|
||||||
|
{
|
||||||
|
_activeValueHandlers.Remove(valueCallback);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
InEventHandler<TPayload> inCallback = _inCallbacks[handlerIndex];
|
||||||
|
if (inCallback != null)
|
||||||
|
{
|
||||||
|
_activeInHandlers.Remove(inCallback);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private static int GetDebugSubscriberCount() => _activeCount;
|
private static int GetDebugSubscriberCount() => _activeCount;
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private static int GetDebugCapacity() => _callbacks.Length;
|
private static int GetDebugCapacity() => _valueCallbacks.Length;
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private static int GetDebugValueSubscriberCount() => _valueSubscriberCount;
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private static int GetDebugInSubscriberCount() => _inSubscriberCount;
|
||||||
|
|
||||||
private static EventDebugSubscriberInfo[] GetDebugSubscribers()
|
private static EventDebugSubscriberInfo[] GetDebugSubscribers()
|
||||||
{
|
{
|
||||||
@ -291,10 +396,15 @@ namespace AlicizaX
|
|||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
int handlerIndex = _activeIndices[i];
|
int handlerIndex = _activeIndices[i];
|
||||||
Action<TPayload> callback = _callbacks[handlerIndex];
|
Action<TPayload> valueCallback = _valueCallbacks[handlerIndex];
|
||||||
|
InEventHandler<TPayload> inCallback = _inCallbacks[handlerIndex];
|
||||||
|
Delegate callback = (Delegate)inCallback ?? valueCallback;
|
||||||
object target = callback.Target;
|
object target = callback.Target;
|
||||||
bool isStatic = target == null;
|
bool isStatic = target == null;
|
||||||
bool isUnityObjectDestroyed = false;
|
bool isUnityObjectDestroyed = false;
|
||||||
|
bool usesInParameter = inCallback != null;
|
||||||
|
bool isCompilerGeneratedTarget = !isStatic && target.GetType().IsDefined(typeof(CompilerGeneratedAttribute), false);
|
||||||
|
bool isCompilerGeneratedMethod = callback.Method.IsDefined(typeof(CompilerGeneratedAttribute), false);
|
||||||
UnityEngine.Object unityTarget = null;
|
UnityEngine.Object unityTarget = null;
|
||||||
|
|
||||||
if (!isStatic && target is UnityEngine.Object engineObject)
|
if (!isStatic && target is UnityEngine.Object engineObject)
|
||||||
@ -311,7 +421,10 @@ namespace AlicizaX
|
|||||||
target?.GetType().FullName ?? "<Static>",
|
target?.GetType().FullName ?? "<Static>",
|
||||||
unityTarget,
|
unityTarget,
|
||||||
isStatic,
|
isStatic,
|
||||||
isUnityObjectDestroyed);
|
isUnityObjectDestroyed,
|
||||||
|
usesInParameter,
|
||||||
|
isCompilerGeneratedTarget,
|
||||||
|
isCompilerGeneratedMethod);
|
||||||
}
|
}
|
||||||
|
|
||||||
return subscribers;
|
return subscribers;
|
||||||
|
|||||||
@ -1,3 +1,11 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 0b7c9a97647245b0a2e0a52e81a466db
|
guid: 0b7c9a97647245b0a2e0a52e81a466db
|
||||||
timeCreated: 1763091204
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
|
|||||||
@ -11,7 +11,8 @@ namespace AlicizaX
|
|||||||
Unsubscribe,
|
Unsubscribe,
|
||||||
Publish,
|
Publish,
|
||||||
Resize,
|
Resize,
|
||||||
Clear
|
Clear,
|
||||||
|
MutationRejected
|
||||||
}
|
}
|
||||||
|
|
||||||
internal readonly struct EventDebugSummary
|
internal readonly struct EventDebugSummary
|
||||||
@ -21,11 +22,14 @@ namespace AlicizaX
|
|||||||
internal readonly int SubscriberCount;
|
internal readonly int SubscriberCount;
|
||||||
internal readonly int PeakSubscriberCount;
|
internal readonly int PeakSubscriberCount;
|
||||||
internal readonly int Capacity;
|
internal readonly int Capacity;
|
||||||
|
internal readonly int ValueSubscriberCount;
|
||||||
|
internal readonly int InSubscriberCount;
|
||||||
internal readonly long PublishCount;
|
internal readonly long PublishCount;
|
||||||
internal readonly long SubscribeCount;
|
internal readonly long SubscribeCount;
|
||||||
internal readonly long UnsubscribeCount;
|
internal readonly long UnsubscribeCount;
|
||||||
internal readonly int ResizeCount;
|
internal readonly int ResizeCount;
|
||||||
internal readonly int ClearCount;
|
internal readonly int ClearCount;
|
||||||
|
internal readonly long MutationRejectedCount;
|
||||||
internal readonly int LastOperationFrame;
|
internal readonly int LastOperationFrame;
|
||||||
internal readonly long LastOperationTicksUtc;
|
internal readonly long LastOperationTicksUtc;
|
||||||
|
|
||||||
@ -35,11 +39,14 @@ namespace AlicizaX
|
|||||||
int subscriberCount,
|
int subscriberCount,
|
||||||
int peakSubscriberCount,
|
int peakSubscriberCount,
|
||||||
int capacity,
|
int capacity,
|
||||||
|
int valueSubscriberCount,
|
||||||
|
int inSubscriberCount,
|
||||||
long publishCount,
|
long publishCount,
|
||||||
long subscribeCount,
|
long subscribeCount,
|
||||||
long unsubscribeCount,
|
long unsubscribeCount,
|
||||||
int resizeCount,
|
int resizeCount,
|
||||||
int clearCount,
|
int clearCount,
|
||||||
|
long mutationRejectedCount,
|
||||||
int lastOperationFrame,
|
int lastOperationFrame,
|
||||||
long lastOperationTicksUtc)
|
long lastOperationTicksUtc)
|
||||||
{
|
{
|
||||||
@ -48,11 +55,14 @@ namespace AlicizaX
|
|||||||
SubscriberCount = subscriberCount;
|
SubscriberCount = subscriberCount;
|
||||||
PeakSubscriberCount = peakSubscriberCount;
|
PeakSubscriberCount = peakSubscriberCount;
|
||||||
Capacity = capacity;
|
Capacity = capacity;
|
||||||
|
ValueSubscriberCount = valueSubscriberCount;
|
||||||
|
InSubscriberCount = inSubscriberCount;
|
||||||
PublishCount = publishCount;
|
PublishCount = publishCount;
|
||||||
SubscribeCount = subscribeCount;
|
SubscribeCount = subscribeCount;
|
||||||
UnsubscribeCount = unsubscribeCount;
|
UnsubscribeCount = unsubscribeCount;
|
||||||
ResizeCount = resizeCount;
|
ResizeCount = resizeCount;
|
||||||
ClearCount = clearCount;
|
ClearCount = clearCount;
|
||||||
|
MutationRejectedCount = mutationRejectedCount;
|
||||||
LastOperationFrame = lastOperationFrame;
|
LastOperationFrame = lastOperationFrame;
|
||||||
LastOperationTicksUtc = lastOperationTicksUtc;
|
LastOperationTicksUtc = lastOperationTicksUtc;
|
||||||
}
|
}
|
||||||
@ -68,6 +78,9 @@ namespace AlicizaX
|
|||||||
internal readonly UnityEngine.Object UnityTarget;
|
internal readonly UnityEngine.Object UnityTarget;
|
||||||
internal readonly bool IsStatic;
|
internal readonly bool IsStatic;
|
||||||
internal readonly bool IsUnityObjectDestroyed;
|
internal readonly bool IsUnityObjectDestroyed;
|
||||||
|
internal readonly bool UsesInParameter;
|
||||||
|
internal readonly bool IsCompilerGeneratedTarget;
|
||||||
|
internal readonly bool IsCompilerGeneratedMethod;
|
||||||
|
|
||||||
internal EventDebugSubscriberInfo(
|
internal EventDebugSubscriberInfo(
|
||||||
int handlerIndex,
|
int handlerIndex,
|
||||||
@ -77,7 +90,10 @@ namespace AlicizaX
|
|||||||
string targetTypeName,
|
string targetTypeName,
|
||||||
UnityEngine.Object unityTarget,
|
UnityEngine.Object unityTarget,
|
||||||
bool isStatic,
|
bool isStatic,
|
||||||
bool isUnityObjectDestroyed)
|
bool isUnityObjectDestroyed,
|
||||||
|
bool usesInParameter,
|
||||||
|
bool isCompilerGeneratedTarget,
|
||||||
|
bool isCompilerGeneratedMethod)
|
||||||
{
|
{
|
||||||
HandlerIndex = handlerIndex;
|
HandlerIndex = handlerIndex;
|
||||||
Version = version;
|
Version = version;
|
||||||
@ -87,6 +103,9 @@ namespace AlicizaX
|
|||||||
UnityTarget = unityTarget;
|
UnityTarget = unityTarget;
|
||||||
IsStatic = isStatic;
|
IsStatic = isStatic;
|
||||||
IsUnityObjectDestroyed = isUnityObjectDestroyed;
|
IsUnityObjectDestroyed = isUnityObjectDestroyed;
|
||||||
|
UsesInParameter = usesInParameter;
|
||||||
|
IsCompilerGeneratedTarget = isCompilerGeneratedTarget;
|
||||||
|
IsCompilerGeneratedMethod = isCompilerGeneratedMethod;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -125,6 +144,8 @@ namespace AlicizaX
|
|||||||
internal readonly Type EventType;
|
internal readonly Type EventType;
|
||||||
internal Func<int> SubscriberCountProvider;
|
internal Func<int> SubscriberCountProvider;
|
||||||
internal Func<int> CapacityProvider;
|
internal Func<int> CapacityProvider;
|
||||||
|
internal Func<int> ValueSubscriberCountProvider;
|
||||||
|
internal Func<int> InSubscriberCountProvider;
|
||||||
internal Func<EventDebugSubscriberInfo[]> SubscribersProvider;
|
internal Func<EventDebugSubscriberInfo[]> SubscribersProvider;
|
||||||
|
|
||||||
internal int PeakSubscriberCount;
|
internal int PeakSubscriberCount;
|
||||||
@ -133,6 +154,7 @@ namespace AlicizaX
|
|||||||
internal long UnsubscribeCount;
|
internal long UnsubscribeCount;
|
||||||
internal int ResizeCount;
|
internal int ResizeCount;
|
||||||
internal int ClearCount;
|
internal int ClearCount;
|
||||||
|
internal long MutationRejectedCount;
|
||||||
internal int LastOperationFrame;
|
internal int LastOperationFrame;
|
||||||
internal long LastOperationTicksUtc;
|
internal long LastOperationTicksUtc;
|
||||||
|
|
||||||
@ -144,13 +166,15 @@ namespace AlicizaX
|
|||||||
|
|
||||||
private static readonly Dictionary<Type, State> _states = new();
|
private static readonly Dictionary<Type, State> _states = new();
|
||||||
private static readonly List<Type> _registrationOrder = new();
|
private static readonly List<Type> _registrationOrder = new();
|
||||||
private static EventDebugOperationRecord[] _history = new EventDebugOperationRecord[HistoryCapacity];
|
private static readonly EventDebugOperationRecord[] _history = new EventDebugOperationRecord[HistoryCapacity];
|
||||||
private static int _historyWriteIndex;
|
private static int _historyWriteIndex;
|
||||||
private static int _historyCount;
|
private static int _historyCount;
|
||||||
|
|
||||||
internal static void RegisterContainer<T>(
|
internal static void RegisterContainer<T>(
|
||||||
Func<int> subscriberCountProvider,
|
Func<int> subscriberCountProvider,
|
||||||
Func<int> capacityProvider,
|
Func<int> capacityProvider,
|
||||||
|
Func<int> valueSubscriberCountProvider,
|
||||||
|
Func<int> inSubscriberCountProvider,
|
||||||
Func<EventDebugSubscriberInfo[]> subscribersProvider)
|
Func<EventDebugSubscriberInfo[]> subscribersProvider)
|
||||||
where T : struct, IEventArgs
|
where T : struct, IEventArgs
|
||||||
{
|
{
|
||||||
@ -164,6 +188,8 @@ namespace AlicizaX
|
|||||||
|
|
||||||
state.SubscriberCountProvider = subscriberCountProvider;
|
state.SubscriberCountProvider = subscriberCountProvider;
|
||||||
state.CapacityProvider = capacityProvider;
|
state.CapacityProvider = capacityProvider;
|
||||||
|
state.ValueSubscriberCountProvider = valueSubscriberCountProvider;
|
||||||
|
state.InSubscriberCountProvider = inSubscriberCountProvider;
|
||||||
state.SubscribersProvider = subscribersProvider;
|
state.SubscribersProvider = subscribersProvider;
|
||||||
state.PeakSubscriberCount = Math.Max(state.PeakSubscriberCount, subscriberCountProvider());
|
state.PeakSubscriberCount = Math.Max(state.PeakSubscriberCount, subscriberCountProvider());
|
||||||
}
|
}
|
||||||
@ -204,6 +230,13 @@ namespace AlicizaX
|
|||||||
MarkOperation(state, EventDebugOperationKind.Clear, subscriberCount, capacity);
|
MarkOperation(state, EventDebugOperationKind.Clear, subscriberCount, capacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal static void RecordMutationRejected<T>(int subscriberCount, int capacity) where T : struct, IEventArgs
|
||||||
|
{
|
||||||
|
State state = GetState<T>();
|
||||||
|
state.MutationRejectedCount++;
|
||||||
|
MarkOperation(state, EventDebugOperationKind.MutationRejected, subscriberCount, capacity);
|
||||||
|
}
|
||||||
|
|
||||||
internal static EventDebugSummary[] GetSummaries()
|
internal static EventDebugSummary[] GetSummaries()
|
||||||
{
|
{
|
||||||
int count = _registrationOrder.Count;
|
int count = _registrationOrder.Count;
|
||||||
@ -253,6 +286,7 @@ namespace AlicizaX
|
|||||||
state.UnsubscribeCount = 0;
|
state.UnsubscribeCount = 0;
|
||||||
state.ResizeCount = 0;
|
state.ResizeCount = 0;
|
||||||
state.ClearCount = 0;
|
state.ClearCount = 0;
|
||||||
|
state.MutationRejectedCount = 0;
|
||||||
state.LastOperationFrame = 0;
|
state.LastOperationFrame = 0;
|
||||||
state.LastOperationTicksUtc = 0;
|
state.LastOperationTicksUtc = 0;
|
||||||
}
|
}
|
||||||
@ -276,6 +310,8 @@ namespace AlicizaX
|
|||||||
{
|
{
|
||||||
int subscriberCount = state.SubscriberCountProvider?.Invoke() ?? 0;
|
int subscriberCount = state.SubscriberCountProvider?.Invoke() ?? 0;
|
||||||
int capacity = state.CapacityProvider?.Invoke() ?? 0;
|
int capacity = state.CapacityProvider?.Invoke() ?? 0;
|
||||||
|
int valueSubscriberCount = state.ValueSubscriberCountProvider?.Invoke() ?? 0;
|
||||||
|
int inSubscriberCount = state.InSubscriberCountProvider?.Invoke() ?? 0;
|
||||||
|
|
||||||
return new EventDebugSummary(
|
return new EventDebugSummary(
|
||||||
state.EventType,
|
state.EventType,
|
||||||
@ -283,11 +319,14 @@ namespace AlicizaX
|
|||||||
subscriberCount,
|
subscriberCount,
|
||||||
state.PeakSubscriberCount,
|
state.PeakSubscriberCount,
|
||||||
capacity,
|
capacity,
|
||||||
|
valueSubscriberCount,
|
||||||
|
inSubscriberCount,
|
||||||
state.PublishCount,
|
state.PublishCount,
|
||||||
state.SubscribeCount,
|
state.SubscribeCount,
|
||||||
state.UnsubscribeCount,
|
state.UnsubscribeCount,
|
||||||
state.ResizeCount,
|
state.ResizeCount,
|
||||||
state.ClearCount,
|
state.ClearCount,
|
||||||
|
state.MutationRejectedCount,
|
||||||
state.LastOperationFrame,
|
state.LastOperationFrame,
|
||||||
state.LastOperationTicksUtc);
|
state.LastOperationTicksUtc);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,3 +1,11 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: e6f1e983f1df4d6cb307f1c0ab0af6b3
|
guid: e6f1e983f1df4d6cb307f1c0ab0af6b3
|
||||||
timeCreated: 1774080000
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
|
|||||||
@ -4,6 +4,8 @@ using Unity.IL2CPP.CompilerServices;
|
|||||||
|
|
||||||
namespace AlicizaX
|
namespace AlicizaX
|
||||||
{
|
{
|
||||||
|
public delegate void InEventHandler<T>(in T evt) where T : struct, IEventArgs;
|
||||||
|
|
||||||
public interface IEventArgs { }
|
public interface IEventArgs { }
|
||||||
|
|
||||||
public static class EventInitialSize<T> where T : struct, IEventArgs
|
public static class EventInitialSize<T> where T : struct, IEventArgs
|
||||||
|
|||||||
@ -23,6 +23,16 @@ namespace AlicizaX
|
|||||||
_eventHandles.Add(handle);
|
_eventHandles.Add(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Il2CppSetOption(Option.NullChecks, false)]
|
||||||
|
[Il2CppSetOption(Option.DivideByZeroChecks, false)]
|
||||||
|
[Il2CppSetOption(Option.ArrayBoundsChecks, false)]
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public void AddUIEvent<T>(InEventHandler<T> handler) where T : struct, IEventArgs
|
||||||
|
{
|
||||||
|
EventRuntimeHandle handle = EventContainer<T>.Subscribe(handler);
|
||||||
|
_eventHandles.Add(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public void Clear()
|
public void Clear()
|
||||||
{
|
{
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user