GFramework/GFramework.Game/coroutine/CoroutineScheduler.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

64 lines
1.8 KiB
C#

using System.Collections;
using GFramework.Game.Abstractions.coroutine;
namespace GFramework.Game.coroutine;
public class CoroutineScheduler : ICoroutineScheduler
{
private readonly List<CoroutineHandle> _active = new();
private readonly List<CoroutineHandle> _toAdd = new();
private readonly HashSet<CoroutineHandle> _toRemove = new();
private int? _ownerThreadId;
public int ActiveCount => _active.Count + _toAdd.Count;
public void Update(float deltaTime)
{
if (_ownerThreadId == null)
{
_ownerThreadId = Thread.CurrentThread.ManagedThreadId;
}
else if (Thread.CurrentThread.ManagedThreadId != _ownerThreadId)
{
throw new InvalidOperationException(
$"CoroutineScheduler must be updated on same thread. " +
$"Owner: {_ownerThreadId}, Current: {Thread.CurrentThread.ManagedThreadId}");
}
if (_toAdd.Count > 0)
{
_active.AddRange(_toAdd);
_toAdd.Clear();
}
for (var i = _active.Count - 1; i >= 0; i--)
{
var c = _active[i];
if (!c.Context.Scope.IsActive)
{
c.Cancel();
_toRemove.Add(c);
continue;
}
((IYieldInstruction)c).Update(deltaTime);
if (c.IsDone)
_toRemove.Add(c);
}
if (_toRemove.Count <= 0) return;
_active.RemoveAll(c => _toRemove.Contains(c));
_toRemove.Clear();
}
internal CoroutineHandle StartCoroutine(IEnumerator routine, CoroutineContext context)
{
var handle = new CoroutineHandle(routine, context, null);
_toAdd.Add(handle);
return handle;
}
internal void RemoveCoroutine(CoroutineHandle handle) => _toRemove.Add(handle);
}