This commit is contained in:
陈思海 2026-03-16 20:52:55 +08:00
parent a99b71b049
commit c692b47a62
5 changed files with 9 additions and 45 deletions

View File

@ -26,13 +26,13 @@ namespace AlicizaX
public bool IsRunning; public bool IsRunning;
public bool IsUnscaled; public bool IsUnscaled;
public bool IsActive; public bool IsActive;
public byte HandlerType; // 0=Handler, 1=NoArgs, 2=Generic public byte HandlerType;
public object[] Args; public object[] Args;
public object GenericArg; public object GenericArg;
// 优化1: 添加层级信息,用于精确定位
public int Level; // 当前所在的时间轮层级 public int Level;
public int SlotIndex; public int SlotIndex;
public int NextTimerIndex; public int NextTimerIndex;
public int PrevTimerIndex; public int PrevTimerIndex;
@ -68,7 +68,6 @@ namespace AlicizaX
private int[] _freeIndices; private int[] _freeIndices;
private int _freeCount; private int _freeCount;
// 优化2: 延迟删除队列,避免在遍历时修改链表
private int[] _pendingRemoveTimers; private int[] _pendingRemoveTimers;
private int _pendingRemoveCount; private int _pendingRemoveCount;
@ -137,7 +136,6 @@ namespace AlicizaX
slotIndex = (_levels[2].CurrentSlot + level2Slots) % SLOT_COUNT_LEVEL2; slotIndex = (_levels[2].CurrentSlot + level2Slots) % SLOT_COUNT_LEVEL2;
} }
// 优化3: 记录层级信息
timer.Level = level; timer.Level = level;
timer.SlotIndex = slotIndex; timer.SlotIndex = slotIndex;
timer.NextTimerIndex = _levels[level].SlotHeads[slotIndex]; timer.NextTimerIndex = _levels[level].SlotHeads[slotIndex];
@ -183,30 +181,26 @@ namespace AlicizaX
wheelLevel.CurrentSlot = (wheelLevel.CurrentSlot + 1) % wheelLevel.SlotCount; wheelLevel.CurrentSlot = (wheelLevel.CurrentSlot + 1) % wheelLevel.SlotCount;
int currentHead = wheelLevel.SlotHeads[wheelLevel.CurrentSlot]; int currentHead = wheelLevel.SlotHeads[wheelLevel.CurrentSlot];
wheelLevel.SlotHeads[wheelLevel.CurrentSlot] = -1; // 清空槽 wheelLevel.SlotHeads[wheelLevel.CurrentSlot] = -1;
// 优化4: 遍历时先断开链表,避免在回调中修改导致问题
int currentIndex = currentHead; int currentIndex = currentHead;
while (currentIndex != -1) while (currentIndex != -1)
{ {
ref TimerInfo timer = ref pool[currentIndex]; ref TimerInfo timer = ref pool[currentIndex];
int nextIndex = timer.NextTimerIndex; int nextIndex = timer.NextTimerIndex;
// 断开链表连接
timer.NextTimerIndex = -1; timer.NextTimerIndex = -1;
timer.PrevTimerIndex = -1; timer.PrevTimerIndex = -1;
timer.Level = -1; // 标记为不在时间轮中 timer.Level = -1;
if (timer.IsActive && timer.IsRunning) if (timer.IsActive && timer.IsRunning)
{ {
if (level == 0) if (level == 0)
{ {
// Level 0 直接触发
processTimer(currentIndex); processTimer(currentIndex);
} }
else else
{ {
// 高层级降级到低层级
AddTimer(currentIndex, pool, _currentTime); AddTimer(currentIndex, pool, _currentTime);
} }
} }
@ -215,7 +209,6 @@ namespace AlicizaX
} }
} }
// 优化5: 安全的移除方法,检查边界
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void RemoveTimer(int poolIndex, TimerInfo[] pool) public void RemoveTimer(int poolIndex, TimerInfo[] pool)
{ {
@ -224,18 +217,15 @@ namespace AlicizaX
ref TimerInfo timer = ref pool[poolIndex]; ref TimerInfo timer = ref pool[poolIndex];
// 优化6: 如果已经不在时间轮中,直接返回
if (timer.Level < 0 || timer.Level >= _levels.Length) if (timer.Level < 0 || timer.Level >= _levels.Length)
return; return;
int level = timer.Level; int level = timer.Level;
int slotIndex = timer.SlotIndex; int slotIndex = timer.SlotIndex;
// 边界检查
if (slotIndex < 0 || slotIndex >= _levels[level].SlotCount) if (slotIndex < 0 || slotIndex >= _levels[level].SlotCount)
return; return;
// 从链表中移除
if (timer.PrevTimerIndex != -1) if (timer.PrevTimerIndex != -1)
{ {
if (timer.PrevTimerIndex < pool.Length) if (timer.PrevTimerIndex < pool.Length)
@ -245,7 +235,6 @@ namespace AlicizaX
} }
else else
{ {
// 是头节点
_levels[level].SlotHeads[slotIndex] = timer.NextTimerIndex; _levels[level].SlotHeads[slotIndex] = timer.NextTimerIndex;
} }
@ -257,7 +246,6 @@ namespace AlicizaX
} }
} }
// 清除链表信息
timer.Level = -1; timer.Level = -1;
timer.SlotIndex = -1; timer.SlotIndex = -1;
timer.NextTimerIndex = -1; timer.NextTimerIndex = -1;
@ -446,11 +434,9 @@ namespace AlicizaX
ref TimerInfo timer = ref _timerPool[poolIndex]; ref TimerInfo timer = ref _timerPool[poolIndex];
// 先从时间轮中移除
HierarchicalTimeWheel targetWheel = timer.IsUnscaled ? _unscaledTimeWheel : _scaledTimeWheel; HierarchicalTimeWheel targetWheel = timer.IsUnscaled ? _unscaledTimeWheel : _scaledTimeWheel;
targetWheel.RemoveTimer(poolIndex, _timerPool); targetWheel.RemoveTimer(poolIndex, _timerPool);
// 重新计算触发时间并添加
timer.TriggerTime = (timer.IsUnscaled ? Time.unscaledTime : Time.time) + timer.Interval; timer.TriggerTime = (timer.IsUnscaled ? Time.unscaledTime : Time.time) + timer.Interval;
targetWheel.AddTimer(poolIndex, _timerPool, timer.IsUnscaled ? Time.unscaledTime : Time.time); targetWheel.AddTimer(poolIndex, _timerPool, timer.IsUnscaled ? Time.unscaledTime : Time.time);
} }
@ -464,7 +450,6 @@ namespace AlicizaX
ref TimerInfo timer = ref _timerPool[poolIndex]; ref TimerInfo timer = ref _timerPool[poolIndex];
timer.IsActive = false; timer.IsActive = false;
// 优化7: 只有在时间轮中时才移除
if (timer.Level >= 0) if (timer.Level >= 0)
{ {
HierarchicalTimeWheel targetWheel = timer.IsUnscaled ? _unscaledTimeWheel : _scaledTimeWheel; HierarchicalTimeWheel targetWheel = timer.IsUnscaled ? _unscaledTimeWheel : _scaledTimeWheel;
@ -507,7 +492,6 @@ namespace AlicizaX
_scaledTimeWheel.Advance(Time.time, _timerPool, ProcessTimer); _scaledTimeWheel.Advance(Time.time, _timerPool, ProcessTimer);
_unscaledTimeWheel.Advance(Time.unscaledTime, _timerPool, ProcessTimer); _unscaledTimeWheel.Advance(Time.unscaledTime, _timerPool, ProcessTimer);
// 优化8: 处理延迟删除队列
ProcessPendingRemovals(); ProcessPendingRemovals();
} }
@ -541,7 +525,6 @@ namespace AlicizaX
Log.Error($"Timer callback error: {e}"); Log.Error($"Timer callback error: {e}");
} }
// 优化9: 回调后检查是否仍然有效
if (!timer.IsActive) if (!timer.IsActive)
return; return;
@ -553,7 +536,6 @@ namespace AlicizaX
} }
else else
{ {
// 优化10: 延迟删除,避免在遍历时修改
AddPendingRemoval(timer.TimerId); AddPendingRemoval(timer.TimerId);
} }
} }

