using GFramework.Core.Abstractions.logging; using GFramework.Core.logging; using GFramework.Game.Abstractions.enums; using GFramework.Game.Abstractions.ui; namespace GFramework.Game.ui; /// /// UI切换处理器管道,负责管理和执行UI切换扩展点 /// public class UiTransitionPipeline { private static readonly ILogger Log = LoggerFactoryResolver.Provider.CreateLogger("UiTransitionPipeline"); private readonly List _handlers = []; private readonly Dictionary _options = new(); /// /// 注册UI切换处理器 /// /// 处理器实例 /// 执行选项 public void RegisterHandler(IUiTransitionHandler handler, UiTransitionHandlerOptions? options = null) { ArgumentNullException.ThrowIfNull(handler); if (_handlers.Contains(handler)) { Log.Debug("Handler already registered: {0}", handler.GetType().Name); return; } _handlers.Add(handler); _options[handler] = options ?? new UiTransitionHandlerOptions(); Log.Debug( "Handler registered: {0}, Priority={1}, Phases={2}, TimeoutMs={3}", handler.GetType().Name, handler.Priority, handler.Phases, _options[handler].TimeoutMs ); } /// /// 注销UI切换处理器 /// /// 处理器实例 public void UnregisterHandler(IUiTransitionHandler handler) { ArgumentNullException.ThrowIfNull(handler); if (!_handlers.Remove(handler)) return; _options.Remove(handler); Log.Debug("Handler unregistered: {0}", handler.GetType().Name); } /// /// 执行指定阶段的所有Handler /// /// UI切换事件 /// 执行阶段 /// 取消令牌 /// 异步任务 public async Task ExecuteAsync( UiTransitionEvent @event, UiTransitionPhases phases, CancellationToken cancellationToken = default ) { @event.Set("Phases", phases.ToString()); Log.Debug( "Execute pipeline: Phases={0}, From={1}, To={2}, Type={3}, HandlerCount={4}", phases, @event.FromUiKey, @event.ToUiKey ?? "None", @event.TransitionType, _handlers.Count ); var sortedHandlers = FilterAndSortHandlers(@event, phases); if (sortedHandlers.Count == 0) { Log.Debug("No handlers to execute for phases: {0}", phases); return; } Log.Debug( "Executing {0} handlers for phases {1}", sortedHandlers.Count, phases ); foreach (var handler in sortedHandlers) { var options = _options[handler]; await ExecuteSingleHandlerAsync(handler, options, @event, cancellationToken); } Log.Debug("Pipeline execution completed for phases: {0}", phases); } private List FilterAndSortHandlers( UiTransitionEvent @event, UiTransitionPhases phases) { return _handlers .Where(h => h.Phases.HasFlag(phases) && h.ShouldHandle(@event, phases)) .OrderBy(h => h.Priority) .ToList(); } private static async Task ExecuteSingleHandlerAsync( IUiTransitionHandler handler, UiTransitionHandlerOptions options, UiTransitionEvent @event, CancellationToken cancellationToken) { Log.Debug( "Executing handler: {0}, Priority={1}", handler.GetType().Name, handler.Priority ); try { using var timeoutCts = options.TimeoutMs > 0 ? new CancellationTokenSource(options.TimeoutMs) : null; using var linkedCts = timeoutCts != null && cancellationToken.CanBeCanceled ? CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutCts.Token) : null; await handler.HandleAsync( @event, linkedCts?.Token ?? cancellationToken ).ConfigureAwait(false); Log.Debug("Handler completed: {0}", handler.GetType().Name); } catch (OperationCanceledException) when (!cancellationToken.IsCancellationRequested) { Log.Error( "Handler timeout: {0}, TimeoutMs={1}", handler.GetType().Name, options.TimeoutMs ); if (options.ContinueOnError) return; Log.Error("Stopping pipeline due to timeout and ContinueOnError=false"); throw; } catch (OperationCanceledException) { Log.Debug("Handler cancelled: {0}", handler.GetType().Name); throw; } catch (Exception ex) { Log.Error("Handler failed: {0}, Error: {1}", handler.GetType().Name, ex.Message); if (options.ContinueOnError) return; Log.Error("Stopping pipeline due to error and ContinueOnError=false"); throw; } } }