饭太稀

This commit is contained in:
bob
2025-06-30 10:51:37 +08:00
commit 8e45469c83
753 changed files with 87652 additions and 0 deletions

View File

@@ -0,0 +1,140 @@
using System;
using System.Collections.Generic;
using Fantasy.Pool;
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type.
namespace Fantasy.Async
{
/// <summary>
/// 协程锁专用的对象池
/// </summary>
public sealed class CoroutineLockPool : PoolCore<CoroutineLock>
{
/// <summary>
/// 协程锁专用的对象池的构造函数
/// </summary>
public CoroutineLockPool() : base(2000) { }
}
/// <summary>
/// 协程锁
/// </summary>
public sealed class CoroutineLock : IPool, IDisposable
{
private Scene _scene;
private CoroutineLockComponent _coroutineLockComponent;
private readonly Dictionary<long, CoroutineLockQueue> _queue = new Dictionary<long, CoroutineLockQueue>();
/// <summary>
/// 表示是否是对象池中创建的
/// </summary>
private bool _isPool;
/// <summary>
/// 协程锁的类型
/// </summary>
public long CoroutineLockType { get; private set; }
internal void Initialize(CoroutineLockComponent coroutineLockComponent, ref long coroutineLockType)
{
_scene = coroutineLockComponent.Scene;
CoroutineLockType = coroutineLockType;
_coroutineLockComponent = coroutineLockComponent;
}
/// <summary>
/// 销毁协程锁,如果调用了该方法,所有使用当前协程锁等待的逻辑会按照顺序释放锁。
/// </summary>
public void Dispose()
{
foreach (var (_, coroutineLockQueue) in _queue)
{
while (TryCoroutineLockQueueDequeue(coroutineLockQueue)) { }
}
_queue.Clear();
_scene = null;
CoroutineLockType = 0;
_coroutineLockComponent = null;
}
/// <summary>
/// 等待上一个任务完成
/// </summary>
/// <param name="coroutineLockQueueKey">需要等待的Id</param>
/// <param name="tag">用于查询协程锁的标记,可不传入,只有在超时的时候排查是哪个锁超时时使用</param>
/// <param name="timeOut">等待多久会超时,当到达设定的时候会把当前锁给按照超时处理</param>
/// <returns></returns>
public async FTask<WaitCoroutineLock> Wait(long coroutineLockQueueKey, string tag = null, int timeOut = 30000)
{
var waitCoroutineLock = _coroutineLockComponent.WaitCoroutineLockPool.Rent(this, ref coroutineLockQueueKey, tag, timeOut);
if (!_queue.TryGetValue(coroutineLockQueueKey, out var queue))
{
queue = _coroutineLockComponent.CoroutineLockQueuePool.Rent();
_queue.Add(coroutineLockQueueKey, queue);
return waitCoroutineLock;
}
queue.Enqueue(waitCoroutineLock);
return await waitCoroutineLock.Tcs;
}
/// <summary>
/// 按照先入先出的顺序,释放最早的一个协程锁
/// </summary>
/// <param name="coroutineLockQueueKey"></param>
public void Release(long coroutineLockQueueKey)
{
if (!_queue.TryGetValue(coroutineLockQueueKey, out var coroutineLockQueue))
{
return;
}
if (!TryCoroutineLockQueueDequeue(coroutineLockQueue))
{
_queue.Remove(coroutineLockQueueKey);
}
}
private bool TryCoroutineLockQueueDequeue(CoroutineLockQueue coroutineLockQueue)
{
if (!coroutineLockQueue.TryDequeue(out var waitCoroutineLock))
{
_coroutineLockComponent.CoroutineLockQueuePool.Return(coroutineLockQueue);
return false;
}
if (waitCoroutineLock.TimerId != 0)
{
_scene.TimerComponent.Net.Remove(waitCoroutineLock.TimerId);
}
try
{
// 放到下一帧执行,如果不这样会导致逻辑的顺序不正常。
_scene.ThreadSynchronizationContext.Post(waitCoroutineLock.SetResult);
}
catch (Exception e)
{
Log.Error($"Error in disposing CoroutineLock: {e}");
}
return true;
}
/// <summary>
/// 获取一个值,该值指示当前实例是否为对象池中的实例。
/// </summary>
/// <returns></returns>
public bool IsPool()
{
return _isPool;
}
/// <summary>
/// 设置一个值,该值指示当前实例是否为对象池中的实例。
/// </summary>
/// <param name="isPool"></param>
public void SetIsPool(bool isPool)
{
_isPool = isPool;
}
}
}

View File

@@ -0,0 +1,100 @@
using System.Collections.Generic;
using Fantasy.Entitas;
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type.
namespace Fantasy.Async
{
/// <summary>
/// 协程锁组件
/// </summary>
public class CoroutineLockComponent : Entity
{
private long _lockId;
private CoroutineLockPool _coroutineLockPool;
internal WaitCoroutineLockPool WaitCoroutineLockPool { get; private set; }
internal CoroutineLockQueuePool CoroutineLockQueuePool { get; private set; }
private readonly Dictionary<long, CoroutineLock> _coroutineLocks = new Dictionary<long, CoroutineLock>();
internal CoroutineLockComponent Initialize()
{
_coroutineLockPool = new CoroutineLockPool();
CoroutineLockQueuePool = new CoroutineLockQueuePool();
WaitCoroutineLockPool = new WaitCoroutineLockPool(this);
return this;
}
internal long LockId => ++_lockId;
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
public override void Dispose()
#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member
{
if (IsDisposed)
{
return;
}
_lockId = 0;
base.Dispose();
}
/// <summary>
/// 创建一个新的协程锁
/// 使用这个方法创建的协程锁需要手动释放管理CoroutineLock。
/// 不会再CoroutineLockComponent理进行管理。
/// </summary>
/// <param name="coroutineLockType"></param>
/// <returns></returns>
public CoroutineLock Create(long coroutineLockType)
{
var coroutineLock = _coroutineLockPool.Rent();
coroutineLock.Initialize(this, ref coroutineLockType);
return coroutineLock;
}
/// <summary>
/// 请求一个协程锁。
/// 使用这个方法创建的协程锁会自动释放CoroutineLockQueueType。
/// </summary>
/// <param name="coroutineLockType">锁类型</param>
/// <param name="coroutineLockQueueKey">锁队列Id</param>
/// <param name="tag">当某些锁超时需要一个标记来方便排查问题正常的情况下这个默认为null就可以。</param>
/// <param name="time">设置锁的超时时间,让超过设置的时间会触发超时,保证锁不会因为某一个锁一直不解锁导致卡住的问题。</param>
/// <returns>
/// 返回的WaitCoroutineLock通过Dispose来解除这个锁、建议用using来保住这个锁。
/// 也可以返回的WaitCoroutineLock通过CoroutineLockComponent.UnLock来解除这个锁。
/// </returns>
public FTask<WaitCoroutineLock> Wait(long coroutineLockType, long coroutineLockQueueKey, string tag = null, int time = 30000)
{
if (!_coroutineLocks.TryGetValue(coroutineLockType, out var coroutineLock))
{
coroutineLock = _coroutineLockPool.Rent();
coroutineLock.Initialize(this, ref coroutineLockType);
_coroutineLocks.Add(coroutineLockType, coroutineLock);
}
return coroutineLock.Wait(coroutineLockQueueKey, tag, time);
}
/// <summary>
/// 解除一个协程锁。
/// </summary>
/// <param name="coroutineLockType"></param>
/// <param name="coroutineLockQueueKey"></param>
public void Release(int coroutineLockType, long coroutineLockQueueKey)
{
if (IsDisposed)
{
return;
}
if (!_coroutineLocks.TryGetValue(coroutineLockType, out var coroutineLock))
{
return;
}
coroutineLock.Release(coroutineLockQueueKey);
}
}
}

View File

@@ -0,0 +1,35 @@
// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
using System.Collections.Generic;
using Fantasy.Pool;
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type.
namespace Fantasy.Async
{
internal sealed class CoroutineLockQueuePool : PoolCore<CoroutineLockQueue>
{
public CoroutineLockQueuePool() : base(2000) { }
}
internal sealed class CoroutineLockQueue : Queue<WaitCoroutineLock>, IPool
{
private bool _isPool;
/// <summary>
/// 获取一个值,该值指示当前实例是否为对象池中的实例。
/// </summary>
/// <returns></returns>
public bool IsPool()
{
return _isPool;
}
/// <summary>
/// 设置一个值,该值指示当前实例是否为对象池中的实例。
/// </summary>
/// <param name="isPool"></param>
public void SetIsPool(bool isPool)
{
_isPool = isPool;
}
}
}

