// Copyright (c) 2026 GeWuYou // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. using GFramework.Core.Abstractions.logging; using GFramework.Core.extensions; using GFramework.Core.logging; using GFramework.Core.system; using GFramework.Game.Abstractions.enums; using GFramework.Game.Abstractions.scene; namespace GFramework.Game.scene; /// /// 场景路由基类,提供场景切换和卸载的基础功能。 /// 实现了 接口,用于管理场景的加载、替换和卸载操作。 /// public abstract class SceneRouterBase : AbstractSystem, ISceneRouter { private static readonly ILogger Log = LoggerFactoryResolver.Provider.CreateLogger(nameof(SceneRouterBase)); private readonly List _guards = new(); private readonly SceneTransitionPipeline _pipeline = new(); private readonly Stack _stack = new(); private readonly SemaphoreSlim _transitionLock = new(1, 1); private ISceneFactory _factory = null!; /// /// 场景根节点 /// protected ISceneRoot? Root; /// /// 获取当前场景行为对象。 /// public ISceneBehavior? Current => _stack.Count > 0 ? _stack.Peek() : null; /// /// 获取当前场景的键名。 /// public string? CurrentKey => Current?.Key; /// /// 获取场景栈的只读视图,按压入顺序排列(从栈底到栈顶)。 /// public IEnumerable Stack => _stack.Reverse(); /// /// 获取是否正在进行场景转换。 /// public bool IsTransitioning { get; private set; } /// /// 绑定场景根节点。 /// /// 场景根节点实例。 public void BindRoot(ISceneRoot root) { Root = root; Log.Debug("Bind Scene Root: {0}", root.GetType().Name); } #region Replace /// /// 替换当前场景为指定场景。 /// /// 目标场景键名。 /// 场景进入参数。 /// 异步任务。 public async ValueTask ReplaceAsync( string sceneKey, ISceneEnterParam? param = null) { await _transitionLock.WaitAsync(); try { IsTransitioning = true; var @event = CreateEvent(sceneKey, SceneTransitionType.Replace, param); await _pipeline.ExecuteAroundAsync(@event, async () => { await BeforeChangeAsync(@event); await ClearInternalAsync(); await PushInternalAsync(sceneKey, param); AfterChange(@event); }); } finally { IsTransitioning = false; _transitionLock.Release(); } } #endregion #region Query /// /// 检查指定场景是否在栈中。 /// /// 场景键名。 /// 如果场景在栈中返回true,否则返回false。 public bool Contains(string sceneKey) { return _stack.Any(s => s.Key == sceneKey); } #endregion /// /// 注册场景过渡处理器。 /// /// 处理器实例。 /// 执行选项。 public void RegisterHandler(ISceneTransitionHandler handler, SceneTransitionHandlerOptions? options = null) { _pipeline.RegisterHandler(handler, options); } /// /// 注销场景过渡处理器。 /// /// 处理器实例。 public void UnregisterHandler(ISceneTransitionHandler handler) { _pipeline.UnregisterHandler(handler); } /// /// 注册环绕场景过渡处理器。 /// /// 环绕处理器实例。 /// 处理器选项配置。 public void RegisterAroundHandler( ISceneAroundTransitionHandler handler, SceneTransitionHandlerOptions? options = null) { _pipeline.RegisterAroundHandler(handler, options); } /// /// 注销环绕场景过渡处理器。 /// /// 环绕处理器实例。 public void UnregisterAroundHandler( ISceneAroundTransitionHandler handler) { _pipeline.UnregisterAroundHandler(handler); } /// /// 添加场景路由守卫。 /// /// 守卫实例。 public void AddGuard(ISceneRouteGuard guard) { ArgumentNullException.ThrowIfNull(guard); if (!_guards.Contains(guard)) { _guards.Add(guard); _guards.Sort((a, b) => a.Priority.CompareTo(b.Priority)); Log.Debug("Guard added: {0}, Priority={1}", guard.GetType().Name, guard.Priority); } } /// /// 添加场景路由守卫(泛型版本)。 /// /// 守卫类型。 public void AddGuard() where T : ISceneRouteGuard, new() { AddGuard(new T()); } /// /// 移除场景路由守卫。 /// /// 守卫实例。 public void RemoveGuard(ISceneRouteGuard guard) { if (_guards.Remove(guard)) { Log.Debug("Guard removed: {0}", guard.GetType().Name); } } /// /// 注册场景过渡处理器的抽象方法,由子类实现。 /// protected abstract void RegisterHandlers(); /// /// 系统初始化方法,获取场景工厂并注册处理器。 /// protected override void OnInit() { _factory = this.GetUtility()!; Log.Debug("SceneRouterBase initialized. Factory={0}", _factory.GetType().Name); RegisterHandlers(); } #region Push /// /// 将指定场景推入栈顶。 /// /// 目标场景键名。 /// 场景进入参数。 /// 异步任务。 public async ValueTask PushAsync( string sceneKey, ISceneEnterParam? param = null) { await _transitionLock.WaitAsync(); try { IsTransitioning = true; var @event = CreateEvent(sceneKey, SceneTransitionType.Push, param); await _pipeline.ExecuteAroundAsync(@event, async () => { await BeforeChangeAsync(@event); await PushInternalAsync(sceneKey, param); AfterChange(@event); }); } finally { IsTransitioning = false; _transitionLock.Release(); } } /// /// 内部推送场景实现方法。 /// 执行守卫检查、场景创建、添加到场景树、加载资源、暂停当前场景、压入栈等操作。 /// /// 场景键名。 /// 场景进入参数。 /// 异步任务。 private async ValueTask PushInternalAsync( string sceneKey, ISceneEnterParam? param) { if (Contains(sceneKey)) { Log.Warn("Scene already in stack: {0}", sceneKey); return; } // 守卫检查 if (!await ExecuteEnterGuardsAsync(sceneKey, param)) { Log.Warn("Push blocked by guard: {0}", sceneKey); return; } // 通过 Factory 创建场景实例 var scene = _factory.Create(sceneKey); // 添加到场景树 Root!.AddScene(scene); // 加载资源 await scene.OnLoadAsync(param); // 暂停当前场景 if (_stack.Count > 0) { var current = _stack.Peek(); await current.OnPauseAsync(); } // 压入栈 _stack.Push(scene); // 进入场景 await scene.OnEnterAsync(); Log.Debug("Push Scene: {0}, stackCount={1}", sceneKey, _stack.Count); } #endregion #region Pop /// /// 弹出栈顶场景。 /// /// 异步任务。 public async ValueTask PopAsync() { await _transitionLock.WaitAsync(); try { IsTransitioning = true; var @event = CreateEvent(null, SceneTransitionType.Pop); await _pipeline.ExecuteAroundAsync(@event, async () => { await BeforeChangeAsync(@event); await PopInternalAsync(); AfterChange(@event); }); } finally { IsTransitioning = false; _transitionLock.Release(); } } /// /// 内部弹出场景实现方法。 /// 执行守卫检查、退出场景、卸载资源、从场景树移除、恢复下一个场景等操作。 /// /// 异步任务。 private async ValueTask PopInternalAsync() { if (_stack.Count == 0) return; var top = _stack.Peek(); // 守卫检查 if (!await ExecuteLeaveGuardsAsync(top.Key)) { Log.Warn("Pop blocked by guard: {0}", top.Key); return; } _stack.Pop(); // 退出场景 await top.OnExitAsync(); // 卸载资源 await top.OnUnloadAsync(); // 从场景树移除 Root!.RemoveScene(top); // 恢复下一个场景 if (_stack.Count > 0) { var next = _stack.Peek(); await next.OnResumeAsync(); } Log.Debug("Pop Scene, stackCount={0}", _stack.Count); } #endregion #region Clear /// /// 清空所有场景栈。 /// /// 异步任务。 public async ValueTask ClearAsync() { await _transitionLock.WaitAsync(); try { IsTransitioning = true; var @event = CreateEvent(null, SceneTransitionType.Clear); await _pipeline.ExecuteAroundAsync(@event, async () => { await BeforeChangeAsync(@event); await ClearInternalAsync(); AfterChange(@event); }); } finally { IsTransitioning = false; _transitionLock.Release(); } } /// /// 内部清空场景栈实现方法。 /// 循环调用弹出操作直到栈为空。 /// /// 异步任务。 private async ValueTask ClearInternalAsync() { while (_stack.Count > 0) { await PopInternalAsync(); } } #endregion #region Helper Methods /// /// 创建场景转换事件对象。 /// /// 目标场景键名。 /// 转换类型。 /// 进入参数。 /// 场景转换事件实例。 private SceneTransitionEvent CreateEvent( string? toSceneKey, SceneTransitionType type, ISceneEnterParam? param = null) { return new SceneTransitionEvent { FromSceneKey = CurrentKey, ToSceneKey = toSceneKey, TransitionType = type, EnterParam = param }; } /// /// 执行转换前阶段的处理逻辑。 /// /// 场景转换事件。 /// 异步任务。 private async Task BeforeChangeAsync(SceneTransitionEvent @event) { Log.Debug("BeforeChange phases started: {0}", @event.TransitionType); await _pipeline.ExecuteAsync(@event, SceneTransitionPhases.BeforeChange); Log.Debug("BeforeChange phases completed: {0}", @event.TransitionType); } /// /// 执行转换后阶段的处理逻辑。 /// 在后台线程中异步执行,避免阻塞主线程。 /// /// 场景转换事件。 private void AfterChange(SceneTransitionEvent @event) { Log.Debug("AfterChange phases started: {0}", @event.TransitionType); _ = Task.Run(async () => { try { await _pipeline.ExecuteAsync(@event, SceneTransitionPhases.AfterChange); Log.Debug("AfterChange phases completed: {0}", @event.TransitionType); } catch (Exception ex) { Log.Error("AfterChange phases failed: {0}, Error: {1}", @event.TransitionType, ex.Message); } }); } /// /// 执行进入场景的守卫检查。 /// 按优先级顺序执行所有守卫的CanEnterAsync方法。 /// /// 场景键名。 /// 进入参数。 /// 如果所有守卫都允许进入返回true,否则返回false。 private async Task ExecuteEnterGuardsAsync(string sceneKey, ISceneEnterParam? param) { foreach (var guard in _guards) { try { Log.Debug("Executing enter guard: {0} for {1}", guard.GetType().Name, sceneKey); var canEnter = await guard.CanEnterAsync(sceneKey, 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; } } catch (Exception ex) { Log.Error("Enter guard {0} failed: {1}", guard.GetType().Name, ex.Message); if (guard.CanInterrupt) return false; } } return true; } /// /// 执行离开场景的守卫检查。 /// 按优先级顺序执行所有守卫的CanLeaveAsync方法。 /// /// 场景键名。 /// 如果所有守卫都允许离开返回true,否则返回false。 private async Task ExecuteLeaveGuardsAsync(string sceneKey) { foreach (var guard in _guards) { try { Log.Debug("Executing leave guard: {0} for {1}", guard.GetType().Name, sceneKey); var canLeave = await guard.CanLeaveAsync(sceneKey); 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 }