using System; using System.Collections.Generic; using System.Runtime.CompilerServices; using AlicizaX; using Cysharp.Threading.Tasks; namespace AlicizaX.UI.Runtime { readonly struct LayerData { public readonly List OrderList; // 维护插入顺序 public readonly HashSet HandleSet; // O(1)存在性检查 public readonly Dictionary IndexMap; // O(1)索引查找 public LayerData(int initialCapacity) { OrderList = new List(initialCapacity); HandleSet = new HashSet(); IndexMap = new Dictionary(initialCapacity); } } internal sealed partial class UIModule { private readonly LayerData[] _openUI = new LayerData[(int)UILayer.All]; private async UniTask ShowUIImplAsync(UIMetadata metaInfo, params object[] userDatas) { CreateMetaUI(metaInfo); await UIHolderFactory.CreateUIResourceAsync(metaInfo, UICacheLayer); FinalizeShow(metaInfo, userDatas); UpdateVisualState(metaInfo).Forget(); return metaInfo.View; } private UIBase ShowUIImplSync(UIMetadata metaInfo, params object[] userDatas) { CreateMetaUI(metaInfo); UIHolderFactory.CreateUIResourceSync(metaInfo, UICacheLayer); FinalizeShow(metaInfo, userDatas); UpdateVisualState(metaInfo).Forget(); return metaInfo.View; } private async UniTask CloseUIImpl(UIMetadata meta, bool force) { if (meta.State == UIState.Uninitialized || meta.State == UIState.CreatedUI) { return; } await meta.View.InternalClose(); Pop(meta); SortWindowVisible(meta.MetaInfo.UILayer); SortWindowDepth(meta.MetaInfo.UILayer); CacheWindow(meta, force); } private UIBase GetUIImpl(UIMetadata meta) { return meta.View; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private void CreateMetaUI(UIMetadata meta) { if (meta.State == UIState.Uninitialized) meta.CreateUI(); } private void FinalizeShow(UIMetadata meta, object[] userDatas) { if (meta.InCache) { RemoveFromCache(meta.MetaInfo.RuntimeTypeHandle); Push(meta); } else { switch (meta.State) { case UIState.Loaded: Push(meta); break; case UIState.Opened: MoveToTop(meta); break; } } meta.View.RefreshParams(userDatas); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private void Push(UIMetadata meta) { ref var layer = ref _openUI[meta.MetaInfo.UILayer]; if (layer.HandleSet.Add(meta.MetaInfo.RuntimeTypeHandle)) { int index = layer.OrderList.Count; layer.OrderList.Add(meta); layer.IndexMap[meta.MetaInfo.RuntimeTypeHandle] = index; UpdateLayerParent(meta); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] private void Pop(UIMetadata meta) { ref var layer = ref _openUI[meta.MetaInfo.UILayer]; if (layer.HandleSet.Remove(meta.MetaInfo.RuntimeTypeHandle)) { if (layer.IndexMap.TryGetValue(meta.MetaInfo.RuntimeTypeHandle, out int index)) { layer.OrderList.RemoveAt(index); layer.IndexMap.Remove(meta.MetaInfo.RuntimeTypeHandle); // Update indices for all elements after the removed one for (int i = index; i < layer.OrderList.Count; i++) { var m = layer.OrderList[i]; layer.IndexMap[m.MetaInfo.RuntimeTypeHandle] = i; } } } } [MethodImpl(MethodImplOptions.AggressiveInlining)] private void UpdateLayerParent(UIMetadata meta) { if (meta.View?.Holder != null && meta.View.Holder.IsValid()) { var layerRect = GetLayerRect(meta.MetaInfo.UILayer); meta.View.Holder.transform.SetParent(layerRect); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] private void MoveToTop(UIMetadata meta) { ref var layer = ref _openUI[meta.MetaInfo.UILayer]; int lastIdx = layer.OrderList.Count - 1; // O(1) lookup instead of O(n) IndexOf if (!layer.IndexMap.TryGetValue(meta.MetaInfo.RuntimeTypeHandle, out int currentIdx)) return; if (currentIdx != lastIdx && currentIdx >= 0) { layer.OrderList.RemoveAt(currentIdx); layer.OrderList.Add(meta); // Update indices for shifted elements for (int i = currentIdx; i < lastIdx; i++) { var m = layer.OrderList[i]; layer.IndexMap[m.MetaInfo.RuntimeTypeHandle] = i; } // Update moved element's index layer.IndexMap[meta.MetaInfo.RuntimeTypeHandle] = lastIdx; // Only update depth for affected windows (from currentIdx onwards) SortWindowDepth(meta.MetaInfo.UILayer, currentIdx); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] private async UniTask UpdateVisualState(UIMetadata meta) { SortWindowVisible(meta.MetaInfo.UILayer); SortWindowDepth(meta.MetaInfo.UILayer); if (meta.State == UIState.Loaded) { await meta.View.InternalInitlized(); } await meta.View.InternalOpen(); } private void SortWindowVisible(int layer) { var list = _openUI[layer].OrderList; int count = list.Count; // Find topmost fullscreen window (early exit optimization) int fullscreenIdx = -1; for (int i = count - 1; i >= 0; i--) { var meta = list[i]; if (meta.MetaInfo.FullScreen && meta.State == UIState.Opened) { fullscreenIdx = i; break; // Early exit - found topmost fullscreen } } // Set visibility based on fullscreen index if (fullscreenIdx == -1) { // No fullscreen window, all visible for (int i = 0; i < count; i++) { list[i].View.Visible = true; } } else { // Hide windows below fullscreen, show from fullscreen onwards for (int i = 0; i < count; i++) { list[i].View.Visible = (i >= fullscreenIdx); } } } private void SortWindowDepth(int layer, int startIndex = 0) { var list = _openUI[layer].OrderList; int baseDepth = layer * LAYER_DEEP; // Only update from startIndex onwards (optimization for partial updates) for (int i = startIndex; i < list.Count; i++) { int newDepth = baseDepth + i * WINDOW_DEEP; // Only set if changed to avoid unnecessary Canvas updates if (list[i].View.Depth != newDepth) { list[i].View.Depth = newDepth; } } } } }