View File

@@ -0,0 +1,146 @@
using System;
using Fantasy.Event;
using Fantasy.Pool;
#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type.
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
namespace Fantasy.Async
{
internal sealed class WaitCoroutineLockPool : PoolCore<WaitCoroutineLock>
{
private readonly Scene _scene;
private readonly CoroutineLockComponent _coroutineLockComponent;
public WaitCoroutineLockPool(CoroutineLockComponent coroutineLockComponent) : base(2000)
{
_scene = coroutineLockComponent.Scene;
_coroutineLockComponent = coroutineLockComponent;
}
public WaitCoroutineLock Rent(CoroutineLock coroutineLock, ref long coroutineLockQueueKey, string tag = null, int timeOut = 30000)
{
var timerId = 0L;
var lockId = _coroutineLockComponent.LockId;
var waitCoroutineLock = _coroutineLockComponent.WaitCoroutineLockPool.Rent();
if (timeOut > 0)
{
timerId = _scene.TimerComponent.Net.OnceTimer(timeOut, new CoroutineLockTimeout(ref lockId, waitCoroutineLock));
}
waitCoroutineLock.Initialize(coroutineLock, this, ref coroutineLockQueueKey, ref timerId, ref lockId, tag);
return waitCoroutineLock;
}
}
internal struct CoroutineLockTimeout
{
public readonly long LockId;
public readonly WaitCoroutineLock WaitCoroutineLock;
public CoroutineLockTimeout(ref long lockId, WaitCoroutineLock waitCoroutineLock)
{
LockId = lockId;
WaitCoroutineLock = waitCoroutineLock;
}
}
internal sealed class OnCoroutineLockTimeout : EventSystem<CoroutineLockTimeout>
{
protected override void Handler(CoroutineLockTimeout self)
{
var selfWaitCoroutineLock = self.WaitCoroutineLock;
if (self.LockId != selfWaitCoroutineLock.LockId)
{
return;
}
Log.Error($"coroutine lock timeout CoroutineLockQueueType:{selfWaitCoroutineLock.CoroutineLock.CoroutineLockType} Key:{selfWaitCoroutineLock.CoroutineLockQueueKey} Tag:{selfWaitCoroutineLock.Tag}");
}
}
/// <summary>
/// 一个协程锁的实例,用户可以用过这个手动释放锁
/// </summary>
public sealed class WaitCoroutineLock : IPool, IDisposable
{
private bool _isPool;
internal string Tag { get; private set; }
internal long LockId { get; private set; }
internal long TimerId { get; private set; }
internal long CoroutineLockQueueKey { get; private set; }
internal CoroutineLock CoroutineLock { get; private set; }
private bool _isSetResult;
private FTask<WaitCoroutineLock> _tcs;
private WaitCoroutineLockPool _waitCoroutineLockPool;
internal void Initialize(CoroutineLock coroutineLock, WaitCoroutineLockPool waitCoroutineLockPool, ref long coroutineLockQueueKey, ref long timerId, ref long lockId, string tag)
{
Tag = tag;
LockId = lockId;
TimerId = timerId;
CoroutineLock = coroutineLock;
CoroutineLockQueueKey = coroutineLockQueueKey;
_waitCoroutineLockPool = waitCoroutineLockPool;
}
/// <summary>
/// 释放协程锁
/// </summary>
public void Dispose()
{
if (LockId == 0)
{
Log.Error("WaitCoroutineLock is already disposed");
return;
}
CoroutineLock.Release(CoroutineLockQueueKey);
_tcs = null;
Tag = null;
LockId = 0;
TimerId = 0;
_isSetResult = false;
CoroutineLockQueueKey = 0;
_waitCoroutineLockPool.Return(this);
CoroutineLock = null;
_waitCoroutineLockPool = null;
}
internal FTask<WaitCoroutineLock> Tcs
{
get { return _tcs ??= FTask<WaitCoroutineLock>.Create(); }
}
internal void SetResult()
{
if (_isSetResult)
{
Log.Error("WaitCoroutineLock is already SetResult");
return;
}
_isSetResult = true;
Tcs.SetResult(this);
}
/// <summary>
/// 获取一个值,该值指示当前实例是否为对象池中的实例。
/// </summary>
/// <returns></returns>
public bool IsPool()
{
return _isPool;
}
/// <summary>
/// 设置一个值,该值指示当前实例是否为对象池中的实例。
/// </summary>
/// <param name="isPool"></param>
public void SetIsPool(bool isPool)
{
_isPool = isPool;
}
}
}

View File

