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