From 3362d9456d7286207c8cea7044a354c2b59c809d Mon Sep 17 00:00:00 2001 From: GeWuYou <95328647+GeWuYou@users.noreply.github.com> Date: Tue, 20 Jan 2026 12:27:22 +0800 Subject: [PATCH] =?UTF-8?q?feat(ui):=20=E5=AE=9E=E7=8E=B0UI=E7=BC=93?= =?UTF-8?q?=E5=AD=98=E6=B7=98=E6=B1=B0=E7=AD=96=E7=95=A5=E5=92=8C=E7=A7=BB?= =?UTF-8?q?=E9=99=A4=E5=8A=A8=E7=94=BB=E7=9B=B8=E5=85=B3=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增CacheEvictionPolicy枚举定义LRU和LFU缓存淘汰策略 - 在GodotUiFactory中实现缓存淘汰机制支持LRU/LFU策略 - 将IUiCacheStatistics接口从IUiFactory中分离到独立文件 - 移除UiAnimationPolicy类及相关动画策略参数配置 - 移除GodotUiTransition类中的UI过渡动画实现 - 移除UiTransitionAnimation枚举类型 - 更新UiRouterBase中路由方法移除动画策略参数 - 重构路由守卫注册方法位置优化代码结构 - 更新UiCacheConfig配置类适配新的缓存策略枚举值 -[skip ci] --- .../enums/CacheEvictionPolicy.cs | 17 ++ .../enums/UiTransitionAnimation.cs | 48 ---- .../ui/IUiCacheStatistics.cs | 34 +++ GFramework.Game.Abstractions/ui/IUiFactory.cs | 31 --- GFramework.Game.Abstractions/ui/IUiRouter.cs | 25 +- .../ui/UiAnimationPolicy.cs | 91 ------- .../ui/UiCacheConfig.cs | 35 +-- GFramework.Game/ui/UiRouterBase.cs | 248 +++++++++--------- GFramework.Godot/ui/GodotUiFactory.cs | 32 ++- GFramework.Godot/ui/GodotUiTransition.cs | 171 ------------ 10 files changed, 203 insertions(+), 529 deletions(-) create mode 100644 GFramework.Game.Abstractions/enums/CacheEvictionPolicy.cs delete mode 100644 GFramework.Game.Abstractions/enums/UiTransitionAnimation.cs create mode 100644 GFramework.Game.Abstractions/ui/IUiCacheStatistics.cs delete mode 100644 GFramework.Game.Abstractions/ui/UiAnimationPolicy.cs delete mode 100644 GFramework.Godot/ui/GodotUiTransition.cs diff --git a/GFramework.Game.Abstractions/enums/CacheEvictionPolicy.cs b/GFramework.Game.Abstractions/enums/CacheEvictionPolicy.cs new file mode 100644 index 0000000..481d943 --- /dev/null +++ b/GFramework.Game.Abstractions/enums/CacheEvictionPolicy.cs @@ -0,0 +1,17 @@ +namespace GFramework.Game.Abstractions.enums; + +/// +/// 缓存淘汰策略枚举 +/// +public enum CacheEvictionPolicy +{ + /// + /// 最近最少使用 + /// + Lru, + + /// + /// 最少使用频率 + /// + Lfu, +} diff --git a/GFramework.Game.Abstractions/enums/UiTransitionAnimation.cs b/GFramework.Game.Abstractions/enums/UiTransitionAnimation.cs deleted file mode 100644 index 15d2c08..0000000 --- a/GFramework.Game.Abstractions/enums/UiTransitionAnimation.cs +++ /dev/null @@ -1,48 +0,0 @@ -namespace GFramework.Game.Abstractions.enums; - -/// -/// UI过渡动画类型枚举 -/// 定义UI切换时支持的动画效果 -/// -public enum UiTransitionAnimation -{ - /// - /// 无动画 - /// - None, - - /// - /// 淡入淡出动画 - /// - Fade, - - /// - /// 从右侧滑入 - /// - SlideLeft, - - /// - /// 从左侧滑入 - /// - SlideRight, - - /// - /// 从下方滑入 - /// - SlideUp, - - /// - /// 从上方滑入 - /// - SlideDown, - - /// - /// 缩放动画 - /// - Scale, - - /// - /// 自定义动画(需要提供自定义的 IUiTransition 实现) - /// - Custom -} diff --git a/GFramework.Game.Abstractions/ui/IUiCacheStatistics.cs b/GFramework.Game.Abstractions/ui/IUiCacheStatistics.cs new file mode 100644 index 0000000..54190d3 --- /dev/null +++ b/GFramework.Game.Abstractions/ui/IUiCacheStatistics.cs @@ -0,0 +1,34 @@ +using System; + +namespace GFramework.Game.Abstractions.ui; + +/// +/// UI缓存统计信息接口 +/// +public interface IUiCacheStatistics +{ + /// + /// 缓存总数 + /// + int CacheSize { get; } + + /// + /// 缓存命中次数 + /// + int HitCount { get; } + + /// + /// 缓存未命中次数 + /// + int MissCount { get; } + + /// + /// 命中率 + /// + double HitRate { get; } + + /// + /// 最近访问时间 + /// + DateTime? LastAccessTime { get; } +} \ No newline at end of file diff --git a/GFramework.Game.Abstractions/ui/IUiFactory.cs b/GFramework.Game.Abstractions/ui/IUiFactory.cs index 70bcf56..20753dc 100644 --- a/GFramework.Game.Abstractions/ui/IUiFactory.cs +++ b/GFramework.Game.Abstractions/ui/IUiFactory.cs @@ -4,37 +4,6 @@ using GFramework.Core.Abstractions.utility; namespace GFramework.Game.Abstractions.ui; -/// -/// UI缓存统计信息接口 -/// -public interface IUiCacheStatistics -{ - /// - /// 缓存总数 - /// - int CacheSize { get; } - - /// - /// 缓存命中次数 - /// - int HitCount { get; } - - /// - /// 缓存未命中次数 - /// - int MissCount { get; } - - /// - /// 命中率 - /// - double HitRate { get; } - - /// - /// 最近访问时间 - /// - DateTime? LastAccessTime { get; } -} - /// /// UI工厂接口,用于创建UI页面实例 /// diff --git a/GFramework.Game.Abstractions/ui/IUiRouter.cs b/GFramework.Game.Abstractions/ui/IUiRouter.cs index 08bd15d..5c3c250 100644 --- a/GFramework.Game.Abstractions/ui/IUiRouter.cs +++ b/GFramework.Game.Abstractions/ui/IUiRouter.cs @@ -26,9 +26,8 @@ public interface IUiRouter : ISystem /// 进入界面的参数,可为空 /// 界面切换策略,默认为Exclusive(独占) /// 实例管理策略,默认为Reuse(复用) - /// 动画策略,可为空 void Push(string uiKey, IUiPageEnterParam? param = null, UiTransitionPolicy policy = UiTransitionPolicy.Exclusive, - UiInstancePolicy instancePolicy = UiInstancePolicy.Reuse, UiAnimationPolicy? animationPolicy = null); + UiInstancePolicy instancePolicy = UiInstancePolicy.Reuse); /// @@ -38,9 +37,8 @@ public interface IUiRouter : ISystem /// 已创建的UI页面行为实例 /// 进入界面的参数,可为空 /// 界面切换策略,默认为Exclusive(独占) - /// 动画策略,可为空 void Push(IUiPageBehavior page, IUiPageEnterParam? param = null, - UiTransitionPolicy policy = UiTransitionPolicy.Exclusive, UiAnimationPolicy? animationPolicy = null); + UiTransitionPolicy policy = UiTransitionPolicy.Exclusive); /// @@ -57,14 +55,12 @@ public interface IUiRouter : ISystem /// 弹出页面时的销毁策略,默认为销毁 /// 推入页面时的过渡策略,默认为独占 /// 实例管理策略 - /// 动画策略,可为空 public void Replace( string uiKey, IUiPageEnterParam? param = null, UiPopPolicy popPolicy = UiPopPolicy.Destroy, UiTransitionPolicy pushPolicy = UiTransitionPolicy.Exclusive, - UiInstancePolicy instancePolicy = UiInstancePolicy.Reuse, - UiAnimationPolicy? animationPolicy = null); + UiInstancePolicy instancePolicy = UiInstancePolicy.Reuse); /// /// 替换当前所有页面为已存在的页面(基于实例) @@ -73,13 +69,11 @@ public interface IUiRouter : ISystem /// 页面进入参数,可为空 /// 弹出页面时的销毁策略,默认为销毁 /// 推入页面时的过渡策略,默认为独占 - /// 动画策略,可为空 public void Replace( IUiPageBehavior page, IUiPageEnterParam? param = null, UiPopPolicy popPolicy = UiPopPolicy.Destroy, - UiTransitionPolicy pushPolicy = UiTransitionPolicy.Exclusive, - UiAnimationPolicy? animationPolicy = null); + UiTransitionPolicy pushPolicy = UiTransitionPolicy.Exclusive); /// /// 清空所有UI界面,重置路由状态 /// @@ -129,17 +123,16 @@ public interface IUiRouter : ISystem /// 守卫实例 void AddGuard(IUiRouteGuard guard); + /// + /// 注册路由守卫(泛型方法) + /// + /// 守卫类型,必须实现 IUiRouteGuard 且有无参构造函数 + void AddGuard() where T : IUiRouteGuard, new(); /// /// 移除路由守卫 /// /// 守卫实例 void RemoveGuard(IUiRouteGuard guard); - /// - /// 注册路由守卫(泛型方法) - /// - /// 守卫类型,必须实现 IUiRouteGuard 且有无参构造函数 - void AddGuard() where T : IUiRouteGuard, new(); - #endregion } \ No newline at end of file diff --git a/GFramework.Game.Abstractions/ui/UiAnimationPolicy.cs b/GFramework.Game.Abstractions/ui/UiAnimationPolicy.cs deleted file mode 100644 index 3ce0713..0000000 --- a/GFramework.Game.Abstractions/ui/UiAnimationPolicy.cs +++ /dev/null @@ -1,91 +0,0 @@ -using GFramework.Game.Abstractions.enums; - -namespace GFramework.Game.Abstractions.ui; - -/// -/// UI动画策略配置 -/// 用于配置UI过渡动画的行为 -/// -public class UiAnimationPolicy -{ - /// - /// 动画类型 - /// - public UiTransitionAnimation Animation { get; set; } = UiTransitionAnimation.None; - - /// - /// 动画持续时间(秒) - /// - public float Duration { get; set; } = 0.3f; - - /// - /// 是否阻塞UI切换(等待动画完成) - /// - public bool BlockTransition { get; set; } = false; - - /// - /// 自定义动画实现(仅当 Animation 为 Custom 时使用) - /// - public IUiTransition? CustomTransition { get; set; } - - /// - /// 缓动函数(可选,用于调整动画曲线) - /// - public EasingFunction Easing { get; set; } = EasingFunction.EaseInOut; - - /// - /// 创建默认策略(无动画) - /// - public static UiAnimationPolicy None => new UiAnimationPolicy { Animation = UiTransitionAnimation.None }; - - /// - /// 创建淡入淡出策略 - /// - /// 持续时间 - /// 是否阻塞 - public static UiAnimationPolicy Fade(float duration = 0.3f, bool block = false) - => new UiAnimationPolicy { Animation = UiTransitionAnimation.Fade, Duration = duration, BlockTransition = block }; - - /// - /// 创建滑入策略 - /// - /// 滑动方向 - /// 持续时间 - /// 是否阻塞 - public static UiAnimationPolicy Slide(UiTransitionAnimation direction, float duration = 0.3f, bool block = false) - => new UiAnimationPolicy { Animation = direction, Duration = duration, BlockTransition = block }; - - /// - /// 创建缩放策略 - /// - /// 持续时间 - /// 是否阻塞 - public static UiAnimationPolicy Scale(float duration = 0.3f, bool block = false) - => new UiAnimationPolicy { Animation = UiTransitionAnimation.Scale, Duration = duration, BlockTransition = block }; -} - -/// -/// 缓动函数枚举 -/// -public enum EasingFunction -{ - /// - /// 线性 - /// - Linear, - - /// - /// 缓入 - /// - EaseIn, - - /// - /// 缓出 - /// - EaseOut, - - /// - /// 缓入缓出 - /// - EaseInOut -} diff --git a/GFramework.Game.Abstractions/ui/UiCacheConfig.cs b/GFramework.Game.Abstractions/ui/UiCacheConfig.cs index c5e14ca..e7d9687 100644 --- a/GFramework.Game.Abstractions/ui/UiCacheConfig.cs +++ b/GFramework.Game.Abstractions/ui/UiCacheConfig.cs @@ -1,4 +1,5 @@ using System; +using GFramework.Game.Abstractions.enums; namespace GFramework.Game.Abstractions.ui; @@ -16,20 +17,20 @@ public class UiCacheConfig /// /// 缓存淘汰策略 /// - public CacheEvictionPolicy EvictionPolicy { get; set; } = CacheEvictionPolicy.LRU; + public CacheEvictionPolicy EvictionPolicy { get; set; } = CacheEvictionPolicy.Lru; /// /// 访问后过期时间(可选,null 表示不启用) /// - public TimeSpan? ExpireAfterAccess { get; set; } = null; + public TimeSpan? ExpireAfterAccess { get; set; } /// /// 创建默认配置(LRU 策略,最大 10 个实例) /// - public static UiCacheConfig Default => new UiCacheConfig + public static UiCacheConfig Default => new() { MaxCacheSize = 10, - EvictionPolicy = CacheEvictionPolicy.LRU, + EvictionPolicy = CacheEvictionPolicy.Lru, ExpireAfterAccess = null }; @@ -39,10 +40,10 @@ public class UiCacheConfig /// 最大缓存数量 /// 访问后过期时间 public static UiCacheConfig Lru(int maxSize = 10, TimeSpan? expireAfter = null) - => new UiCacheConfig + => new() { MaxCacheSize = maxSize, - EvictionPolicy = CacheEvictionPolicy.LRU, + EvictionPolicy = CacheEvictionPolicy.Lru, ExpireAfterAccess = expireAfter }; @@ -52,26 +53,10 @@ public class UiCacheConfig /// 最大缓存数量 /// 访问后过期时间 public static UiCacheConfig Lfu(int maxSize = 10, TimeSpan? expireAfter = null) - => new UiCacheConfig + => new() { MaxCacheSize = maxSize, - EvictionPolicy = CacheEvictionPolicy.LFU, + EvictionPolicy = CacheEvictionPolicy.Lfu, ExpireAfterAccess = expireAfter }; -} - -/// -/// 缓存淘汰策略枚举 -/// -public enum CacheEvictionPolicy -{ - /// - /// 最近最少使用 - /// - LRU, - - /// - /// 最少使用频率 - /// - LFU -} +} \ No newline at end of file diff --git a/GFramework.Game/ui/UiRouterBase.cs b/GFramework.Game/ui/UiRouterBase.cs index 70b5a79..a249ee7 100644 --- a/GFramework.Game/ui/UiRouterBase.cs +++ b/GFramework.Game/ui/UiRouterBase.cs @@ -4,7 +4,6 @@ using GFramework.Core.logging; using GFramework.Core.system; using GFramework.Game.Abstractions.enums; using GFramework.Game.Abstractions.ui; -using System.Linq; namespace GFramework.Game.ui; @@ -69,7 +68,7 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter _uiRoot = root; Log.Debug("Bind UI Root: {0}", root.GetType().Name); } - + /// /// 将指定的UI界面压入路由栈,显示新的UI界面 @@ -78,9 +77,9 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter /// 进入界面的参数,可为空 /// 界面切换策略,默认为Exclusive(独占) /// 实例管理策略,默认为Reuse(复用) - /// 动画策略,可为空 - public void Push(string uiKey, IUiPageEnterParam? param = null, UiTransitionPolicy policy = UiTransitionPolicy.Exclusive, - UiInstancePolicy instancePolicy = UiInstancePolicy.Reuse, UiAnimationPolicy? animationPolicy = null) + public void Push(string uiKey, IUiPageEnterParam? param = null, + UiTransitionPolicy policy = UiTransitionPolicy.Exclusive, + UiInstancePolicy instancePolicy = UiInstancePolicy.Reuse) { if (IsTop(uiKey)) { @@ -89,7 +88,6 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter } var @event = CreateEvent(uiKey, UiTransitionType.Push, policy, param); - @event.Set("AnimationPolicy", animationPolicy); Log.Debug( "Push UI Page: key={0}, policy={1}, instancePolicy={2}, stackBefore={3}", @@ -97,7 +95,7 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter ); BeforeChange(@event); - DoPushPageInternal(uiKey, param, policy, instancePolicy, animationPolicy); + DoPushPageInternal(uiKey, param, policy, instancePolicy); AfterChange(@event); } @@ -107,12 +105,10 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter /// 已创建的UI页面行为实例 /// 页面进入参数,可为空 /// 页面切换策略 - /// 动画策略,可为空 public void Push( IUiPageBehavior page, IUiPageEnterParam? param = null, - UiTransitionPolicy policy = UiTransitionPolicy.Exclusive, - UiAnimationPolicy? animationPolicy = null + UiTransitionPolicy policy = UiTransitionPolicy.Exclusive ) { var uiKey = page.View.GetType().Name; @@ -124,7 +120,6 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter } var @event = CreateEvent(uiKey, UiTransitionType.Push, policy, param); - @event.Set("AnimationPolicy", animationPolicy); Log.Debug( "Push existing UI Page: key={0}, policy={1}, stackBefore={2}", @@ -177,18 +172,14 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter /// 弹出页面时的销毁策略,默认为销毁 /// 推入页面时的过渡策略,默认为独占 /// 实例管理策略 - /// 动画策略,可为空 public void Replace( string uiKey, IUiPageEnterParam? param = null, UiPopPolicy popPolicy = UiPopPolicy.Destroy, UiTransitionPolicy pushPolicy = UiTransitionPolicy.Exclusive, - UiInstancePolicy instancePolicy = UiInstancePolicy.Reuse, - UiAnimationPolicy? animationPolicy = null) + UiInstancePolicy instancePolicy = UiInstancePolicy.Reuse) { var @event = CreateEvent(uiKey, UiTransitionType.Replace, pushPolicy, param); - @event.Set("AnimationPolicy", animationPolicy); - Log.Debug( "Replace UI Stack with page: key={0}, popPolicy={1}, pushPolicy={2}, instancePolicy={3}", uiKey, popPolicy, pushPolicy, instancePolicy @@ -207,6 +198,7 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter AfterChange(@event); } + /// /// 替换当前所有页面为已存在的页面(基于实例) /// @@ -214,17 +206,14 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter /// 页面进入参数,可为空 /// 弹出页面时的销毁策略,默认为销毁 /// 推入页面时的过渡策略,默认为独占 - /// 动画策略,可为空 public void Replace( IUiPageBehavior page, IUiPageEnterParam? param = null, UiPopPolicy popPolicy = UiPopPolicy.Destroy, - UiTransitionPolicy pushPolicy = UiTransitionPolicy.Exclusive, - UiAnimationPolicy? animationPolicy = null) + UiTransitionPolicy pushPolicy = UiTransitionPolicy.Exclusive) { var uiKey = page.Key; var @event = CreateEvent(uiKey, UiTransitionType.Replace, pushPolicy, param); - @event.Set("AnimationPolicy", animationPolicy); Log.Debug( "Replace UI Stack with existing page: key={0}, popPolicy={1}, pushPolicy={2}", @@ -373,7 +362,7 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter /// 执行Push页面的核心逻辑(基于 uiKey) /// private void DoPushPageInternal(string uiKey, IUiPageEnterParam? param, UiTransitionPolicy policy, - UiInstancePolicy instancePolicy, UiAnimationPolicy? animationPolicy) + UiInstancePolicy instancePolicy) { // 执行进入守卫 if (!ExecuteEnterGuardsAsync(uiKey, param).GetAwaiter().GetResult()) @@ -486,11 +475,11 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter /// public void Show( string uiKey, - Game.Abstractions.enums.UiLayer layer, + UiLayer layer, IUiPageEnterParam? param = null, UiInstancePolicy instancePolicy = UiInstancePolicy.Reuse) { - if (layer == Game.Abstractions.enums.UiLayer.Page) + if (layer == UiLayer.Page) { throw new ArgumentException("Use Push() for Page layer"); } @@ -546,7 +535,7 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter /// /// 隐藏指定层级的UI /// - public void Hide(string uiKey, Game.Abstractions.enums.UiLayer layer, bool destroy = false) + public void Hide(string uiKey, UiLayer layer, bool destroy = false) { if (!_layers.TryGetValue(layer, out var layerDict)) return; @@ -575,7 +564,7 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter /// /// 清空指定层级的所有UI /// - public void ClearLayer(Game.Abstractions.enums.UiLayer layer, bool destroy = false) + public void ClearLayer(UiLayer layer, bool destroy = false) { if (!_layers.TryGetValue(layer, out var layerDict)) return; @@ -612,121 +601,120 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter #region 路由守卫 - -/// -/// 注册路由守卫 -/// -public void AddGuard(IUiRouteGuard guard) -{ - ArgumentNullException.ThrowIfNull(guard); - - if (_guards.Contains(guard)) + /// + /// 注册路由守卫 + /// + public void AddGuard(IUiRouteGuard guard) { - Log.Debug("Guard already registered: {0}", guard.GetType().Name); - return; - } - - _guards.Add(guard); - // 按优先级排序 - _guards.Sort((a, b) => a.Priority.CompareTo(b.Priority)); - Log.Debug("Guard registered: {0}, Priority={1}", guard.GetType().Name, guard.Priority); -} + ArgumentNullException.ThrowIfNull(guard); -/// -/// 移除路由守卫 -/// -public void RemoveGuard(IUiRouteGuard guard) -{ - ArgumentNullException.ThrowIfNull(guard); - - if (_guards.Remove(guard)) - { - Log.Debug("Guard removed: {0}", guard.GetType().Name); - } -} - -/// -/// 注册路由守卫(泛型方法) -/// -public void AddGuard() where T : IUiRouteGuard, new() -{ - var guard = new T(); - AddGuard(guard); -} - -/// -/// 执行进入守卫 -/// -private async Task ExecuteEnterGuardsAsync(string uiKey, IUiPageEnterParam? param) -{ - foreach (var guard in _guards) - { - try + if (_guards.Contains(guard)) { - Log.Debug("Executing enter guard: {0} for {1}", guard.GetType().Name, uiKey); - var canEnter = await guard.CanEnterAsync(uiKey, param); - - if (!canEnter) - { - Log.Debug("Enter guard blocked: {0}", guard.GetType().Name); - return false; - } - - if (guard.CanInterrupt) - { - Log.Debug("Enter guard {0} passed, can interrupt = true", guard.GetType().Name); - return true; - } + Log.Debug("Guard already registered: {0}", guard.GetType().Name); + return; } - catch (Exception ex) + + _guards.Add(guard); + // 按优先级排序 + _guards.Sort((a, b) => a.Priority.CompareTo(b.Priority)); + Log.Debug("Guard registered: {0}, Priority={1}", guard.GetType().Name, guard.Priority); + } + + /// + /// 注册路由守卫(泛型方法) + /// + public void AddGuard() where T : IUiRouteGuard, new() + { + var guard = new T(); + AddGuard(guard); + } + + /// + /// 移除路由守卫 + /// + public void RemoveGuard(IUiRouteGuard guard) + { + ArgumentNullException.ThrowIfNull(guard); + + if (_guards.Remove(guard)) { - Log.Error("Enter guard {0} failed: {1}", guard.GetType().Name, ex.Message); - if (guard.CanInterrupt) - { - return false; - } + Log.Debug("Guard removed: {0}", guard.GetType().Name); } } - - return true; -} -/// -/// 执行离开守卫 -/// -private async Task ExecuteLeaveGuardsAsync(string uiKey) -{ - foreach (var guard in _guards) + /// + /// 执行进入守卫 + /// + private async Task ExecuteEnterGuardsAsync(string uiKey, IUiPageEnterParam? param) { - try + foreach (var guard in _guards) { - Log.Debug("Executing leave guard: {0} for {1}", guard.GetType().Name, uiKey); - var canLeave = await guard.CanLeaveAsync(uiKey); - - if (!canLeave) + try { - Log.Debug("Leave guard blocked: {0}", guard.GetType().Name); - return false; - } - - if (guard.CanInterrupt) - { - Log.Debug("Leave guard {0} passed, can interrupt = true", guard.GetType().Name); - return true; - } - } - catch (Exception ex) - { - Log.Error("Leave guard {0} failed: {1}", guard.GetType().Name, ex.Message); - if (guard.CanInterrupt) - { - return false; - } - } - } - - return true; -} + Log.Debug("Executing enter guard: {0} for {1}", guard.GetType().Name, uiKey); + var canEnter = await guard.CanEnterAsync(uiKey, param); -#endregion + if (!canEnter) + { + Log.Debug("Enter guard blocked: {0}", guard.GetType().Name); + return false; + } + + if (guard.CanInterrupt) + { + Log.Debug("Enter guard {0} passed, can interrupt = true", guard.GetType().Name); + return true; + } + } + catch (Exception ex) + { + Log.Error("Enter guard {0} failed: {1}", guard.GetType().Name, ex.Message); + if (guard.CanInterrupt) + { + return false; + } + } + } + + return true; + } + + /// + /// 执行离开守卫 + /// + private async Task ExecuteLeaveGuardsAsync(string uiKey) + { + foreach (var guard in _guards) + { + try + { + Log.Debug("Executing leave guard: {0} for {1}", guard.GetType().Name, uiKey); + var canLeave = await guard.CanLeaveAsync(uiKey); + + if (!canLeave) + { + Log.Debug("Leave guard blocked: {0}", guard.GetType().Name); + return false; + } + + if (guard.CanInterrupt) + { + Log.Debug("Leave guard {0} passed, can interrupt = true", guard.GetType().Name); + return true; + } + } + catch (Exception ex) + { + Log.Error("Leave guard {0} failed: {1}", guard.GetType().Name, ex.Message); + if (guard.CanInterrupt) + { + return false; + } + } + } + + return true; + } + + #endregion } \ No newline at end of file diff --git a/GFramework.Godot/ui/GodotUiFactory.cs b/GFramework.Godot/ui/GodotUiFactory.cs index db6c568..365daab 100644 --- a/GFramework.Godot/ui/GodotUiFactory.cs +++ b/GFramework.Godot/ui/GodotUiFactory.cs @@ -1,8 +1,8 @@ -using System; using GFramework.Core.Abstractions.logging; using GFramework.Core.extensions; using GFramework.Core.logging; using GFramework.Core.utility; +using GFramework.Game.Abstractions.enums; using GFramework.Game.Abstractions.ui; using GFramework.Godot.extensions; using Godot; @@ -18,7 +18,7 @@ public class GodotUiFactory : AbstractContextUtility, IUiFactory /// /// 缓存统计信息实现类 /// - private class CacheStatisticsInfo : IUiCacheStatistics + private sealed class CacheStatisticsInfo : IUiCacheStatistics { public int CacheSize { get; set; } public int HitCount { get; set; } @@ -381,27 +381,25 @@ public class GodotUiFactory : AbstractContextUtility, IUiFactory { var config = GetCacheConfig(uiKey); var currentSize = _cachedInstances.TryGetValue(uiKey, out var queue) ? queue.Count : 0; - - if (currentSize > config.MaxCacheSize) + + if (currentSize <= config.MaxCacheSize) return; + var toEvict = currentSize - config.MaxCacheSize; + + for (var i = 0; i < toEvict; i++) { - var toEvict = currentSize - config.MaxCacheSize; - - for (int i = 0; i < toEvict; i++) - { - if (config.EvictionPolicy == CacheEvictionPolicy.LRU) - EvictLRU(uiKey); - else - EvictLFU(uiKey); - } - - Log.Debug("Evicted {0} instances for UI: {1}", toEvict, uiKey); + if (config.EvictionPolicy == CacheEvictionPolicy.Lru) + EvictLru(uiKey); + else + EvictLfu(uiKey); } + + Log.Debug("Evicted {0} instances for UI: {1}", toEvict, uiKey); } /// /// LRU淘汰策略 /// - private void EvictLRU(string uiKey) + private void EvictLru(string uiKey) { if (!_accessTimeQueue.TryGetValue(uiKey, out var timeQueue) || timeQueue.Count == 0) return; @@ -437,7 +435,7 @@ public class GodotUiFactory : AbstractContextUtility, IUiFactory /// /// LFU淘汰策略 /// - private void EvictLFU(string uiKey) + private void EvictLfu(string uiKey) { if (!_cachedInstances.TryGetValue(uiKey, out var queue) || queue.Count == 0) return; diff --git a/GFramework.Godot/ui/GodotUiTransition.cs b/GFramework.Godot/ui/GodotUiTransition.cs deleted file mode 100644 index 85323cf..0000000 --- a/GFramework.Godot/ui/GodotUiTransition.cs +++ /dev/null @@ -1,171 +0,0 @@ -using System; -using System.Threading.Tasks; -using GFramework.Game.Abstractions.enums; -using GFramework.Game.Abstractions.ui; -using Godot; - -namespace GFramework.Godot.ui; - -/// -/// Godot平台的UI过渡动画实现 -/// 支持多种预定义动画效果 -/// -public class GodotUiTransition : IUiTransition -{ - private readonly UiTransitionAnimation _animation; - - /// - /// 创建过渡动画实例 - /// - /// 动画类型 - public GodotUiTransition(UiTransitionAnimation animation) - { - _animation = animation; - } - - /// - /// 播放进入动画 - /// - public async Task PlayEnterAsync(IUiPageBehavior page) - { - var node = page.View as Node; - if (node == null) - return; - - switch (_animation) - { - case UiTransitionAnimation.Fade: - await PlayFadeEnterAsync(node); - break; - case UiTransitionAnimation.Scale: - await PlayScaleEnterAsync(node); - break; - case UiTransitionAnimation.SlideLeft: - case UiTransitionAnimation.SlideRight: - case UiTransitionAnimation.SlideUp: - case UiTransitionAnimation.SlideDown: - await PlaySlideEnterAsync(node, _animation); - break; - case UiTransitionAnimation.None: - default: - break; - } - } - - /// - /// 播放退出动画 - /// - public async Task PlayExitAsync(IUiPageBehavior page) - { - var node = page.View as Node; - if (node == null) - return; - - switch (_animation) - { - case UiTransitionAnimation.Fade: - await PlayFadeExitAsync(node); - break; - case UiTransitionAnimation.Scale: - await PlayScaleExitAsync(node); - break; - case UiTransitionAnimation.SlideLeft: - case UiTransitionAnimation.SlideRight: - case UiTransitionAnimation.SlideUp: - case UiTransitionAnimation.SlideDown: - await PlaySlideExitAsync(node, _animation); - break; - case UiTransitionAnimation.None: - default: - break; - } - } - - private static async Task PlayFadeEnterAsync(Node node) - { - if (node is CanvasItem canvasItem) - { - canvasItem.Modulate = new Color(1,1, 1, 0); - canvasItem.Visible = true; - await Task.Delay(300); - canvasItem.Modulate = new Color(1,1, 1, 1); - } - } - - private static async Task PlayFadeExitAsync(Node node) - { - if (node is CanvasItem canvasItem) - { - await Task.Delay(300); - canvasItem.Modulate = new Color(1,1, 1, 0); - } - } - - private static async Task PlayScaleEnterAsync(Node node) - { - if (node is Control control) - { - control.Scale = Vector2.Zero; - control.PivotOffset = control.Size / 2; - await Task.Delay(300); - control.Scale = Vector2.One; - } - } - - private static async Task PlayScaleExitAsync(Node node) - { - if (node is Control control) - { - control.PivotOffset = control.Size / 2; - await Task.Delay(300); - control.Scale = Vector2.Zero; - } - } - - private static async Task PlaySlideEnterAsync(Node node, UiTransitionAnimation direction) - { - if (node is Control control) - { - var screenPos = control.GetViewportRect().Size; - var offset = GetSlideOffset(direction, screenPos); - control.Position += offset; - await Task.Delay(300); - control.Position -= offset; - } - } - - private static async Task PlaySlideExitAsync(Node node, UiTransitionAnimation direction) - { - if (node is Control control) - { - var screenPos = control.GetViewportRect().Size; - var offset = GetSlideExitOffset(direction, screenPos); - await Task.Delay(300); - control.Position += offset; - } - } - - private static Vector2 GetSlideOffset(UiTransitionAnimation direction, Vector2 screenPos) - { - return direction switch - { - UiTransitionAnimation.SlideLeft => Vector2.Right * screenPos.X, - UiTransitionAnimation.SlideRight => Vector2.Left * screenPos.X, - UiTransitionAnimation.SlideUp => Vector2.Down * screenPos.Y, - UiTransitionAnimation.SlideDown => Vector2.Up * screenPos.Y, - _ => Vector2.Zero - }; - } - - private static Vector2 GetSlideExitOffset(UiTransitionAnimation direction, Vector2 screenPos) - { - return direction switch - { - UiTransitionAnimation.SlideLeft => Vector2.Left * screenPos.X, - UiTransitionAnimation.SlideRight => Vector2.Right * screenPos.X, - UiTransitionAnimation.SlideUp => Vector2.Up * screenPos.Y, - UiTransitionAnimation.SlideDown => Vector2.Down * screenPos.Y, - _ => Vector2.Zero - }; - } -}