@@ -0,0 +1,471 @@
// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
using Fantasy.Assembly;
using Fantasy.Async;
using Fantasy.DataStructure.Collection;
using Fantasy.Entitas;
using Fantasy.Entitas.Interface;
using Fantasy.Helper;
#pragma warning disable CS8602 // Dereference of a possibly null reference.
#pragma warning disable CS8765 // Nullability of type of parameter doesn't match overridden member (possibly because of nullability attributes).
#pragma warning disable CS8604 // Possible null reference argument.
#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type.
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
namespace Fantasy.Entitas
{
internal sealed class UpdateQueueInfo
{
public bool IsStop;
public readonly Type Type;
public readonly long RunTimeId;
public UpdateQueueInfo(Type type, long runTimeId)
{
Type = type;
IsStop = false;
RunTimeId = runTimeId;
}
}
internal sealed class FrameUpdateQueueInfo
{
public readonly Type Type;
public readonly long RunTimeId;
public FrameUpdateQueueInfo(Type type, long runTimeId)
{
Type = type;
RunTimeId = runTimeId;
}
}
internal struct CustomEntitiesSystemKey : IEquatable<CustomEntitiesSystemKey>
{
public int CustomEventType { get; }
public Type EntitiesType { get; }
public CustomEntitiesSystemKey(int customEventType, Type entitiesType)
{
CustomEventType = customEventType;
EntitiesType = entitiesType;
}
public bool Equals(CustomEntitiesSystemKey other)
{
return CustomEventType == other.CustomEventType && EntitiesType == other.EntitiesType;
}
public override bool Equals(object obj)
{
return obj is CustomEntitiesSystemKey other && Equals(other);
}
public override int GetHashCode()
{
return HashCode.Combine(CustomEventType, EntitiesType);
}
}
/// <summary>
/// Entity管理组件
/// </summary>
public sealed class EntityComponent : Entity, ISceneUpdate, IAssembly
{
private readonly OneToManyList<long, Type> _assemblyList = new();
private readonly OneToManyList<long, Type> _assemblyHashCodes = new();
private readonly Dictionary<Type, IAwakeSystem> _awakeSystems = new();
private readonly Dictionary<Type, IUpdateSystem> _updateSystems = new();
private readonly Dictionary<Type, IDestroySystem> _destroySystems = new();
private readonly Dictionary<Type, IDeserializeSystem> _deserializeSystems = new();
private readonly Dictionary<Type, IFrameUpdateSystem> _frameUpdateSystem = new();
private readonly OneToManyList<long, CustomEntitiesSystemKey> _assemblyCustomSystemList = new();
private readonly Dictionary<CustomEntitiesSystemKey, ICustomEntitiesSystem> _customEntitiesSystems = new Dictionary<CustomEntitiesSystemKey, ICustomEntitiesSystem>();
private readonly Dictionary<Type, long> _hashCodes = new Dictionary<Type, long>();
private readonly Queue<UpdateQueueInfo> _updateQueue = new Queue<UpdateQueueInfo>();
private readonly Queue<FrameUpdateQueueInfo> _frameUpdateQueue = new Queue<FrameUpdateQueueInfo>();
private readonly Dictionary<long, UpdateQueueInfo> _updateQueueDic = new Dictionary<long, UpdateQueueInfo>();
internal async FTask<EntityComponent> Initialize()
{
await AssemblySystem.Register(this);
return this;
}
#region Assembly
public FTask Load(long assemblyIdentity)
{
var task = FTask.Create(false);
Scene?.ThreadSynchronizationContext.Post(() =>
{
LoadInner(assemblyIdentity);
task.SetResult();
});
return task;
}
public FTask ReLoad(long assemblyIdentity)
{
var task = FTask.Create(false);
Scene?.ThreadSynchronizationContext.Post(() =>
{
OnUnLoadInner(assemblyIdentity);
LoadInner(assemblyIdentity);
task.SetResult();
});
return task;
}
public FTask OnUnLoad(long assemblyIdentity)
{
var task = FTask.Create(false);
Scene?.ThreadSynchronizationContext.Post(() =>
{
OnUnLoadInner(assemblyIdentity);
task.SetResult();
});
return task;
}
private void LoadInner(long assemblyIdentity)
{
foreach (var entityType in AssemblySystem.ForEach(assemblyIdentity, typeof(IEntity)))
{
_hashCodes.Add(entityType, HashCodeHelper.ComputeHash64(entityType.FullName));
_assemblyHashCodes.Add(assemblyIdentity, entityType);
}
foreach (var entitiesSystemType in AssemblySystem.ForEach(assemblyIdentity, typeof(IEntitiesSystem)))
{
Type entitiesType = null;
var entity = Activator.CreateInstance(entitiesSystemType);
switch (entity)
{
case IAwakeSystem iAwakeSystem:
{
entitiesType = iAwakeSystem.EntitiesType();
_awakeSystems.Add(entitiesType, iAwakeSystem);
break;
}
case IDestroySystem iDestroySystem:
{
entitiesType = iDestroySystem.EntitiesType();
_destroySystems.Add(entitiesType, iDestroySystem);
break;
}
case IDeserializeSystem iDeserializeSystem:
{
entitiesType = iDeserializeSystem.EntitiesType();
_deserializeSystems.Add(entitiesType, iDeserializeSystem);
break;
}
case IUpdateSystem iUpdateSystem:
{
entitiesType = iUpdateSystem.EntitiesType();
_updateSystems.Add(entitiesType, iUpdateSystem);
break;
}
case IFrameUpdateSystem iFrameUpdateSystem:
{
entitiesType = iFrameUpdateSystem.EntitiesType();
_frameUpdateSystem.Add(entitiesType, iFrameUpdateSystem);
break;
}
default:
{
Log.Error($"IEntitiesSystem not support type {entitiesSystemType}");
return;
}
}
_assemblyList.Add(assemblyIdentity, entitiesType);
}
foreach (var customEntitiesSystemType in AssemblySystem.ForEach(assemblyIdentity, typeof(ICustomEntitiesSystem)))
{
var entity = (ICustomEntitiesSystem)Activator.CreateInstance(customEntitiesSystemType);
var customEntitiesSystemKey = new CustomEntitiesSystemKey(entity.CustomEventType, entity.EntitiesType());
_customEntitiesSystems.Add(customEntitiesSystemKey, entity);
_assemblyCustomSystemList.Add(assemblyIdentity, customEntitiesSystemKey);
}
}
private void OnUnLoadInner(long assemblyIdentity)
{
if (_assemblyHashCodes.TryGetValue(assemblyIdentity, out var entityType))
{
foreach (var type in entityType)
{
_hashCodes.Remove(type);
}
_assemblyHashCodes.RemoveByKey(assemblyIdentity);
}
if (_assemblyList.TryGetValue(assemblyIdentity, out var assembly))
{
foreach (var type in assembly)
{
_awakeSystems.Remove(type);
_updateSystems.Remove(type);
_destroySystems.Remove(type);
_deserializeSystems.Remove(type);
_frameUpdateSystem.Remove(type);
}
_assemblyList.RemoveByKey(assemblyIdentity);
}
if (_assemblyCustomSystemList.TryGetValue(assemblyIdentity, out var customSystemAssembly))
{
foreach (var customEntitiesSystemKey in customSystemAssembly)
{
_customEntitiesSystems.Remove(customEntitiesSystemKey);
}
_assemblyCustomSystemList.RemoveByKey(assemblyIdentity);
}
}
#endregion
#region Event
/// <summary>
/// 触发实体的唤醒方法
/// </summary>
/// <param name="entity">实体对象</param>
public void Awake(Entity entity)
{
if (!_awakeSystems.TryGetValue(entity.Type, out var awakeSystem))
{
return;
}
try
{
awakeSystem.Invoke(entity);
}
catch (Exception e)
{
Log.Error($"{entity.Type.FullName} Error {e}");
}
}
/// <summary>
/// 触发实体的销毁方法
/// </summary>
/// <param name="entity">实体对象</param>
public void Destroy(Entity entity)
{
if (!_destroySystems.TryGetValue(entity.Type, out var system))
{
return;
}
try
{
system.Invoke(entity);
}
catch (Exception e)
{
Log.Error($"{entity.Type.FullName} Destroy Error {e}");
}
}
/// <summary>
/// 触发实体的反序列化方法
/// </summary>
/// <param name="entity">实体对象</param>
public void Deserialize(Entity entity)
{
if (!_deserializeSystems.TryGetValue(entity.Type, out var system))
{
return;
}
try
{
system.Invoke(entity);
}
catch (Exception e)
{
Log.Error($"{entity.Type.FullName} Deserialize Error {e}");
}
}
#endregion
#region CustomEvent
public void CustomSystem(Entity entity, int customEventType)
{
var customEntitiesSystemKey = new CustomEntitiesSystemKey(customEventType, entity.Type);
if (!_customEntitiesSystems.TryGetValue(customEntitiesSystemKey, out var system))
{
return;
}
try
{
system.Invoke(entity);
}
catch (Exception e)
{
Log.Error($"{entity.Type.FullName} CustomSystem Error {e}");
}
}
#endregion
#region Update
/// <summary>
/// 将实体加入更新队列,准备进行更新
/// </summary>
/// <param name="entity">实体对象</param>
public void StartUpdate(Entity entity)
{
var type = entity.Type;
var entityRuntimeId = entity.RuntimeId;
if (_updateSystems.ContainsKey(type))
{
var updateQueueInfo = new UpdateQueueInfo(type, entityRuntimeId);
_updateQueue.Enqueue(updateQueueInfo);
_updateQueueDic.Add(entityRuntimeId, updateQueueInfo);
}
if (_frameUpdateSystem.ContainsKey(type))
{
_frameUpdateQueue.Enqueue(new FrameUpdateQueueInfo(type, entityRuntimeId));
}
}
/// <summary>
/// 停止实体进行更新
/// </summary>
/// <param name="entity">实体对象</param>
public void StopUpdate(Entity entity)
{
if (!_updateQueueDic.Remove(entity.RuntimeId, out var updateQueueInfo))
{
return;
}
updateQueueInfo.IsStop = true;
}
/// <summary>
/// 执行实体系统的更新逻辑
/// </summary>
public void Update()
{
var updateQueueCount = _updateQueue.Count;
while (updateQueueCount-- > 0)
{
var updateQueueStruct = _updateQueue.Dequeue();
if (updateQueueStruct.IsStop)
{
continue;
}
if (!_updateSystems.TryGetValue(updateQueueStruct.Type, out var updateSystem))
{
continue;
}
var entity = Scene.GetEntity(updateQueueStruct.RunTimeId);
if (entity == null || entity.IsDisposed)
{
_updateQueueDic.Remove(updateQueueStruct.RunTimeId);
continue;
}
_updateQueue.Enqueue(updateQueueStruct);
try
{
updateSystem.Invoke(entity);
}
catch (Exception e)
{
Log.Error($"{updateQueueStruct.Type.FullName} Update Error {e}");
}
}
}
/// <summary>
/// 执行实体系统的帧更新逻辑
/// </summary>
public void FrameUpdate()
{
var count = _frameUpdateQueue.Count;
while (count-- > 0)
{
var frameUpdateQueueStruct = _frameUpdateQueue.Dequeue();
if (!_frameUpdateSystem.TryGetValue(frameUpdateQueueStruct.Type, out var frameUpdateSystem))
{
continue;
}
var entity = Scene.GetEntity(frameUpdateQueueStruct.RunTimeId);
if (entity == null || entity.IsDisposed)
{
continue;
}
_frameUpdateQueue.Enqueue(frameUpdateQueueStruct);
try
{
frameUpdateSystem.Invoke(entity);
}
catch (Exception e)
{
Log.Error($"{frameUpdateQueueStruct.Type.FullName} FrameUpdate Error {e}");
}
}
}
#endregion
public long GetHashCode(Type type)
{
return _hashCodes[type];
}
/// <summary>
/// 释放实体系统管理器资源
/// </summary>
public override void Dispose()
{
_updateQueue.Clear();
_frameUpdateQueue.Clear();
_assemblyList.Clear();
_awakeSystems.Clear();
_updateSystems.Clear();
_destroySystems.Clear();
_deserializeSystems.Clear();
_frameUpdateSystem.Clear();
AssemblySystem.UnRegister(this);
base.Dispose();
}
}
}

View File

