using System.Reflection; using GFramework.Core.Abstractions.coroutine; using GFramework.Core.coroutine; using GFramework.Core.coroutine.instructions; using Godot; namespace GFramework.Godot.coroutine; /// /// Godot协程管理器,提供基于不同更新循环的协程调度功能 /// 支持Process、PhysicsProcess和DeferredProcess三种执行段的协程管理 /// public partial class Timing : Node { private static Timing? _instance; private static readonly Timing?[] ActiveInstances = new Timing?[16]; private CoroutineScheduler? _deferredScheduler; private GodotTimeSource? _deferredTimeSource; private ushort _frameCounter; private byte _instanceId = 1; private CoroutineScheduler? _physicsScheduler; private GodotTimeSource? _physicsTimeSource; private CoroutineScheduler? _processScheduler; private GodotTimeSource? _processTimeSource; /// /// 获取Process调度器,如果未初始化则抛出异常 /// private CoroutineScheduler ProcessScheduler => _processScheduler ?? throw new InvalidOperationException( "Timing not yet initialized (_Ready not executed)"); /// /// 获取Physics调度器,如果未初始化则抛出异常 /// private CoroutineScheduler PhysicsScheduler => _physicsScheduler ?? throw new InvalidOperationException( "Timing not yet initialized (_Ready not executed)"); /// /// 获取Deferred调度器,如果未初始化则抛出异常 /// private CoroutineScheduler DeferredScheduler => _deferredScheduler ?? throw new InvalidOperationException( "Timing not yet initialized (_Ready not executed)"); #region 单例 /// /// 获取Timing单例实例 /// 如果实例不存在则自动创建并添加到场景树根节点 /// public static Timing Instance { get { if (_instance != null) return _instance; var tree = (SceneTree)Engine.GetMainLoop(); _instance = tree.Root.GetNodeOrNull(nameof(Timing)); if (_instance == null) { _instance = new Timing { Name = nameof(Timing) }; tree.Root.AddChild(_instance); } return _instance; } } #endregion #region Debug 信息 /// /// 获取Process段活跃协程数量 /// public int ProcessCoroutines => _processScheduler?.ActiveCoroutineCount ?? 0; /// /// 获取Physics段活跃协程数量 /// public int PhysicsCoroutines => _physicsScheduler?.ActiveCoroutineCount ?? 0; /// /// 获取Deferred段活跃协程数量 /// public int DeferredCoroutines => _deferredScheduler?.ActiveCoroutineCount ?? 0; #endregion #region 生命周期 /// /// 节点就绪时的初始化方法 /// 设置处理优先级,初始化调度器,并注册实例 /// public override void _Ready() { ProcessPriority = -1; TrySetPhysicsPriority(-1); InitializeSchedulers(); RegisterInstance(); } /// /// 节点退出场景树时的清理方法 /// 从活动实例数组中移除当前实例并清理必要资源 /// public override void _ExitTree() { if (_instanceId < ActiveInstances.Length) ActiveInstances[_instanceId] = null; CleanupInstanceIfNecessary(); } /// /// 清理实例引用 /// private static void CleanupInstanceIfNecessary() { _instance = null; } /// /// 每帧处理逻辑 /// 更新Process调度器,增加帧计数器,并安排延迟处理 /// /// 时间增量 public override void _Process(double delta) { _processScheduler?.Update(); _frameCounter++; CallDeferred(nameof(ProcessDeferred)); } /// /// 物理处理逻辑 /// 更新Physics调度器 /// /// 物理时间增量 public override void _PhysicsProcess(double delta) { _physicsScheduler?.Update(); } /// /// 延迟处理逻辑 /// 更新Deferred调度器 /// private void ProcessDeferred() { _deferredScheduler?.Update(); } #endregion #region 初始化 /// /// 初始化所有调度器和时间源 /// 创建Process、Physics和Deferred三个调度器实例 /// private void InitializeSchedulers() { _processTimeSource = new GodotTimeSource(GetProcessDeltaTime); _physicsTimeSource = new GodotTimeSource(GetPhysicsProcessDeltaTime); _deferredTimeSource = new GodotTimeSource(GetProcessDeltaTime); _processScheduler = new CoroutineScheduler( _processTimeSource, _instanceId ); _physicsScheduler = new CoroutineScheduler( _physicsTimeSource, _instanceId, 128 ); _deferredScheduler = new CoroutineScheduler( _deferredTimeSource, _instanceId, 64 ); } /// /// 注册当前实例到活动实例数组中 /// 如果当前ID已被占用则寻找可用ID /// private void RegisterInstance() { if (ActiveInstances[_instanceId] == null) { ActiveInstances[_instanceId] = this; return; } for (byte i = 1; i < ActiveInstances.Length; i++) if (ActiveInstances[i] == null) { _instanceId = i; ActiveInstances[i] = this; return; } throw new OverflowException("最多只能存在 15 个 Timing 实例"); } /// /// 尝试设置物理处理优先级 /// 使用反射方式设置ProcessPhysicsPriority属性 /// /// 物理处理优先级 private static void TrySetPhysicsPriority(int priority) { try { typeof(Node) .GetProperty( "ProcessPhysicsPriority", BindingFlags.Instance | BindingFlags.Public) ?.SetValue(Instance, priority); } catch { // ignored } } #endregion #region 协程启动 API /// /// 在指定段运行协程 /// /// 要运行的协程枚举器 /// 协程执行段(Process/PhysicsProcess/DeferredProcess) /// 协程标签,用于批量操作 /// 协程句柄 public static CoroutineHandle RunCoroutine( IEnumerator coroutine, Segment segment = Segment.Process, string? tag = null) { return Instance.RunCoroutineOnInstance(coroutine, segment, tag); } /// /// 在当前实例上运行协程 /// 根据指定的段选择对应的调度器运行协程 /// /// 要运行的协程枚举器 /// 协程执行段 /// 协程标签 /// 协程句柄 public CoroutineHandle RunCoroutineOnInstance( IEnumerator? coroutine, Segment segment = Segment.Process, string? tag = null) { if (coroutine == null) return default; return segment switch { Segment.Process => ProcessScheduler.Run(coroutine, tag), Segment.PhysicsProcess => PhysicsScheduler.Run(coroutine, tag), Segment.DeferredProcess => DeferredScheduler.Run(coroutine, tag), _ => default }; } #endregion #region 协程控制 API /// /// 暂停指定的协程 /// /// 协程句柄 /// 是否成功暂停 public static bool PauseCoroutine(CoroutineHandle handle) { return GetInstance(handle.Key)?.PauseOnInstance(handle) ?? false; } /// /// 恢复指定的协程 /// /// 协程句柄 /// 是否成功恢复 public static bool ResumeCoroutine(CoroutineHandle handle) { return GetInstance(handle.Key)?.ResumeOnInstance(handle) ?? false; } /// /// 终止指定的协程 /// /// 协程句柄 /// 是否成功终止 public static bool KillCoroutine(CoroutineHandle handle) { return GetInstance(handle.Key)?.KillOnInstance(handle) ?? false; } /// /// 终止所有具有指定标签的协程 /// /// 协程标签 /// 被终止的协程数量 public static int KillCoroutines(string tag) { return Instance.KillByTagOnInstance(tag); } /// /// 终止所有协程 /// /// 被终止的协程总数 public static int KillAllCoroutines() { return Instance.ClearOnInstance(); } /// /// 在当前实例上暂停协程 /// 尝试在所有调度器中查找并暂停指定协程 /// /// 协程句柄 /// 是否成功暂停 private bool PauseOnInstance(CoroutineHandle handle) { return ProcessScheduler.Pause(handle) || PhysicsScheduler.Pause(handle) || DeferredScheduler.Pause(handle); } /// /// 在当前实例上恢复协程 /// 尝试在所有调度器中查找并恢复指定协程 /// /// 协程句柄 /// 是否成功恢复 private bool ResumeOnInstance(CoroutineHandle handle) { return ProcessScheduler.Resume(handle) || PhysicsScheduler.Resume(handle) || DeferredScheduler.Resume(handle); } /// /// 在当前实例上终止协程 /// 尝试在所有调度器中查找并终止指定协程 /// /// 协程句柄 /// 是否成功终止 private bool KillOnInstance(CoroutineHandle handle) { return ProcessScheduler.Kill(handle) || PhysicsScheduler.Kill(handle) || DeferredScheduler.Kill(handle); } /// /// 在当前实例上根据标签终止协程 /// 在所有调度器中查找并终止具有指定标签的协程 /// /// 协程标签 /// 被终止的协程数量 private int KillByTagOnInstance(string tag) { var count = 0; count += ProcessScheduler.KillByTag(tag); count += PhysicsScheduler.KillByTag(tag); count += DeferredScheduler.KillByTag(tag); return count; } /// /// 清空当前实例上的所有协程 /// 从所有调度器中清除协程 /// /// 被清除的协程总数 private int ClearOnInstance() { var count = 0; count += ProcessScheduler.Clear(); count += PhysicsScheduler.Clear(); count += DeferredScheduler.Clear(); return count; } #endregion #region 工具方法 /// /// 根据ID获取Timing实例 /// /// 实例ID /// 对应的Timing实例或null public static Timing? GetInstance(byte id) { return id < ActiveInstances.Length ? ActiveInstances[id] : null; } /// /// 检查节点是否处于有效状态 /// /// 要检查的节点 /// 如果节点存在且有效则返回true,否则返回false public static bool IsNodeAlive(Node? node) { // 验证节点是否存在、实例是否有效、未被标记为删除且在场景树中 return node != null && IsInstanceValid(node) && !node.IsQueuedForDeletion() && node.IsInsideTree(); } #endregion #region 延迟调用 /// /// 延迟调用指定动作 /// /// 延迟时间(秒) /// 要执行的动作 /// 执行段 /// 协程句柄 public static CoroutineHandle CallDelayed( double delay, Action? action, Segment segment = Segment.Process) { if (action == null) return default; return RunCoroutine(DelayedCallCoroutine(delay, action), segment); } /// /// 延迟调用指定动作,支持取消条件 /// /// 延迟时间(秒) /// 要执行的动作 /// 取消条件节点 /// 执行段 /// 协程句柄 public static CoroutineHandle CallDelayed( double delay, Action? action, Node cancelWith, Segment segment = Segment.Process) { if (action == null) return default; return RunCoroutine( DelayedCallWithCancelCoroutine(delay, action, cancelWith), segment); } /// /// 延迟调用协程实现 /// /// 延迟时间 /// 要执行的动作 /// 协程枚举器 private static IEnumerator DelayedCallCoroutine( double delay, Action action) { yield return new Delay(delay); action(); } /// /// 带取消条件的延迟调用协程实现 /// /// 延迟时间 /// 要执行的动作 /// 取消条件节点 /// 协程枚举器 private static IEnumerator DelayedCallWithCancelCoroutine( double delay, Action action, Node cancelWith) { yield return new Delay(delay); if (IsNodeAlive(cancelWith)) action(); } #endregion }