优化Timer模块
This commit is contained in:
parent
d5518c46b1
commit
d2b3a36da6
@ -8,6 +8,18 @@ namespace AlicizaX
|
||||
{
|
||||
public delegate void TimerHandler(params object[] args);
|
||||
public delegate void TimerHandlerNoArgs();
|
||||
internal delegate void TimerGenericInvoker(Delegate handler, object arg);
|
||||
|
||||
internal static class TimerGenericInvokerCache<T>
|
||||
{
|
||||
public static readonly TimerGenericInvoker Invoke = InvokeGeneric;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static void InvokeGeneric(Delegate handler, object arg)
|
||||
{
|
||||
((Action<T>)handler)?.Invoke((T)arg);
|
||||
}
|
||||
}
|
||||
|
||||
[Il2CppSetOption(Option.NullChecks, false)]
|
||||
[Il2CppSetOption(Option.ArrayBoundsChecks, false)]
|
||||
@ -21,6 +33,7 @@ namespace AlicizaX
|
||||
public TimerHandler Handler;
|
||||
public TimerHandlerNoArgs HandlerNoArgs;
|
||||
public Delegate HandlerGeneric;
|
||||
public TimerGenericInvoker GenericInvoker;
|
||||
|
||||
public bool IsLoop;
|
||||
public bool IsRunning;
|
||||
@ -40,11 +53,19 @@ namespace AlicizaX
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Clear()
|
||||
{
|
||||
TimerId = 0;
|
||||
TriggerTime = 0f;
|
||||
Interval = 0f;
|
||||
Handler = null;
|
||||
HandlerNoArgs = null;
|
||||
HandlerGeneric = null;
|
||||
GenericInvoker = null;
|
||||
IsLoop = false;
|
||||
IsRunning = false;
|
||||
IsUnscaled = false;
|
||||
Args = null;
|
||||
GenericArg = null;
|
||||
HandlerType = 0;
|
||||
IsActive = false;
|
||||
Level = -1;
|
||||
SlotIndex = -1;
|
||||
@ -58,6 +79,8 @@ namespace AlicizaX
|
||||
[Il2CppSetOption(Option.ArrayBoundsChecks, false)]
|
||||
internal sealed class TimerModule : ITimerModule
|
||||
{
|
||||
private const float TimeWheelSlotInterval = 0.001f;
|
||||
|
||||
private int _curTimerId;
|
||||
private HierarchicalTimeWheel _scaledTimeWheel;
|
||||
private HierarchicalTimeWheel _unscaledTimeWheel;
|
||||
@ -76,10 +99,14 @@ namespace AlicizaX
|
||||
private const int SLOT_COUNT_LEVEL0 = 256;
|
||||
private const int SLOT_COUNT_LEVEL1 = 64;
|
||||
private const int SLOT_COUNT_LEVEL2 = 64;
|
||||
private const int SLOT_MASK_LEVEL0 = SLOT_COUNT_LEVEL0 - 1;
|
||||
private const int SLOT_MASK_LEVEL1 = SLOT_COUNT_LEVEL1 - 1;
|
||||
private const int SLOT_MASK_LEVEL2 = SLOT_COUNT_LEVEL2 - 1;
|
||||
|
||||
private readonly float _slotInterval;
|
||||
private readonly TimeWheelLevel[] _levels;
|
||||
private float _currentTime;
|
||||
private bool _isInitialized;
|
||||
|
||||
private class TimeWheelLevel
|
||||
{
|
||||
@ -108,6 +135,8 @@ namespace AlicizaX
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void AddTimer(int poolIndex, TimerInfo[] pool, float currentTime)
|
||||
{
|
||||
EnsureInitialized(currentTime);
|
||||
|
||||
ref TimerInfo timer = ref pool[poolIndex];
|
||||
if (!timer.IsActive) return;
|
||||
|
||||
@ -121,19 +150,19 @@ namespace AlicizaX
|
||||
if (totalSlots < SLOT_COUNT_LEVEL0)
|
||||
{
|
||||
level = 0;
|
||||
slotIndex = (_levels[0].CurrentSlot + totalSlots) % SLOT_COUNT_LEVEL0;
|
||||
slotIndex = (_levels[0].CurrentSlot + totalSlots) & SLOT_MASK_LEVEL0;
|
||||
}
|
||||
else if (totalSlots < SLOT_COUNT_LEVEL0 * SLOT_COUNT_LEVEL1)
|
||||
{
|
||||
level = 1;
|
||||
int level1Slots = totalSlots / SLOT_COUNT_LEVEL0;
|
||||
slotIndex = (_levels[1].CurrentSlot + level1Slots) % SLOT_COUNT_LEVEL1;
|
||||
slotIndex = (_levels[1].CurrentSlot + level1Slots) & SLOT_MASK_LEVEL1;
|
||||
}
|
||||
else
|
||||
{
|
||||
level = 2;
|
||||
int level2Slots = totalSlots / (SLOT_COUNT_LEVEL0 * SLOT_COUNT_LEVEL1);
|
||||
slotIndex = (_levels[2].CurrentSlot + level2Slots) % SLOT_COUNT_LEVEL2;
|
||||
slotIndex = (_levels[2].CurrentSlot + level2Slots) & SLOT_MASK_LEVEL2;
|
||||
}
|
||||
|
||||
timer.Level = level;
|
||||
@ -152,6 +181,8 @@ namespace AlicizaX
|
||||
|
||||
public void Advance(float currentTime, TimerInfo[] pool, Action<int> processTimer)
|
||||
{
|
||||
EnsureInitialized(currentTime);
|
||||
|
||||
float timeDelta = currentTime - _currentTime;
|
||||
if (timeDelta <= 0) return;
|
||||
|
||||
@ -162,23 +193,45 @@ namespace AlicizaX
|
||||
_currentTime += _slotInterval;
|
||||
ProcessLevel(0, pool, processTimer);
|
||||
|
||||
if ((_levels[0].CurrentSlot % SLOT_COUNT_LEVEL0) == 0)
|
||||
if (_levels[0].CurrentSlot == 0)
|
||||
{
|
||||
ProcessLevel(1, pool, processTimer);
|
||||
}
|
||||
|
||||
if ((_levels[0].CurrentSlot % (SLOT_COUNT_LEVEL0 * SLOT_COUNT_LEVEL1)) == 0)
|
||||
if (_levels[1].CurrentSlot == 0)
|
||||
{
|
||||
ProcessLevel(2, pool, processTimer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private void EnsureInitialized(float currentTime)
|
||||
{
|
||||
if (_isInitialized)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_currentTime = currentTime;
|
||||
_isInitialized = true;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private void ProcessLevel(int level, TimerInfo[] pool, Action<int> processTimer)
|
||||
{
|
||||
TimeWheelLevel wheelLevel = _levels[level];
|
||||
wheelLevel.CurrentSlot = (wheelLevel.CurrentSlot + 1) % wheelLevel.SlotCount;
|
||||
if (level == 0)
|
||||
{
|
||||
wheelLevel.CurrentSlot = (wheelLevel.CurrentSlot + 1) & SLOT_MASK_LEVEL0;
|
||||
}
|
||||
else if (level == 1)
|
||||
{
|
||||
wheelLevel.CurrentSlot = (wheelLevel.CurrentSlot + 1) & SLOT_MASK_LEVEL1;
|
||||
}
|
||||
else
|
||||
{
|
||||
wheelLevel.CurrentSlot = (wheelLevel.CurrentSlot + 1) & SLOT_MASK_LEVEL2;
|
||||
}
|
||||
|
||||
int currentHead = wheelLevel.SlotHeads[wheelLevel.CurrentSlot];
|
||||
wheelLevel.SlotHeads[wheelLevel.CurrentSlot] = -1;
|
||||
@ -263,6 +316,8 @@ namespace AlicizaX
|
||||
_pendingRemoveTimers = new int[64];
|
||||
_pendingRemoveCount = 0;
|
||||
|
||||
InitializeTimerIdMapping(_timerIdToPoolIndex, 0);
|
||||
|
||||
for (int i = 0; i < _timerPoolCapacity; i++)
|
||||
{
|
||||
_freeIndices[i] = i;
|
||||
@ -272,8 +327,8 @@ namespace AlicizaX
|
||||
_timerPool[i].SlotIndex = -1;
|
||||
}
|
||||
|
||||
_scaledTimeWheel = new HierarchicalTimeWheel(0.001f);
|
||||
_unscaledTimeWheel = new HierarchicalTimeWheel(0.001f);
|
||||
_scaledTimeWheel = new HierarchicalTimeWheel(TimeWheelSlotInterval);
|
||||
_unscaledTimeWheel = new HierarchicalTimeWheel(TimeWheelSlotInterval);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
@ -285,7 +340,10 @@ namespace AlicizaX
|
||||
timer.TimerId = ++_curTimerId;
|
||||
timer.TriggerTime = (isUnscaled ? Time.unscaledTime : Time.time) + time;
|
||||
timer.Interval = isLoop ? time : 0f;
|
||||
timer.Handler = null;
|
||||
timer.HandlerNoArgs = callback;
|
||||
timer.HandlerGeneric = null;
|
||||
timer.GenericInvoker = null;
|
||||
timer.HandlerType = 1;
|
||||
timer.IsLoop = isLoop;
|
||||
timer.IsRunning = true;
|
||||
@ -311,7 +369,10 @@ namespace AlicizaX
|
||||
timer.TimerId = ++_curTimerId;
|
||||
timer.TriggerTime = (isUnscaled ? Time.unscaledTime : Time.time) + time;
|
||||
timer.Interval = isLoop ? time : 0f;
|
||||
timer.Handler = null;
|
||||
timer.HandlerNoArgs = null;
|
||||
timer.HandlerGeneric = callback;
|
||||
timer.GenericInvoker = TimerGenericInvokerCache<T>.Invoke;
|
||||
timer.GenericArg = arg;
|
||||
timer.HandlerType = 2;
|
||||
timer.IsLoop = isLoop;
|
||||
@ -337,6 +398,9 @@ namespace AlicizaX
|
||||
timer.TriggerTime = (isUnscaled ? Time.unscaledTime : Time.time) + time;
|
||||
timer.Interval = isLoop ? time : 0f;
|
||||
timer.Handler = callback;
|
||||
timer.HandlerNoArgs = null;
|
||||
timer.HandlerGeneric = null;
|
||||
timer.GenericInvoker = null;
|
||||
timer.HandlerType = 0;
|
||||
timer.IsLoop = isLoop;
|
||||
timer.IsRunning = true;
|
||||
@ -383,7 +447,15 @@ namespace AlicizaX
|
||||
{
|
||||
if (timerId >= _timerIdToPoolIndex.Length)
|
||||
{
|
||||
Array.Resize(ref _timerIdToPoolIndex, _timerIdToPoolIndex.Length * 2);
|
||||
int oldLength = _timerIdToPoolIndex.Length;
|
||||
int newLength = oldLength;
|
||||
while (timerId >= newLength)
|
||||
{
|
||||
newLength *= 2;
|
||||
}
|
||||
|
||||
Array.Resize(ref _timerIdToPoolIndex, newLength);
|
||||
InitializeTimerIdMapping(_timerIdToPoolIndex, oldLength);
|
||||
}
|
||||
|
||||
_timerIdToPoolIndex[timerId] = poolIndex;
|
||||
@ -392,7 +464,28 @@ namespace AlicizaX
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private int GetPoolIndex(int timerId)
|
||||
{
|
||||
return timerId > 0 && timerId < _timerIdToPoolIndex.Length ? _timerIdToPoolIndex[timerId] : -1;
|
||||
if (timerId <= 0 || timerId >= _timerIdToPoolIndex.Length)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
int poolIndex = _timerIdToPoolIndex[timerId];
|
||||
if ((uint)poolIndex >= (uint)_timerPool.Length)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
ref TimerInfo timer = ref _timerPool[poolIndex];
|
||||
return timer.IsActive && timer.TimerId == timerId ? poolIndex : -1;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static void InitializeTimerIdMapping(int[] mapping, int startIndex)
|
||||
{
|
||||
for (int i = startIndex; i < mapping.Length; i++)
|
||||
{
|
||||
mapping[i] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
public void Stop(int timerId)
|
||||
@ -465,10 +558,20 @@ namespace AlicizaX
|
||||
{
|
||||
if (_timerPool[i].IsActive)
|
||||
{
|
||||
int timerId = _timerPool[i].TimerId;
|
||||
if (timerId > 0 && timerId < _timerIdToPoolIndex.Length)
|
||||
{
|
||||
_timerIdToPoolIndex[timerId] = -1;
|
||||
}
|
||||
|
||||
_timerPool[i].Clear();
|
||||
_freeIndices[_freeCount++] = i;
|
||||
}
|
||||
}
|
||||
|
||||
_pendingRemoveCount = 0;
|
||||
_scaledTimeWheel = new HierarchicalTimeWheel(TimeWheelSlotInterval);
|
||||
_unscaledTimeWheel = new HierarchicalTimeWheel(TimeWheelSlotInterval);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
@ -476,6 +579,12 @@ namespace AlicizaX
|
||||
{
|
||||
if (poolIndex >= 0 && poolIndex < _timerPool.Length)
|
||||
{
|
||||
int timerId = _timerPool[poolIndex].TimerId;
|
||||
if (timerId > 0 && timerId < _timerIdToPoolIndex.Length && _timerIdToPoolIndex[timerId] == poolIndex)
|
||||
{
|
||||
_timerIdToPoolIndex[timerId] = -1;
|
||||
}
|
||||
|
||||
_timerPool[poolIndex].Clear();
|
||||
|
||||
if (_freeCount >= _freeIndices.Length)
|
||||
@ -516,7 +625,7 @@ namespace AlicizaX
|
||||
timer.HandlerNoArgs?.Invoke();
|
||||
break;
|
||||
case 2: // Generic
|
||||
((dynamic)timer.HandlerGeneric)?.Invoke((dynamic)timer.GenericArg);
|
||||
timer.GenericInvoker?.Invoke(timer.HandlerGeneric, timer.GenericArg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -49,7 +49,7 @@ namespace AlicizaX.UI.Runtime
|
||||
RecoverLayerOptionAll();
|
||||
}
|
||||
|
||||
private void OnBlockCountDown(object[] args)
|
||||
private void OnBlockCountDown()
|
||||
{
|
||||
RecoverLayerOptionAll();
|
||||
}
|
||||
|
||||
@ -42,10 +42,10 @@ namespace AlicizaX.UI.Runtime
|
||||
{
|
||||
timerId = _timerModule.AddTimer(
|
||||
OnTimerDisposeWindow,
|
||||
uiMetadata,
|
||||
uiMetadata.MetaInfo.CacheTime,
|
||||
isLoop: false,
|
||||
isUnscaled: true,
|
||||
uiMetadata
|
||||
isUnscaled: true
|
||||
);
|
||||
|
||||
if (timerId <= 0)
|
||||
@ -58,11 +58,8 @@ namespace AlicizaX.UI.Runtime
|
||||
m_CacheWindow.Add(uiMetadata.MetaInfo.RuntimeTypeHandle, new CacheEntry(uiMetadata, timerId));
|
||||
}
|
||||
|
||||
private void OnTimerDisposeWindow(object[] args)
|
||||
private void OnTimerDisposeWindow(UIMetadata meta)
|
||||
{
|
||||
if (args == null || args.Length == 0) return;
|
||||
|
||||
UIMetadata meta = args[0] as UIMetadata;
|
||||
if (meta != null)
|
||||
{
|
||||
meta.Dispose();
|
||||
|
||||
Loading…
Reference in New Issue
Block a user