@@ -0,0 +1,252 @@
using System;
using System.Reflection;
using Fantasy.Assembly;
using Fantasy.Async;
using Fantasy.DataStructure.Collection;
using Fantasy.Entitas;
// ReSharper disable PossibleMultipleEnumeration
#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type.
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
// ReSharper disable MethodOverloadWithOptionalParameter
namespace Fantasy.Event
{
internal sealed class EventCache
{
public readonly Type EnventType;
public readonly object Obj;
public EventCache(Type enventType, object obj)
{
EnventType = enventType;
Obj = obj;
}
}
public sealed class EventComponent : Entity, IAssembly
{
private readonly OneToManyList<Type, IEvent> _events = new();
private readonly OneToManyList<Type, IAsyncEvent> _asyncEvents = new();
private readonly OneToManyList<long, EventCache> _assemblyEvents = new();
private readonly OneToManyList<long, EventCache> _assemblyAsyncEvents = new();
internal async FTask<EventComponent> Initialize()
{
await AssemblySystem.Register(this);
return this;
}
#region Assembly
public async FTask Load(long assemblyIdentity)
{
var tcs = FTask.Create(false);
Scene?.ThreadSynchronizationContext.Post(() =>
{
LoadInner(assemblyIdentity);
tcs.SetResult();
});
await tcs;
}
public async FTask ReLoad(long assemblyIdentity)
{
var tcs = FTask.Create(false);
Scene?.ThreadSynchronizationContext.Post(() =>
{
OnUnLoadInner(assemblyIdentity);
LoadInner(assemblyIdentity);
tcs.SetResult();
});
await tcs;
}
public async FTask OnUnLoad(long assemblyIdentity)
{
var tcs = FTask.Create(false);
Scene?.ThreadSynchronizationContext.Post(() =>
{
OnUnLoadInner(assemblyIdentity);
tcs.SetResult();
});
await tcs;
}
private void LoadInner(long assemblyIdentity)
{
foreach (var type in AssemblySystem.ForEach(assemblyIdentity, typeof(IEvent)))
{
var @event = (IEvent)Activator.CreateInstance(type);
if (@event == null)
{
continue;
}
var eventType = @event.EventType();
_events.Add(eventType, @event);
_assemblyEvents.Add(assemblyIdentity, new EventCache(eventType, @event));
}
foreach (var type in AssemblySystem.ForEach(assemblyIdentity, typeof(IAsyncEvent)))
{
var @event = (IAsyncEvent)Activator.CreateInstance(type);
if (@event == null)
{
continue;
}
var eventType = @event.EventType();
_asyncEvents.Add(eventType, @event);
_assemblyAsyncEvents.Add(assemblyIdentity, new EventCache(eventType, @event));
}
}
private void OnUnLoadInner(long assemblyIdentity)
{
if (_assemblyEvents.TryGetValue(assemblyIdentity, out var events))
{
foreach (var @event in events)
{
_events.RemoveValue(@event.EnventType, (IEvent)@event.Obj);
}
_assemblyEvents.RemoveByKey(assemblyIdentity);
}
if (_assemblyAsyncEvents.TryGetValue(assemblyIdentity, out var asyncEvents))
{
foreach (var @event in asyncEvents)
{
_asyncEvents.RemoveValue(@event.EnventType, (IAsyncEvent)@event.Obj);
}
_assemblyAsyncEvents.RemoveByKey(assemblyIdentity);
}
}
#endregion
#region Publish
/// <summary>
/// 发布一个值类型的事件数据。
/// </summary>
/// <typeparam name="TEventData">事件数据类型(值类型)。</typeparam>
/// <param name="eventData">事件数据实例。</param>
public void Publish<TEventData>(TEventData eventData) where TEventData : struct
{
if (!_events.TryGetValue(typeof(TEventData), out var list))
{
return;
}
foreach (var @event in list)
{
try
{
@event.Invoke(eventData);
}
catch (Exception e)
{
Log.Error(e);
}
}
}
/// <summary>
/// 发布一个继承自 Entity 的事件数据。
/// </summary>
/// <typeparam name="TEventData">事件数据类型(继承自 Entity。</typeparam>
/// <param name="eventData">事件数据实例。</param>
/// <param name="isDisposed">是否释放事件数据。</param>
public void Publish<TEventData>(TEventData eventData, bool isDisposed = true) where TEventData : Entity
{
if (!_events.TryGetValue(typeof(TEventData), out var list))
{
return;
}
foreach (var @event in list)
{
try
{
@event.Invoke(eventData);
}
catch (Exception e)
{
Log.Error(e);
}
}
if (isDisposed)
{
eventData.Dispose();
}
}
/// <summary>
/// 异步发布一个值类型的事件数据。
/// </summary>
/// <typeparam name="TEventData">事件数据类型(值类型)。</typeparam>
/// <param name="eventData">事件数据实例。</param>
/// <returns>表示异步操作的任务。</returns>
public async FTask PublishAsync<TEventData>(TEventData eventData) where TEventData : struct
{
if (!_asyncEvents.TryGetValue(typeof(TEventData), out var list))
{
return;
}
using var tasks = ListPool<FTask>.Create();
foreach (var @event in list)
{
tasks.Add(@event.InvokeAsync(eventData));
}
await FTask.WaitAll(tasks);
}
/// <summary>
/// 异步发布一个继承自 Entity 的事件数据。
/// </summary>
/// <typeparam name="TEventData">事件数据类型(继承自 Entity。</typeparam>
/// <param name="eventData">事件数据实例。</param>
/// <param name="isDisposed">是否释放事件数据。</param>
/// <returns>表示异步操作的任务。</returns>
public async FTask PublishAsync<TEventData>(TEventData eventData, bool isDisposed = true) where TEventData : Entity
{
if (!_asyncEvents.TryGetValue(eventData.GetType(), out var list))
{
return;
}
using var tasks = ListPool<FTask>.Create();
foreach (var @event in list)
{
tasks.Add(@event.InvokeAsync(eventData));
}
await FTask.WaitAll(tasks);
if (isDisposed)
{
eventData.Dispose();
}
}
#endregion
public override void Dispose()
{
_events.Clear();
_asyncEvents.Clear();
_assemblyEvents.Clear();
_assemblyAsyncEvents.Clear();
base.Dispose();
}
}
}

View File

@@ -0,0 +1,112 @@
using System;
using Fantasy.Async;
namespace Fantasy.Event
{
/// <summary>
/// 事件的接口
/// </summary>
public interface IEvent
{
/// <summary>
/// 用于指定事件的Type
/// </summary>
/// <returns></returns>
Type EventType();
/// <summary>
/// 时间内部使用的入口
/// </summary>
/// <param name="self"></param>
void Invoke(object self);
}
/// <summary>
/// 异步事件的接口
/// </summary>
public interface IAsyncEvent
{
/// <summary>
/// <see cref="IEvent.EventType"/>
/// </summary>
/// <returns></returns>
Type EventType();
/// <summary>
/// <see cref="IEvent.Invoke"/>
/// </summary>
/// <returns></returns>
FTask InvokeAsync(object self);
}
/// <summary>
/// 事件的抽象类,要使用事件必须要继承这个抽象接口。
/// </summary>
/// <typeparam name="T">要监听的事件泛型类型</typeparam>
public abstract class EventSystem<T> : IEvent
{
private readonly Type _selfType = typeof(T);
/// <summary>
/// <see cref="IEvent.EventType"/>
/// </summary>
/// <returns></returns>
public Type EventType()
{
return _selfType;
}
/// <summary>
/// 事件调用的方法,要在这个方法里编写事件发生的逻辑
/// </summary>
/// <param name="self"></param>
protected abstract void Handler(T self);
/// <summary>
/// <see cref="IEvent.Invoke"/>
/// </summary>
/// <returns></returns>
public void Invoke(object self)
{
try
{
Handler((T) self);
}
catch (Exception e)
{
Log.Error($"{_selfType.Name} Error {e}");
}
}
}
/// <summary>
/// 异步事件的抽象类,要使用事件必须要继承这个抽象接口。
/// </summary>
/// <typeparam name="T">要监听的事件泛型类型</typeparam>
public abstract class AsyncEventSystem<T> : IAsyncEvent
{
private readonly Type _selfType = typeof(T);
/// <summary>
/// <see cref="IEvent.EventType"/>
/// </summary>
/// <returns></returns>
public Type EventType()
{
return _selfType;
}
/// <summary>
/// 事件调用的方法,要在这个方法里编写事件发生的逻辑
/// </summary>
/// <param name="self"></param>
protected abstract FTask Handler(T self);
/// <summary>
/// <see cref="IEvent.Invoke"/>
/// </summary>
/// <returns></returns>
public async FTask InvokeAsync(object self)
{
try
{
await Handler((T) self);
}
catch (Exception e)
{
Log.Error($"{_selfType.Name} Error {e}");
}
}
}
}

View File

