mirror of
https://github.com/GeWuYou/GFramework.git
synced 2026-03-23 03:04:29 +08:00
- 将所有小写的命名空间导入更正为首字母大写格式 - 统一 GFramework 框架的命名空间引用规范 - 修复 core、ecs、godot 等模块的命名空间导入错误 - 标准化文档示例代码中的 using 语句格式 - 确保所有文档中的命名空间引用保持一致性 - 更新 global using 语句以匹配正确的命名空间格式
284 lines
9.2 KiB
C#
284 lines
9.2 KiB
C#
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<IUiAroundTransitionHandler> _aroundHandlers = [];
|
||
private readonly Dictionary<IUiAroundTransitionHandler, UiTransitionHandlerOptions> _aroundOptions = new();
|
||
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>
|
||
/// 注册 Around 中间件处理器
|
||
/// </summary>
|
||
/// <param name="handler">处理器实例</param>
|
||
/// <param name="options">执行选项</param>
|
||
public void RegisterAroundHandler(IUiAroundTransitionHandler handler, UiTransitionHandlerOptions? options = null)
|
||
{
|
||
ArgumentNullException.ThrowIfNull(handler);
|
||
|
||
if (_aroundHandlers.Contains(handler))
|
||
{
|
||
Log.Debug("Around handler already registered: {0}", handler.GetType().Name);
|
||
return;
|
||
}
|
||
|
||
_aroundHandlers.Add(handler);
|
||
_aroundOptions[handler] = options ?? new UiTransitionHandlerOptions();
|
||
Log.Debug(
|
||
"Around handler registered: {0}, Priority={1}",
|
||
handler.GetType().Name,
|
||
handler.Priority
|
||
);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 注销 Around 中间件处理器
|
||
/// </summary>
|
||
/// <param name="handler">处理器实例</param>
|
||
public void UnregisterAroundHandler(IUiAroundTransitionHandler handler)
|
||
{
|
||
ArgumentNullException.ThrowIfNull(handler);
|
||
|
||
if (!_aroundHandlers.Remove(handler)) return;
|
||
_aroundOptions.Remove(handler);
|
||
Log.Debug("Around 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 ?? "None",
|
||
@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);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 执行 Around 中间件处理器,包裹核心操作
|
||
/// </summary>
|
||
/// <param name="event">UI切换事件</param>
|
||
/// <param name="coreAction">核心操作委托</param>
|
||
/// <param name="cancellationToken">取消令牌</param>
|
||
/// <returns>异步任务</returns>
|
||
public async Task ExecuteAroundAsync(
|
||
UiTransitionEvent @event,
|
||
Func<Task> coreAction,
|
||
CancellationToken cancellationToken = default)
|
||
{
|
||
var handlers = _aroundHandlers
|
||
.Where(h => h.ShouldHandle(@event))
|
||
.OrderBy(h => h.Priority)
|
||
.ToList();
|
||
|
||
if (handlers.Count == 0)
|
||
{
|
||
await coreAction();
|
||
return;
|
||
}
|
||
|
||
Log.Debug(
|
||
"Executing {0} around handlers for event: {1}",
|
||
handlers.Count,
|
||
@event.TransitionType
|
||
);
|
||
|
||
// 构建中间件链
|
||
Func<Task> pipeline = coreAction;
|
||
for (int i = handlers.Count - 1; i >= 0; i--)
|
||
{
|
||
var handler = handlers[i];
|
||
var options = _aroundOptions[handler];
|
||
var next = pipeline;
|
||
|
||
pipeline = async () => await ExecuteSingleAroundHandlerAsync(
|
||
handler, options, @event, next, cancellationToken);
|
||
}
|
||
|
||
await pipeline();
|
||
}
|
||
|
||
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;
|
||
}
|
||
}
|
||
|
||
private static async Task ExecuteSingleAroundHandlerAsync(
|
||
IUiAroundTransitionHandler handler,
|
||
UiTransitionHandlerOptions options,
|
||
UiTransitionEvent @event,
|
||
Func<Task> next,
|
||
CancellationToken cancellationToken)
|
||
{
|
||
Log.Debug("Executing around handler: {0}", handler.GetType().Name);
|
||
|
||
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, next, linkedCts?.Token ?? cancellationToken);
|
||
|
||
Log.Debug("Around handler completed: {0}", handler.GetType().Name);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Log.Error("Around handler failed: {0}, Error: {1}",
|
||
handler.GetType().Name, ex.Message);
|
||
|
||
if (!options.ContinueOnError)
|
||
throw;
|
||
}
|
||
}
|
||
} |