164 lines
5.5 KiB
C#
164 lines
5.5 KiB
C#
using System;
|
|
using System.Runtime.CompilerServices;
|
|
using System.Runtime.InteropServices;
|
|
using Unity.IL2CPP.CompilerServices;
|
|
using UnityEngine;
|
|
|
|
namespace AlicizaX
|
|
{
|
|
[Il2CppSetOption(Option.NullChecks, false)]
|
|
[Il2CppSetOption(Option.DivideByZeroChecks, false)]
|
|
[Il2CppSetOption(Option.ArrayBoundsChecks, false)]
|
|
public static class EventContainer<TPayload> where TPayload : struct, IEventArgs
|
|
{
|
|
private static readonly int InitialSize = EventInitialSize<TPayload>.Size;
|
|
private static Handler[] _handlers = new Handler[InitialSize];
|
|
private static int[] _freeSlots = new int[InitialSize];
|
|
private static int _freeCount = InitialSize;
|
|
private static int[] _activeIndices = new int[InitialSize];
|
|
private static int _activeCount;
|
|
private static int _version;
|
|
|
|
#if Event_StrickCheck
|
|
private static System.Collections.Generic.HashSet<Action<TPayload>> _activeHandlers = new();
|
|
#endif
|
|
|
|
static EventContainer()
|
|
{
|
|
Debug.Log(InitialSize);
|
|
for (int i = 0; i < InitialSize; i++)
|
|
{
|
|
_freeSlots[i] = i;
|
|
}
|
|
}
|
|
|
|
[Il2CppSetOption(Option.NullChecks, false)]
|
|
[Il2CppSetOption(Option.DivideByZeroChecks, false)]
|
|
[Il2CppSetOption(Option.ArrayBoundsChecks, false)]
|
|
[StructLayout(LayoutKind.Sequential, Pack = 4)]
|
|
private struct Handler
|
|
{
|
|
public Action<TPayload> Callback;
|
|
public int Version;
|
|
public int ActiveSlot;
|
|
}
|
|
|
|
[Il2CppSetOption(Option.NullChecks, false)]
|
|
[Il2CppSetOption(Option.DivideByZeroChecks, false)]
|
|
[Il2CppSetOption(Option.ArrayBoundsChecks, false)]
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static EventRuntimeHandle Subscribe(Action<TPayload> callback)
|
|
{
|
|
#if Event_StrickCheck
|
|
if (_activeHandlers.Contains(callback))
|
|
{
|
|
Log.Warning($"重复订阅事件处理程序: {callback.Method.Name}");
|
|
return default;
|
|
}
|
|
else
|
|
{
|
|
_activeHandlers.Add(callback);
|
|
}
|
|
#endif
|
|
|
|
int handlerIndex = GetFreeSlot();
|
|
if (_activeCount >= _activeIndices.Length)
|
|
{
|
|
Array.Resize(ref _activeIndices, _activeIndices.Length * 2);
|
|
}
|
|
|
|
int activeIndex = _activeCount++;
|
|
_activeIndices[activeIndex] = handlerIndex;
|
|
|
|
int version = ++_version;
|
|
_handlers[handlerIndex] = new Handler
|
|
{
|
|
Callback = callback,
|
|
Version = version,
|
|
ActiveSlot = activeIndex
|
|
};
|
|
|
|
return new EventRuntimeHandle(Unsubscribe, handlerIndex, version);
|
|
}
|
|
|
|
[Il2CppSetOption(Option.NullChecks, false)]
|
|
[Il2CppSetOption(Option.DivideByZeroChecks, false)]
|
|
[Il2CppSetOption(Option.ArrayBoundsChecks, false)]
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
private static int GetFreeSlot()
|
|
{
|
|
if (_freeCount > 0) return _freeSlots[--_freeCount];
|
|
|
|
int oldLen = _handlers.Length;
|
|
int newSize = oldLen == 0 ? 64 : oldLen * 2;
|
|
Array.Resize(ref _handlers, newSize);
|
|
Array.Resize(ref _freeSlots, newSize);
|
|
|
|
for (int i = newSize - 1; i >= oldLen; i--)
|
|
{
|
|
_freeSlots[_freeCount++] = i;
|
|
}
|
|
|
|
return _freeSlots[--_freeCount];
|
|
}
|
|
|
|
[Il2CppSetOption(Option.NullChecks, false)]
|
|
[Il2CppSetOption(Option.DivideByZeroChecks, false)]
|
|
[Il2CppSetOption(Option.ArrayBoundsChecks, false)]
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
private static void Unsubscribe(int handlerIndex, int version)
|
|
{
|
|
ref Handler handler = ref _handlers[handlerIndex];
|
|
if (handler.Version != version) return;
|
|
|
|
int lastActiveIndex = --_activeCount;
|
|
int lastHandlerIndex = _activeIndices[lastActiveIndex];
|
|
int currentActiveIndex = handler.ActiveSlot;
|
|
|
|
_activeIndices[currentActiveIndex] = lastHandlerIndex;
|
|
_handlers[lastHandlerIndex].ActiveSlot = currentActiveIndex;
|
|
|
|
#if Event_StrickCheck
|
|
_activeHandlers.Remove(handler.Callback);
|
|
#endif
|
|
|
|
handler.Callback = null;
|
|
handler.Version = 0;
|
|
|
|
if (_freeCount >= _freeSlots.Length)
|
|
{
|
|
Array.Resize(ref _freeSlots, _freeSlots.Length * 2);
|
|
}
|
|
|
|
_freeSlots[_freeCount++] = handlerIndex;
|
|
|
|
}
|
|
|
|
|
|
[Il2CppSetOption(Option.NullChecks, false)]
|
|
[Il2CppSetOption(Option.DivideByZeroChecks, false)]
|
|
[Il2CppSetOption(Option.ArrayBoundsChecks, false)]
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static void Publish(in TPayload payload)
|
|
{
|
|
int count = _activeCount;
|
|
int[] indices = _activeIndices;
|
|
Handler[] handlers = _handlers;
|
|
|
|
int i = 0;
|
|
for (; i <= count - 4; i += 4)
|
|
{
|
|
handlers[indices[i]].Callback(payload);
|
|
handlers[indices[i + 1]].Callback(payload);
|
|
handlers[indices[i + 2]].Callback(payload);
|
|
handlers[indices[i + 3]].Callback(payload);
|
|
}
|
|
|
|
for (; i < count; i++)
|
|
{
|
|
handlers[indices[i]].Callback(payload);
|
|
}
|
|
}
|
|
}
|
|
}
|