@@ -0,0 +1,139 @@
// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using Fantasy.DataStructure.Collection;
using Fantasy.Entitas;
using Fantasy.Pool;
using Fantasy.Serialize;
namespace Fantasy.Entitas
{
/// <summary>
/// 消息的对象池组件
/// </summary>
public sealed class MessagePoolComponent : Entity
{
private int _poolCount;
private const int MaxCapacity = ushort.MaxValue;
private readonly OneToManyQueue<Type, AMessage> _poolQueue = new OneToManyQueue<Type, AMessage>();
private readonly Dictionary<Type, Func<AMessage>> _typeCheckCache = new Dictionary<Type, Func<AMessage>>();
/// <summary>
/// 销毁组件
/// </summary>
public override void Dispose()
{
_poolCount = 0;
_poolQueue.Clear();
_typeCheckCache.Clear();
base.Dispose();
}
/// <summary>
/// 从对象池里获取一个消息,如果没有就创建一个新的
/// </summary>
/// <typeparam name="T">消息的泛型类型</typeparam>
/// <returns></returns>
public T Rent<T>() where T : AMessage, new()
{
if (!_poolQueue.TryDequeue(typeof(T), out var queue))
{
var instance = new T();
instance.SetScene(Scene);
instance.SetIsPool(true);
return instance;
}
queue.SetIsPool(true);
_poolCount--;
return (T)queue;
}
/// <summary>
/// <see cref="Rent"/>
/// </summary>
/// <param name="type">消息的类型</param>
/// <returns></returns>
/// <exception cref="NotSupportedException"></exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public AMessage Rent(Type type)
{
if (!_poolQueue.TryDequeue(type, out var queue))
{
if (!_typeCheckCache.TryGetValue(type, out var createInstance))
{
if (!typeof(AMessage).IsAssignableFrom(type))
{
throw new NotSupportedException($"{this.GetType().FullName} Type:{type.FullName} must inherit from IPool");
}
else
{
createInstance = CreateInstance.CreateMessage(type);
_typeCheckCache[type] = createInstance;
}
}
var instance = createInstance();
instance.SetScene(Scene);
instance.SetIsPool(true);
return instance;
}
queue.SetIsPool(true);
_poolCount--;
return queue;
}
/// <summary>
/// 返还一个消息到对象池中
/// </summary>
/// <param name="obj"></param>
public void Return(AMessage obj)
{
if (obj == null)
{
return;
}
if (!obj.IsPool())
{
return;
}
if (_poolCount >= MaxCapacity)
{
return;
}
_poolCount++;
obj.SetIsPool(false);
_poolQueue.Enqueue(obj.GetType(), obj);
}
/// <summary>
/// <see cref="Return"/>
/// </summary>
/// <param name="obj">返还的消息</param>
/// <typeparam name="T">返还的消息泛型类型</typeparam>
public void Return<T>(T obj) where T : AMessage
{
if (obj == null)
{
return;
}
if (!obj.IsPool())
{
return;
}
if (_poolCount >= MaxCapacity)
{
return;
}
_poolCount++;
obj.SetIsPool(false);
_poolQueue.Enqueue(typeof(T), obj);
}
}
}

View File

@@ -0,0 +1,167 @@
// ReSharper disable SuspiciousTypeConversion.Global
using Fantasy.Assembly;
using Fantasy.Async;
using Fantasy.DataStructure.Collection;
using Fantasy.Entitas;
using Fantasy.Entitas.Interface;
using Fantasy.Helper;
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
#pragma warning disable CS8604 // Possible null reference argument.
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
#if FANTASY_NET
namespace Fantasy.SingleCollection
{
/// <summary>
/// 用于处理Entity下的实体进行数据库分表存储的组件
/// </summary>
public sealed class SingleCollectionComponent : Entity, IAssembly
{
private CoroutineLock _coroutineLock;
private readonly OneToManyHashSet<Type, string> _collection = new OneToManyHashSet<Type, string>();
private readonly OneToManyList<long, SingleCollectionInfo> _assemblyCollections =
new OneToManyList<long, SingleCollectionInfo>();
private sealed class SingleCollectionInfo(Type rootType, string collectionName)
{
public readonly Type RootType = rootType;
public readonly string CollectionName = collectionName;
}
internal async FTask<SingleCollectionComponent> Initialize()
{
var coroutineLockType = HashCodeHelper.ComputeHash64(GetType().FullName);
_coroutineLock = Scene.CoroutineLockComponent.Create(coroutineLockType);
await AssemblySystem.Register(this);
return this;
}
#region Assembly
public async FTask Load(long assemblyIdentity)
{
var tcs = FTask.Create(false);
Scene?.ThreadSynchronizationContext.Post(() =>
{
LoadInner(assemblyIdentity);
tcs.SetResult();
});
await tcs;
}
public async FTask ReLoad(long assemblyIdentity)
{
var tcs = FTask.Create(false);
Scene?.ThreadSynchronizationContext.Post(() =>
{
OnUnLoadInner(assemblyIdentity);
LoadInner(assemblyIdentity);
tcs.SetResult();
});
await tcs;
}
public async FTask OnUnLoad(long assemblyIdentity)
{
var tcs = FTask.Create(false);
Scene?.ThreadSynchronizationContext.Post(() =>
{
OnUnLoadInner(assemblyIdentity);
tcs.SetResult();
});
await tcs;
}
private void LoadInner(long assemblyIdentity)
{
foreach (var type in AssemblySystem.ForEach(assemblyIdentity, typeof(ISupportedSingleCollection)))
{
var customAttributes = type.GetCustomAttributes(typeof(SingleCollectionAttribute), false);
if (customAttributes.Length == 0)
{
Log.Error(
$"type {type.FullName} Implemented the interface of ISingleCollection, requiring the implementation of SingleCollectionAttribute");
continue;
}
var singleCollectionAttribute = (SingleCollectionAttribute)customAttributes[0];
var rootType = singleCollectionAttribute.RootType;
var collectionName = singleCollectionAttribute.CollectionName;
_collection.Add(rootType, collectionName);
_assemblyCollections.Add(assemblyIdentity, new SingleCollectionInfo(rootType, collectionName));
}
}
private void OnUnLoadInner(long assemblyIdentity)
{
if (!_assemblyCollections.TryGetValue(assemblyIdentity, out var types))
{
return;
}
foreach (var singleCollectionInfo in types)
{
_collection.RemoveValue(singleCollectionInfo.RootType, singleCollectionInfo.CollectionName);
}
_assemblyCollections.RemoveByKey(assemblyIdentity);
}
#endregion
#region Collections
/// <summary>
/// 通过数据库获取某一个实体类型下所有的分表数据到当前实体下,并且会自动建立父子关系。
/// </summary>
/// <param name="entity">实体实例</param>
/// <typeparam name="T">实体泛型类型</typeparam>
public async FTask GetCollections<T>(T entity) where T : Entity, ISingleCollectionRoot
{
if (!_collection.TryGetValue(typeof(T), out var collections))
{
return;
}
var worldDateBase = Scene.World.DataBase;
using (await _coroutineLock.Wait(entity.Id))
{
foreach (var collectionName in collections)
{
var singleCollection = await worldDateBase.QueryNotLock<Entity>(entity.Id, true, collectionName);
entity.AddComponent(singleCollection);
}
}
}
/// <summary>
/// 存储当前实体下支持分表的组件到数据中,包括存储实体本身。
/// </summary>
/// <param name="entity">实体实例</param>
/// <typeparam name="T">实体泛型类型</typeparam>
public async FTask SaveCollections<T>(T entity) where T : Entity, ISingleCollectionRoot
{
using var collections = ListPool<Entity>.Create();
foreach (var treeEntity in entity.ForEachSingleCollection)
{
if (treeEntity is not ISupportedSingleCollection)
{
continue;
}
collections.Add(treeEntity);
}
collections.Add(entity);
await entity.Scene.World.DataBase.Save(entity.Id, collections);
}
#endregion
}
}
#endif

View File

@@ -0,0 +1,10 @@
using Fantasy.Event;
namespace Fantasy.Timer
{
/// <summary>
/// 计时器抽象类,提供了一个基础框架,用于创建处理计时器事件的具体类。
/// </summary>
/// <typeparam name="T">事件的类型参数</typeparam>
public abstract class TimerHandler<T> : EventSystem<T> { }
}

View File