View File

@ -144,7 +144,6 @@ namespace AlicizaX.UI.Runtime
ref var layer = ref _openUI[meta.MetaInfo.UILayer]; ref var layer = ref _openUI[meta.MetaInfo.UILayer];
int lastIdx = layer.OrderList.Count - 1; int lastIdx = layer.OrderList.Count - 1;
// O(1) lookup instead of O(n) IndexOf
if (!layer.IndexMap.TryGetValue(meta.MetaInfo.RuntimeTypeHandle, out int currentIdx)) if (!layer.IndexMap.TryGetValue(meta.MetaInfo.RuntimeTypeHandle, out int currentIdx))
return; return;
@ -153,17 +152,14 @@ namespace AlicizaX.UI.Runtime
layer.OrderList.RemoveAt(currentIdx); layer.OrderList.RemoveAt(currentIdx);
layer.OrderList.Add(meta); layer.OrderList.Add(meta);
// Update indices for shifted elements
for (int i = currentIdx; i < lastIdx; i++) for (int i = currentIdx; i < lastIdx; i++)
{ {
var m = layer.OrderList[i]; var m = layer.OrderList[i];
layer.IndexMap[m.MetaInfo.RuntimeTypeHandle] = i; layer.IndexMap[m.MetaInfo.RuntimeTypeHandle] = i;
} }
// Update moved element's index
layer.IndexMap[meta.MetaInfo.RuntimeTypeHandle] = lastIdx; layer.IndexMap[meta.MetaInfo.RuntimeTypeHandle] = lastIdx;
// Only update depth for affected windows (from currentIdx onwards)
SortWindowDepth(meta.MetaInfo.UILayer, currentIdx); SortWindowDepth(meta.MetaInfo.UILayer, currentIdx);
} }
} }
@ -186,7 +182,6 @@ namespace AlicizaX.UI.Runtime
var list = _openUI[layer].OrderList; var list = _openUI[layer].OrderList;
int count = list.Count; int count = list.Count;
// Find topmost fullscreen window (early exit optimization)
int fullscreenIdx = -1; int fullscreenIdx = -1;
for (int i = count - 1; i >= 0; i--) for (int i = count - 1; i >= 0; i--)
{ {
@ -194,14 +189,12 @@ namespace AlicizaX.UI.Runtime
if (meta.MetaInfo.FullScreen && meta.State == UIState.Opened) if (meta.MetaInfo.FullScreen && meta.State == UIState.Opened)
{ {
fullscreenIdx = i; fullscreenIdx = i;
break; // Early exit - found topmost fullscreen break;
} }
} }
// Set visibility based on fullscreen index
if (fullscreenIdx == -1) if (fullscreenIdx == -1)
{ {
// No fullscreen window, all visible
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
list[i].View.Visible = true; list[i].View.Visible = true;
@ -209,7 +202,6 @@ namespace AlicizaX.UI.Runtime
} }
else else
{ {
// Hide windows below fullscreen, show from fullscreen onwards
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
list[i].View.Visible = (i >= fullscreenIdx); list[i].View.Visible = (i >= fullscreenIdx);
@ -222,12 +214,10 @@ namespace AlicizaX.UI.Runtime
var list = _openUI[layer].OrderList; var list = _openUI[layer].OrderList;
int baseDepth = layer * LAYER_DEEP; int baseDepth = layer * LAYER_DEEP;
// Only update from startIndex onwards (optimization for partial updates)
for (int i = startIndex; i < list.Count; i++) for (int i = startIndex; i < list.Count; i++)
{ {
int newDepth = baseDepth + i * WINDOW_DEEP; int newDepth = baseDepth + i * WINDOW_DEEP;
// Only set if changed to avoid unnecessary Canvas updates
if (list[i].View.Depth != newDepth) if (list[i].View.Depth != newDepth)
{ {
list[i].View.Depth = newDepth; list[i].View.Depth = newDepth;

View File

@ -12,11 +12,10 @@ namespace AlicizaX.UI.Runtime
public abstract partial class UIBase public abstract partial class UIBase
{ {
private readonly Dictionary<UIBase, UIMetadata> _children = new(); private readonly Dictionary<UIBase, UIMetadata> _children = new();
private readonly List<UIMetadata> _updateableChildren = new(); // Cache for widgets that need updates private readonly List<UIMetadata> _updateableChildren = new();
private void UpdateChildren() private void UpdateChildren()
{ {
// Use cached list to avoid dictionary enumeration allocation
for (int i = 0; i < _updateableChildren.Count; i++) for (int i = 0; i < _updateableChildren.Count; i++)
{ {
var meta = _updateableChildren[i]; var meta = _updateableChildren[i];
@ -33,7 +32,6 @@ namespace AlicizaX.UI.Runtime
try try
{ {
int i = 0; int i = 0;
// Use struct enumerator to avoid allocation
foreach (var kvp in _children) foreach (var kvp in _children)
{ {
temp[i++] = kvp.Value; temp[i++] = kvp.Value;
@ -56,7 +54,6 @@ namespace AlicizaX.UI.Runtime
private void ChildVisible(bool value) private void ChildVisible(bool value)
{ {
// Use struct enumerator to avoid allocation
foreach (var kvp in _children) foreach (var kvp in _children)
{ {
var view = kvp.Value.View; var view = kvp.Value.View;
@ -164,7 +161,6 @@ namespace AlicizaX.UI.Runtime
return false; return false;
} }
// Add to updateable list if widget needs updates
if (meta.MetaInfo.NeedUpdate) if (meta.MetaInfo.NeedUpdate)
{ {
_updateableChildren.Add(meta); _updateableChildren.Add(meta);
@ -180,7 +176,6 @@ namespace AlicizaX.UI.Runtime
meta.CancelAsyncOperations(); meta.CancelAsyncOperations();
await widget.InternalClose(); await widget.InternalClose();
// Remove from updateable list if present
if (meta.MetaInfo.NeedUpdate) if (meta.MetaInfo.NeedUpdate)
{ {
_updateableChildren.Remove(meta); _updateableChildren.Remove(meta);

View File

@ -233,7 +233,7 @@ namespace AlicizaX.UI.Runtime
internal async UniTask InternalClose(CancellationToken cancellationToken = default) internal async UniTask InternalClose(CancellationToken cancellationToken = default)
{ {
if (_state != UIState.Opened) if (_state != UIState.Opened)
return; // Not open, nothing to close return;
if (!UIStateMachine.ValidateTransition(GetType().Name, _state, UIState.Closed)) if (!UIStateMachine.ValidateTransition(GetType().Name, _state, UIState.Closed))
return; return;

View File

@ -68,10 +68,7 @@ namespace AlicizaX.UI.Runtime
private bool _isAlive = true; private bool _isAlive = true;
/// <summary>
/// Checks if this holder is still valid (not destroyed).
/// Use this instead of null check for better clarity.
/// </summary>
public bool IsValid() public bool IsValid()
{ {
return this != null && _isAlive; return this != null && _isAlive;