GFramework/GFramework.Game/ui/UiTransitionPipeline.cs
GeWuYou ef2e718efe feat(coroutine): 完善协程系统接口设计与实现
- 实现ICoroutineContext和ICoroutineHandle接口,提供协程上下文和句柄的标准定义
- 重构CoroutineContext实现ICoroutineContext接口,统一协程上下文访问方式
- 修改CoroutineHandle实现ICoroutineHandle接口,标准化协程控制方法
- 扩展ICoroutineScheduler和ICoroutineScope接口,增加ActiveCount属性和Launch方法
- 优化CoroutineScheduler线程安全性,添加线程ID检查防止跨线程调用
- 为WaitForSeconds、WaitUntil、WaitWhile添加Reset方法支持状态重置
- 重构CoroutineScopeExtensions移除类型转换,使用接口方法替代具体类型
- 改进GlobalCoroutineScope添加TryGetScope方法,使用TryGet模式替代异常控制
- 优化CoroutineHandle取消逻辑,确保取消时正确触发OnComplete事件
- 统一各协程组件的XML文档注释,完善参数和返回值说明
- [skip ci]
2026-01-21 00:06:01 +08:00

168 lines
5.4 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using GFramework.Core.Abstractions.logging;
using GFramework.Core.logging;
using GFramework.Game.Abstractions.enums;
using GFramework.Game.Abstractions.ui;
namespace GFramework.Game.ui;
/// <summary>
/// UI切换处理器管道负责管理和执行UI切换扩展点
/// </summary>
public class UiTransitionPipeline
{
private static readonly ILogger Log = LoggerFactoryResolver.Provider.CreateLogger("UiTransitionPipeline");
private readonly List<IUiTransitionHandler> _handlers = [];
private readonly Dictionary<IUiTransitionHandler, UiTransitionHandlerOptions> _options = new();
/// <summary>
/// 注册UI切换处理器
/// </summary>
/// <param name="handler">处理器实例</param>
/// <param name="options">执行选项</param>
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
);
}
/// <summary>
/// 注销UI切换处理器
/// </summary>
/// <param name="handler">处理器实例</param>
public void UnregisterHandler(IUiTransitionHandler handler)
{
ArgumentNullException.ThrowIfNull(handler);
if (!_handlers.Remove(handler)) return;
_options.Remove(handler);
Log.Debug("Handler unregistered: {0}", handler.GetType().Name);
}
/// <summary>
/// 执行指定阶段的所有Handler
/// </summary>
/// <param name="event">UI切换事件</param>
/// <param name="phases">执行阶段</param>
/// <param name="cancellationToken">取消令牌</param>
/// <returns>异步任务</returns>
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<IUiTransitionHandler> 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;
}
}
}