@@ -0,0 +1,49 @@
// #pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
// #pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type.
// namespace Fantasy
// {
// public sealed class ScheduledTaskPool : PoolCore<ScheduledTask>
// {
// public ScheduledTaskPool() : base(2000) { }
//
// public ScheduledTask Rent(Action action, ref int rounds, ref int finalSlot)
// {
// var scheduledTask = Rent();
// scheduledTask.Rounds = rounds;
// scheduledTask.Action = action;
// scheduledTask.FinalSlot = finalSlot;
// return scheduledTask;
// }
//
// public override void Return(ScheduledTask item)
// {
// base.Return(item);
// item.Dispose();
// }
// }
//
// public sealed class ScheduledTask : IPool, IDisposable
// {
// public int Rounds;
// public int FinalSlot;
// public Action Action;
// public LinkedListNode<ScheduledTask> Node;
//
// public bool IsPool { get; set; }
// public ScheduledTask() { }
// public ScheduledTask(Action action, ref int rounds, ref int finalSlot)
// {
// Action = action;
// Rounds = rounds;
// FinalSlot = finalSlot;
// }
//
// public void Dispose()
// {
// Rounds = 0;
// FinalSlot = 0;
// Action = null;
// Node = null;
// }
// }
// }

View File

@@ -0,0 +1,134 @@
// using System.Runtime.CompilerServices;
// // ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
// #pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type.
//
// namespace Fantasy
// {
// public sealed class TimeWheel
// {
// private int _currentIndex;
// private ScheduledTaskPool _scheduledTaskPool;
//
// private readonly Scene _scene;
// private readonly int _wheelSize;
// private readonly int _tickDuration;
// private readonly TimeWheel _upperLevelWheel;
// private readonly LinkedList<ScheduledTask>[] _wheel;
// private readonly Queue<ScheduledTask> _tasksToReschedule = new Queue<ScheduledTask>();
// private readonly Dictionary<long, ScheduledTask> _taskDictionary = new Dictionary<long, ScheduledTask>();
//
// public TimeWheel(TimerComponent timerComponent, int wheelSize, int tickDuration, TimeWheel upperLevelWheel = null)
// {
// _scene = timerComponent.Scene;
// _wheelSize = wheelSize;
// _tickDuration = tickDuration;
// _upperLevelWheel = upperLevelWheel;
// _scheduledTaskPool = timerComponent.ScheduledTaskPool;
// _wheel = new LinkedList<ScheduledTask>[_wheelSize];
// for (var i = 0; i < wheelSize; i++)
// {
// _wheel[i] = new LinkedList<ScheduledTask>();
// }
// }
//
// public long Schedule(Action action, int delay)
// {
// var ticks = delay / _tickDuration;
// var futureIndex = ticks + _currentIndex;
// var rounds = futureIndex / _wheelSize;
// var slot = futureIndex % _wheelSize;
//
// if (slot == 0)
// {
// slot = _wheelSize - 1;
// rounds--;
// }
// else
// {
// slot--;
// }
//
// var taskId = _scene.RuntimeIdFactory.Create;
// var task = _scheduledTaskPool.Rent(action, ref rounds, ref slot);
// task.Node = _wheel[slot].AddLast(task);
// _taskDictionary.Add(taskId, task);
// Console.WriteLine($"Schedule rounds:{rounds} slot:{slot} _currentIndex:{_currentIndex}");
// return taskId;
// }
//
// public bool Remove(int taskId)
// {
// if (!_taskDictionary.TryGetValue(taskId, out var task))
// {
// return false;
// }
//
// _taskDictionary.Remove(taskId);
// _wheel[task.FinalSlot].Remove(task.Node);
// _scheduledTaskPool.Return(task);
// Console.WriteLine("找到已经删除了任务");
// return true;
// }
//
// public void Tick(object? state)
// {
// var currentWheel = _wheel[_currentIndex];
//
// if (currentWheel.Count == 0)
// {
// AdvanceIndex();
// return;
// }
//
// var currentNode = currentWheel.First;
//
// while (currentNode != null)
// {
// var nextNode = currentNode.Next;
// var task = currentNode.Value;
//
// if (task.Rounds <= 0 && task.FinalSlot == _currentIndex)
// {
// try
// {
// task.Action.Invoke();
// }
// catch (Exception ex)
// {
// Log.Error($"Exception during task execution: {ex.Message}");
// }
// }
// else
// {
// task.Rounds--;
// _tasksToReschedule.Enqueue(task);
// }
//
// currentWheel.Remove(currentNode);
// currentNode = nextNode;
// }
//
// RescheduleTasks();
// AdvanceIndex();
// }
//
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
// private void AdvanceIndex()
// {
// _currentIndex = (_currentIndex + 1) % _wheelSize;
// if (_currentIndex == 0 && _upperLevelWheel != null)
// {
// _upperLevelWheel.Tick(null);
// }
// }
//
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
// private void RescheduleTasks()
// {
// while (_tasksToReschedule.TryDequeue(out var task))
// {
// _wheel[task.FinalSlot].AddLast(task);
// }
// }
// }
// }

View File

@@ -0,0 +1,27 @@
using System;
using System.Runtime.InteropServices;
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
#pragma warning disable CS8625
#pragma warning disable CS8618
namespace Fantasy.Timer
{
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct TimerAction
{
public long TimerId;
public long StartTime;
public long TriggerTime;
public readonly object Callback;
public readonly TimerType TimerType;
public TimerAction(long timerId, TimerType timerType, long startTime, long triggerTime, object callback)
{
TimerId = timerId;
Callback = callback;
TimerType = timerType;
StartTime = startTime;
TriggerTime = triggerTime;
}
}
}

View File

@@ -0,0 +1,52 @@
// ReSharper disable ForCanBeConvertedToForeach
using Fantasy.Entitas;
using Fantasy.Entitas.Interface;
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
#if FANTASY_UNITY
using UnityEngine;
#endif
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
namespace Fantasy.Timer
{
public sealed class TimerComponentUpdateSystem : UpdateSystem<TimerComponent>
{
protected override void Update(TimerComponent self)
{
self.Update();
}
}
/// <summary>
/// 时间调度组件
/// </summary>
public sealed class TimerComponent : Entity
{
/// <summary>
/// 使用系统时间创建的计时器核心。
/// </summary>
public TimerSchedulerNet Net { get; private set; }
#if FANTASY_UNITY
/// <summary>
/// 使用 Unity 时间创建的计时器核心。
/// </summary>
public TimerSchedulerNetUnity Unity { get; private set; }
#endif
internal TimerComponent Initialize()
{
Net = new TimerSchedulerNet(Scene);
#if FANTASY_UNITY
Unity = new TimerSchedulerNetUnity(Scene);
#endif
return this;
}
public void Update()
{
Net.Update();
#if FANTASY_UNITY
Unity.Update();
#endif
}
}
}

View File

@@ -0,0 +1,390 @@
using System;
using System.Collections.Generic;
using Fantasy.Async;
using Fantasy.DataStructure.Collection;
using Fantasy.Helper;
// ReSharper disable UnusedParameter.Global
#pragma warning disable CS8602 // Dereference of a possibly null reference.
#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type.
namespace Fantasy.Timer
{
/// <summary>
/// 基于系统事件的任务调度系统
/// </summary>
public sealed class TimerSchedulerNet
{
private readonly Scene _scene;
private long _idGenerator;
private long _minTime; // 最小时间
private readonly Queue<long> _timeOutTime = new Queue<long>();
private readonly Queue<long> _timeOutTimerIds = new Queue<long>();
private readonly Dictionary<long, TimerAction> _timerActions = new Dictionary<long, TimerAction>();
private readonly SortedOneToManyList<long, long> _timeId = new(); // 时间与计时器ID的有序一对多列表
private long GetId => ++_idGenerator;
/// <summary>
/// 构造函数
/// </summary>
/// <param name="scene">当前的Scene</param>
public TimerSchedulerNet(Scene scene)
{
_scene = scene;
}
private long Now()
{
return TimeHelper.Now;
}
/// <summary>
/// 驱动方法,只有调用这个方法任务系统才会正常运转。
/// </summary>
public void Update()
{
if (_timeId.Count == 0)
{
return;
}
var currentTime = Now();
if (currentTime < _minTime)
{
return;
}
// 遍历时间ID列表查找超时的计时器任务
foreach (var (key, _) in _timeId)
{
if (key > currentTime)
{
_minTime = key;
break;
}
_timeOutTime.Enqueue(key);
}
// 处理超时的计时器任务
while (_timeOutTime.TryDequeue(out var time))
{
var timerIds = _timeId[time];
for (var i = 0; i < timerIds.Count; ++i)
{
_timeOutTimerIds.Enqueue(timerIds[i]);
}
_timeId.Remove(time);
// _timeId.RemoveKey(time);
}
if (_timeId.Count == 0)
{
_minTime = long.MaxValue;
}
// 执行超时的计时器任务的回调操作
while (_timeOutTimerIds.TryDequeue(out var timerId))
{
if (!_timerActions.Remove(timerId, out var timerAction))
{
continue;
}
// 根据计时器类型执行不同的操作
switch (timerAction.TimerType)
{
case TimerType.OnceWaitTimer:
{
var tcs = (FTask<bool>)timerAction.Callback;
tcs.SetResult(true);
break;
}
case TimerType.OnceTimer:
{
if (timerAction.Callback is not Action action)
{
Log.Error($"timerAction {timerAction.ToJson()}");
break;
}
action();
break;
}
case TimerType.RepeatedTimer:
{
if (timerAction.Callback is not Action action)
{
Log.Error($"timerAction {timerAction.ToJson()}");
break;
}
timerAction.StartTime = Now();
AddTimer(ref timerAction);
action();
break;
}
}
}
}
private void AddTimer(ref TimerAction timer)
{
var tillTime = timer.StartTime + timer.TriggerTime;
_timeId.Add(tillTime, timer.TimerId);
_timerActions.Add(timer.TimerId, timer);
if (tillTime < _minTime)
{
_minTime = tillTime;
}
}
/// <summary>
/// 异步等待指定时间。
/// </summary>
/// <param name="time">等待的时间长度。</param>
/// <param name="cancellationToken">取消令牌。</param>
/// <returns>等待是否成功。</returns>
public async FTask<bool> WaitAsync(long time, FCancellationToken cancellationToken = null)
{
if (time <= 0)
{
return true;
}
var now = Now();
var timerId = GetId;
var tcs = FTask<bool>.Create();
var timerAction = new TimerAction(timerId, TimerType.OnceWaitTimer, now, time, tcs);
void CancelActionVoid()
{
if (Remove(timerId))
{
tcs.SetResult(false);
}
}
bool result;
try
{
cancellationToken?.Add(CancelActionVoid);
AddTimer(ref timerAction);
result = await tcs;
}
finally
{
cancellationToken?.Remove(CancelActionVoid);
}
return result;
}
/// <summary>
/// 异步等待直到指定时间。
/// </summary>
/// <param name="tillTime">等待的目标时间。</param>
/// <param name="cancellationToken">取消令牌。</param>
/// <returns>等待是否成功。</returns>
public async FTask<bool> WaitTillAsync(long tillTime, FCancellationToken cancellationToken = null)
{
var now = Now();
if (now >= tillTime)
{
return true;
}
var timerId = GetId;
var tcs = FTask<bool>.Create();
var timerAction = new TimerAction(timerId, TimerType.OnceWaitTimer, now, tillTime - now, tcs);
void CancelActionVoid()
{
if (Remove(timerId))
{
tcs.SetResult(false);
}
}
bool result;
try
{
cancellationToken?.Add(CancelActionVoid);
AddTimer(ref timerAction);
result = await tcs;
}
finally
{
cancellationToken?.Remove(CancelActionVoid);
}
return result;
}
/// <summary>
/// 异步等待一帧时间。
/// </summary>
/// <returns>等待是否成功。</returns>
public async FTask WaitFrameAsync()
{
#if FANTASY_NET
await WaitAsync(100);
#else
await WaitAsync(1);
#endif
}
/// <summary>
/// 创建一个只执行一次的计时器,直到指定时间
/// </summary>
/// <param name="time">计时器执行的目标时间。</param>
/// <param name="action">计时器回调方法。</param>
/// <returns></returns>
public long OnceTimer(long time, Action action)
{
var now = Now();
var timerId = GetId;
var timerAction = new TimerAction(timerId, TimerType.OnceTimer, now, time, action);
AddTimer(ref timerAction);
return timerId;
}
/// <summary>
/// 创建一个只执行一次的计时器,直到指定时间。
/// </summary>
/// <param name="tillTime">计时器执行的目标时间。</param>
/// <param name="action">计时器回调方法。</param>
/// <returns>计时器的 ID。</returns>
public long OnceTillTimer(long tillTime, Action action)
{
var now = Now();
if (tillTime < now)
{
Log.Error($"new once time too small tillTime:{tillTime} Now:{now}");
}
var timerId = GetId;
var timerAction = new TimerAction(timerId, TimerType.OnceTimer, now, tillTime - now, action);
AddTimer(ref timerAction);
return timerId;
}
/// <summary>
/// 创建一个只执行一次的计时器,用于发布指定类型的事件。
/// </summary>
/// <typeparam name="T">事件类型。</typeparam>
/// <param name="time">计时器执行的延迟时间。</param>
/// <param name="timerHandlerType">事件处理器类型。</param>
/// <returns>计时器的 ID。</returns>
public long OnceTimer<T>(long time, T timerHandlerType) where T : struct
{
void OnceTimerVoid()
{
_scene.EventComponent.Publish(timerHandlerType);
}
return OnceTimer(time, OnceTimerVoid);
}
/// <summary>
/// 创建一个只执行一次的计时器,直到指定时间,用于发布指定类型的事件。
/// </summary>
/// <typeparam name="T">事件类型。</typeparam>
/// <param name="tillTime">计时器执行的目标时间。</param>
/// <param name="timerHandlerType">事件处理器类型。</param>
/// <returns>计时器的 ID。</returns>
public long OnceTillTimer<T>(long tillTime, T timerHandlerType) where T : struct
{
void OnceTillTimerVoid()
{
_scene.EventComponent.Publish(timerHandlerType);
}
return OnceTillTimer(tillTime, OnceTillTimerVoid);
}
/// <summary>
/// 创建一个帧任务
/// </summary>
/// <param name="action"></param>
/// <returns></returns>
public long FrameTimer(Action action)
{
#if FANTASY_NET
return RepeatedTimerInner(100, action);
#else
return RepeatedTimerInner(0, action);
#endif
}
/// <summary>
/// 创建一个重复执行的计时器。
/// </summary>
/// <param name="time">计时器重复间隔的时间。</param>
/// <param name="action">计时器回调方法。</param>
/// <returns>计时器的 ID。</returns>
public long RepeatedTimer(long time, Action action)
{
if (time < 0)
{
Log.Error($"time too small: {time}");
return 0;
}
return RepeatedTimerInner(time, action);
}
/// <summary>
/// 创建一个重复执行的计时器,用于发布指定类型的事件。
/// </summary>
/// <typeparam name="T">事件类型。</typeparam>
/// <param name="time">计时器重复间隔的时间。</param>
/// <param name="timerHandlerType">事件处理器类型。</param>
/// <returns>计时器的 ID。</returns>
public long RepeatedTimer<T>(long time, T timerHandlerType) where T : struct
{
void RepeatedTimerVoid()
{
_scene.EventComponent.Publish(timerHandlerType);
}
return RepeatedTimer(time, RepeatedTimerVoid);
}
private long RepeatedTimerInner(long time, Action action)
{
var now = Now();
var timerId = GetId;
var timerAction = new TimerAction(timerId, TimerType.RepeatedTimer, now, time, action);
AddTimer(ref timerAction);
return timerId;
}
/// <summary>
/// 移除指定 ID 的计时器。
/// </summary>
/// <param name="timerId"></param>
/// <returns></returns>
public bool Remove(ref long timerId)
{
var id = timerId;
timerId = 0;
return Remove(id);
}
/// <summary>
/// 移除指定 ID 的计时器。
/// </summary>
/// <param name="timerId">计时器的 ID。</param>
public bool Remove(long timerId)
{
return timerId != 0 && _timerActions.Remove(timerId, out _);
}
}
}

View File

@@ -0,0 +1,372 @@
#if FANTASY_UNITY
using System;
using System.Collections.Generic;
using Fantasy.Async;
using Fantasy.DataStructure.Collection;
using Fantasy.Helper;
using UnityEngine;
namespace Fantasy.Timer
{
public sealed class TimerSchedulerNetUnity
{
private readonly Scene _scene;
private long _idGenerator;
private long _minTime; // 最小时间
private readonly Queue<long> _timeOutTime = new Queue<long>();
private readonly Queue<long> _timeOutTimerIds = new Queue<long>();
private readonly Dictionary<long, TimerAction> _timerActions = new Dictionary<long, TimerAction>();
private readonly SortedOneToManyList<long, long> _timeId = new(); // 时间与计时器ID的有序一对多列表
private long GetId => ++_idGenerator;
public TimerSchedulerNetUnity(Scene scene)
{
_scene = scene;
}
private long Now()
{
return (long)(Time.time * 1000);
}
public void Update()
{
if (_timeId.Count == 0)
{
return;
}
var currentTime = Now();
if (currentTime < _minTime)
{
return;
}
// 遍历时间ID列表查找超时的计时器任务
foreach (var (key, _) in _timeId)
{
if (key > currentTime)
{
_minTime = key;
break;
}
_timeOutTime.Enqueue(key);
}
// 处理超时的计时器任务
while (_timeOutTime.TryDequeue(out var time))
{
var timerIds = _timeId[time];
for (var i = 0; i < timerIds.Count; ++i)
{
_timeOutTimerIds.Enqueue(timerIds[i]);
}
_timeId.Remove(time);
// _timeId.RemoveKey(time);
}
if (_timeId.Count == 0)
{
_minTime = long.MaxValue;
}
// 执行超时的计时器任务的回调操作
while (_timeOutTimerIds.TryDequeue(out var timerId))
{
if (!_timerActions.Remove(timerId, out var timerAction))
{
continue;
}
// 根据计时器类型执行不同的操作
switch (timerAction.TimerType)
{
case TimerType.OnceWaitTimer:
{
var tcs = (FTask<bool>)timerAction.Callback;
tcs.SetResult(true);
break;
}
case TimerType.OnceTimer:
{
if (timerAction.Callback is not Action action)
{
Log.Error($"timerAction {timerAction.ToJson()}");
break;
}
action();
break;
}
case TimerType.RepeatedTimer:
{
if (timerAction.Callback is not Action action)
{
Log.Error($"timerAction {timerAction.ToJson()}");
break;
}
timerAction.StartTime = Now();
AddTimer(ref timerAction);
action();
break;
}
}
}
}
private void AddTimer(ref TimerAction timer)
{
var tillTime = timer.StartTime + timer.TriggerTime;
_timeId.Add(tillTime, timer.TimerId);
_timerActions.Add(timer.TimerId, timer);
if (tillTime < _minTime)
{
_minTime = tillTime;
}
}
/// <summary>
/// 异步等待指定时间。
/// </summary>
/// <param name="time">等待的时间长度。</param>
/// <param name="cancellationToken">可选的取消令牌。</param>
/// <returns>等待是否成功。</returns>
public async FTask<bool> WaitAsync(long time, FCancellationToken cancellationToken = null)
{
if (time <= 0)
{
return true;
}
var now = Now();
var timerId = GetId;
var tcs = FTask<bool>.Create();
var timerAction = new TimerAction(timerId, TimerType.OnceWaitTimer, now, time, tcs);
void CancelActionVoid()
{
if (Remove(timerId))
{
tcs.SetResult(false);
}
}
bool result;
try
{
cancellationToken?.Add(CancelActionVoid);
AddTimer(ref timerAction);
result =await tcs;
}
finally
{
cancellationToken?.Remove(CancelActionVoid);
}
return result;
}
/// <summary>
/// 异步等待直到指定时间。
/// </summary>
/// <param name="tillTime">等待的目标时间。</param>
/// <param name="cancellationToken">可选的取消令牌。</param>
/// <returns>等待是否成功。</returns>
public async FTask<bool> WaitTillAsync(long tillTime, FCancellationToken cancellationToken = null)
{
var now = Now();
if (now >= tillTime)
{
return true;
}
var timerId = GetId;
var tcs = FTask<bool>.Create();
var timerAction = new TimerAction(timerId, TimerType.OnceWaitTimer, now, tillTime - now, tcs);
void CancelActionVoid()
{
if (Remove(timerId))
{
tcs.SetResult(false);
}
}
bool result;
try
{
cancellationToken?.Add(CancelActionVoid);
AddTimer(ref timerAction);
result = await tcs;
}
finally
{
cancellationToken?.Remove(CancelActionVoid);
}
return result;
}
/// <summary>
/// 异步等待一帧时间。
/// </summary>
/// <returns>等待是否成功。</returns>
public async FTask WaitFrameAsync(FCancellationToken cancellationToken = null)
{
await WaitAsync(1, cancellationToken);
}
/// <summary>
/// 创建一个只执行一次的计时器,直到指定时间
/// </summary>
/// <param name="time">计时器执行的目标时间。</param>
/// <param name="action">计时器回调方法。</param>
/// <returns></returns>
public long OnceTimer(long time, Action action)
{
var now = Now();
var timerId = GetId;
var timerAction = new TimerAction(timerId, TimerType.OnceTimer, now, time, action);
AddTimer(ref timerAction);
return timerId;
}
/// <summary>
/// 创建一个只执行一次的计时器,直到指定时间。
/// </summary>
/// <param name="tillTime">计时器执行的目标时间。</param>
/// <param name="action">计时器回调方法。</param>
/// <returns>计时器的 ID。</returns>
public long OnceTillTimer(long tillTime, Action action)
{
var now = Now();
if (tillTime < now)
{
Log.Error($"new once time too small tillTime:{tillTime} Now:{now}");
}
var timerId = GetId;
var timerAction = new TimerAction(timerId, TimerType.OnceTimer, now, tillTime - now, action);
AddTimer(ref timerAction);
return timerId;
}
/// <summary>
/// 创建一个只执行一次的计时器,用于发布指定类型的事件。
/// </summary>
/// <typeparam name="T">事件类型。</typeparam>
/// <param name="time">计时器执行的延迟时间。</param>
/// <param name="timerHandlerType">事件处理器类型。</param>
/// <returns>计时器的 ID。</returns>
public long OnceTimer<T>(long time, T timerHandlerType) where T : struct
{
void OnceTimerVoid()
{
_scene.EventComponent.Publish(timerHandlerType);
}
return OnceTimer(time, OnceTimerVoid);
}
/// <summary>
/// 创建一个只执行一次的计时器,直到指定时间,用于发布指定类型的事件。
/// </summary>
/// <typeparam name="T">事件类型。</typeparam>
/// <param name="tillTime">计时器执行的目标时间。</param>
/// <param name="timerHandlerType">事件处理器类型。</param>
/// <returns>计时器的 ID。</returns>
public long OnceTillTimer<T>(long tillTime, T timerHandlerType) where T : struct
{
void OnceTillTimerVoid()
{
_scene.EventComponent.Publish(timerHandlerType);
}
return OnceTillTimer(tillTime, OnceTillTimerVoid);
}
/// <summary>
/// 创建一个帧任务
/// </summary>
/// <param name="action"></param>
/// <returns></returns>
public long FrameTimer(Action action)
{
return RepeatedTimerInner(1, action);
}
/// <summary>
/// 创建一个重复执行的计时器。
/// </summary>
/// <param name="time">计时器重复间隔的时间。</param>
/// <param name="action">计时器回调方法。</param>
/// <returns>计时器的 ID。</returns>
public long RepeatedTimer(long time, Action action)
{
if (time < 0)
{
Log.Error($"time too small: {time}");
return 0;
}
return RepeatedTimerInner(time, action);
}
/// <summary>
/// 创建一个重复执行的计时器,用于发布指定类型的事件。
/// </summary>
/// <typeparam name="T">事件类型。</typeparam>
/// <param name="time">计时器重复间隔的时间。</param>
/// <param name="timerHandlerType">事件处理器类型。</param>
/// <returns>计时器的 ID。</returns>
public long RepeatedTimer<T>(long time, T timerHandlerType) where T : struct
{
void RepeatedTimerVoid()
{
_scene.EventComponent.Publish(timerHandlerType);
}
return RepeatedTimer(time, RepeatedTimerVoid);
}
private long RepeatedTimerInner(long time, Action action)
{
var now = Now();
var timerId = GetId;
var timerAction = new TimerAction(timerId, TimerType.RepeatedTimer, now, time, action);
AddTimer(ref timerAction);
return timerId;
}
/// <summary>
/// 移除指定 ID 的计时器。
/// </summary>
/// <param name="timerId"></param>
/// <returns></returns>
public bool Remove(ref long timerId)
{
var id = timerId;
timerId = 0;
return Remove(id);
}
/// <summary>
/// 移除指定 ID 的计时器。
/// </summary>
/// <param name="timerId">计时器的 ID。</param>
public bool Remove(long timerId)
{
return timerId != 0 && _timerActions.Remove(timerId, out _);
}
}
}
#endif

View File

@@ -0,0 +1,25 @@
namespace Fantasy.Timer
{
/// <summary>
/// 枚举对象TimerType
/// </summary>
public enum TimerType
{
/// <summary>
/// None
/// </summary>
None,
/// <summary>
/// 一次等待定时器
/// </summary>
OnceWaitTimer,
/// <summary>
/// 一次性定时器
/// </summary>
OnceTimer,
/// <summary>
/// 重复定时器
/// </summary>
RepeatedTimer
}
}