NBC修改
This commit is contained in:
8
Assets/Scripts/NBC/Runtime/Core/Entitas/Component.meta
Normal file
8
Assets/Scripts/NBC/Runtime/Core/Entitas/Component.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e39207f0f9770415093af2f27fd7e988
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: db6a6392f9f6e4a2fbedb6ba3df377e8
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,140 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using NBC.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 NBC.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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e2fe8fb8f49ad4565b47c840fb690d1f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,100 @@
|
||||
using System.Collections.Generic;
|
||||
using NBC.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 NBC.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8abfde11ad4d344eda0bf16b249a0dae
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,35 @@
|
||||
// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
|
||||
using System.Collections.Generic;
|
||||
using NBC.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 NBC.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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c1a15c49a7b7b488c8aac3d7720d506e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,146 @@
|
||||
using System;
|
||||
using NBC.Event;
|
||||
using NBC.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 NBC.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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c6d5307f677ba48f891c12ac183a0128
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,472 @@
|
||||
// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.InteropServices;
|
||||
using NBC.Entitas;
|
||||
using NBC.Assembly;
|
||||
using NBC.Async;
|
||||
using NBC.DataStructure.Collection;
|
||||
using NBC.Entitas.Interface;
|
||||
using NBC.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 NBC.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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 41c0ffdbeaaf84d848105eb341414c4a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5ff190d313de0433bb5c6cad4f116d1a
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,255 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using NBC.Assembly;
|
||||
using NBC.Async;
|
||||
using NBC.DataStructure.Collection;
|
||||
using NBC.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 NBC.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));
|
||||
}
|
||||
_events.SortAll();
|
||||
|
||||
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));
|
||||
}
|
||||
_asyncEvents.SortAll();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bc6c3f6b01eb14a35934175e36eeb544
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 10dcbb383d66a4915b44d6f20331a7bf
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,112 @@
|
||||
using System;
|
||||
using NBC.Async;
|
||||
|
||||
namespace NBC.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}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1e46ad748051f4277a8f660fa842b19d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,139 @@
|
||||
// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using NBC.Entitas;
|
||||
using NBC.DataStructure.Collection;
|
||||
using NBC.Pool;
|
||||
using NBC.Serialize;
|
||||
|
||||
namespace NBC.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b4db4a3115fd64377b5b89f2bdc001a1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: de3b132dd12a0427face9541cc1ba095
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 20842cefeece84173bf625c41a94ef63
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,10 @@
|
||||
using NBC.Event;
|
||||
|
||||
namespace NBC
|
||||
{
|
||||
/// <summary>
|
||||
/// 计时器抽象类,提供了一个基础框架,用于创建处理计时器事件的具体类。
|
||||
/// </summary>
|
||||
/// <typeparam name="T">事件的类型参数</typeparam>
|
||||
public abstract class TimerHandler<T> : EventSystem<T> { }
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0bb411c4d246b43aba54eb60b7654492
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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 NBC
|
||||
{
|
||||
[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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5c875fd82f74f430c963315b79f7a9a7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,45 @@
|
||||
// ReSharper disable ForCanBeConvertedToForeach
|
||||
|
||||
using NBC.Entitas;
|
||||
using NBC.Entitas.Interface;
|
||||
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
|
||||
using UnityEngine;
|
||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||
namespace NBC
|
||||
{
|
||||
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; }
|
||||
|
||||
/// <summary>
|
||||
/// 使用 Unity 时间创建的计时器核心。
|
||||
/// </summary>
|
||||
public TimerSchedulerNetUnity Unity { get; private set; }
|
||||
|
||||
internal TimerComponent Initialize()
|
||||
{
|
||||
Net = new TimerSchedulerNet(Scene);
|
||||
Unity = new TimerSchedulerNetUnity(Scene);
|
||||
return this;
|
||||
}
|
||||
public void Update()
|
||||
{
|
||||
Net.Update();
|
||||
Unity.Update();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4b33402f4024349359a173ef6aa46abf
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 74544bc3e0a9a4cc2af251a9a2a871c1
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,383 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using NBC.Async;
|
||||
using NBC.DataStructure.Collection;
|
||||
using NBC.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 NBC
|
||||
{
|
||||
/// <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()
|
||||
{
|
||||
await WaitAsync(1);
|
||||
}
|
||||
|
||||
/// <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(0, 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 _);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: af9a02de83dce4c088f786cf6cf6bdd7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,372 @@
|
||||
#if FANTASY_UNITY
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using NBC.Helper;
|
||||
using NBC.Async;
|
||||
using NBC.DataStructure.Collection;
|
||||
using UnityEngine;
|
||||
namespace NBC
|
||||
{
|
||||
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
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3d14712dd51d84d7eb7e8998013d28ce
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,25 @@
|
||||
namespace NBC
|
||||
{
|
||||
/// <summary>
|
||||
/// 枚举对象TimerType
|
||||
/// </summary>
|
||||
public enum TimerType
|
||||
{
|
||||
/// <summary>
|
||||
/// None
|
||||
/// </summary>
|
||||
None,
|
||||
/// <summary>
|
||||
/// 一次等待定时器
|
||||
/// </summary>
|
||||
OnceWaitTimer,
|
||||
/// <summary>
|
||||
/// 一次性定时器
|
||||
/// </summary>
|
||||
OnceTimer,
|
||||
/// <summary>
|
||||
/// 重复定时器
|
||||
/// </summary>
|
||||
RepeatedTimer
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b1b471e1861ac4718a57e94ba520588e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
837
Assets/Scripts/NBC/Runtime/Core/Entitas/Entity.cs
Normal file
837
Assets/Scripts/NBC/Runtime/Core/Entitas/Entity.cs
Normal file
@@ -0,0 +1,837 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Serialization;
|
||||
using MongoDB.Bson.Serialization.Attributes;
|
||||
using NBC.Entitas.Interface;
|
||||
using NBC.Pool;
|
||||
using Newtonsoft.Json;
|
||||
using ProtoBuf;
|
||||
// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
|
||||
// ReSharper disable MergeIntoPattern
|
||||
// ReSharper disable SuspiciousTypeConversion.Global
|
||||
// ReSharper disable NullCoalescingConditionIsAlwaysNotNullAccordingToAPIContract
|
||||
// ReSharper disable CheckNamespace
|
||||
#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type.
|
||||
#pragma warning disable CS8603 // Possible null reference return.
|
||||
#pragma warning disable CS8602 // Dereference of a possibly null reference.
|
||||
#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type.
|
||||
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
|
||||
|
||||
namespace NBC.Entitas
|
||||
{
|
||||
/// <summary>
|
||||
/// 用来表示一个Entity
|
||||
/// </summary>
|
||||
public interface IEntity : IDisposable, IPool { }
|
||||
|
||||
/// <summary>
|
||||
/// Entity的抽象类,任何Entity必须继承这个接口才可以使用
|
||||
/// </summary>
|
||||
public abstract partial class Entity : IEntity
|
||||
{
|
||||
#region Members
|
||||
|
||||
/// <summary>
|
||||
/// 获取一个值,表示实体是否支持对象池。
|
||||
/// </summary>
|
||||
[BsonIgnore]
|
||||
[JsonIgnore]
|
||||
[ProtoIgnore]
|
||||
[IgnoreDataMember]
|
||||
private bool _isPool;
|
||||
/// <summary>
|
||||
/// 实体的Id
|
||||
/// </summary>
|
||||
[BsonId]
|
||||
[BsonElement]
|
||||
[BsonIgnoreIfDefault]
|
||||
[BsonDefaultValue(0L)]
|
||||
public long Id { get; protected set; }
|
||||
/// <summary>
|
||||
/// 实体的RunTimeId,其他系统可以通过这个Id发送Route消息,这个Id也可以理解为RouteId
|
||||
/// </summary>
|
||||
[BsonIgnore]
|
||||
[IgnoreDataMember]
|
||||
[ProtoIgnore]
|
||||
public long RuntimeId { get; protected set; }
|
||||
/// <summary>
|
||||
/// 当前实体是否已经被销毁
|
||||
/// </summary>
|
||||
[BsonIgnore]
|
||||
[JsonIgnore]
|
||||
[IgnoreDataMember]
|
||||
[ProtoIgnore]
|
||||
public bool IsDisposed => RuntimeId == 0;
|
||||
/// <summary>
|
||||
/// 当前实体所归属的Scene
|
||||
/// </summary>
|
||||
[BsonIgnore]
|
||||
[JsonIgnore]
|
||||
[IgnoreDataMember]
|
||||
[ProtoIgnore]
|
||||
public Scene Scene { get; protected set; }
|
||||
/// <summary>
|
||||
/// 实体的父实体
|
||||
/// </summary>
|
||||
[BsonIgnore]
|
||||
[JsonIgnore]
|
||||
[IgnoreDataMember]
|
||||
[ProtoIgnore]
|
||||
public Entity Parent { get; protected set; }
|
||||
/// <summary>
|
||||
/// 实体的真实Type
|
||||
/// </summary>
|
||||
[BsonIgnore]
|
||||
[JsonIgnore]
|
||||
[IgnoreDataMember]
|
||||
[ProtoIgnore]
|
||||
public Type Type { get; protected set; }
|
||||
|
||||
[BsonIgnore] [IgnoreDataMember] [ProtoIgnore] private EntitySortedDictionary<long, Entity> _tree;
|
||||
[BsonIgnore] [IgnoreDataMember] [ProtoIgnore] private EntitySortedDictionary<long, Entity> _multi;
|
||||
|
||||
/// <summary>
|
||||
/// 获得父Entity
|
||||
/// </summary>
|
||||
/// <typeparam name="T">父实体的泛型类型</typeparam>
|
||||
/// <returns></returns>
|
||||
public T GetParent<T>() where T : Entity, new()
|
||||
{
|
||||
return Parent as T;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前实体的RouteId。
|
||||
/// </summary>
|
||||
public long RouteId => RuntimeId;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Create
|
||||
|
||||
/// <summary>
|
||||
/// 创建一个实体
|
||||
/// </summary>
|
||||
/// <param name="scene">所属的Scene</param>
|
||||
/// <param name="type">实体的Type</param>
|
||||
/// <param name="isPool">是否从对象池创建,如果选择的是,销毁的时候同样会进入对象池</param>
|
||||
/// <param name="isRunEvent">是否执行实体事件</param>
|
||||
/// <returns></returns>
|
||||
public static Entity Create(Scene scene, Type type, bool isPool, bool isRunEvent)
|
||||
{
|
||||
return Create(scene, type, scene.EntityIdFactory.Create, isPool, isRunEvent);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建一个实体
|
||||
/// </summary>
|
||||
/// <param name="scene">所属的Scene</param>
|
||||
/// <param name="type">实体的Type</param>
|
||||
/// <param name="id">指定实体的Id</param>
|
||||
/// <param name="isPool">是否从对象池创建,如果选择的是,销毁的时候同样会进入对象池</param>
|
||||
/// <param name="isRunEvent">是否执行实体事件</param>
|
||||
/// <returns></returns>
|
||||
public static Entity Create(Scene scene, Type type, long id, bool isPool, bool isRunEvent)
|
||||
{
|
||||
if (!typeof(Entity).IsAssignableFrom(type))
|
||||
{
|
||||
throw new NotSupportedException($"{type.FullName} Type:{type.FullName} must inherit from Entity");
|
||||
}
|
||||
|
||||
Entity entity = null;
|
||||
|
||||
if (isPool)
|
||||
{
|
||||
entity = (Entity)scene.EntityPool.Rent(type);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!scene.TypeInstance.TryGetValue(type, out var createInstance))
|
||||
{
|
||||
createInstance = CreateInstance.CreateIPool(type);
|
||||
scene.TypeInstance[type] = createInstance;
|
||||
}
|
||||
|
||||
entity = (Entity)createInstance();
|
||||
}
|
||||
|
||||
entity.Scene = scene;
|
||||
entity.Type = type;
|
||||
entity.SetIsPool(isPool);
|
||||
entity.Id = id;
|
||||
entity.RuntimeId = scene.RuntimeIdFactory.Create;
|
||||
scene.AddEntity(entity);
|
||||
|
||||
if (isRunEvent)
|
||||
{
|
||||
scene.EntityComponent.Awake(entity);
|
||||
scene.EntityComponent.StartUpdate(entity);
|
||||
}
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建一个实体
|
||||
/// </summary>
|
||||
/// <param name="scene">所属的Scene</param>
|
||||
/// <param name="isPool">是否从对象池创建,如果选择的是,销毁的时候同样会进入对象池</param>
|
||||
/// <param name="isRunEvent">是否执行实体事件</param>
|
||||
/// <typeparam name="T">要创建的实体泛型类型</typeparam>
|
||||
/// <returns></returns>
|
||||
public static T Create<T>(Scene scene, bool isPool, bool isRunEvent) where T : Entity, new()
|
||||
{
|
||||
return Create<T>(scene, scene.EntityIdFactory.Create, isPool, isRunEvent);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建一个实体
|
||||
/// </summary>
|
||||
/// <param name="scene">所属的Scene</param>
|
||||
/// <param name="id">指定实体的Id</param>
|
||||
/// <param name="isPool">是否从对象池创建,如果选择的是,销毁的时候同样会进入对象池</param>
|
||||
/// <param name="isRunEvent">是否执行实体事件</param>
|
||||
/// <typeparam name="T">要创建的实体泛型类型</typeparam>
|
||||
/// <returns></returns>
|
||||
public static T Create<T>(Scene scene, long id, bool isPool, bool isRunEvent) where T : Entity, new()
|
||||
{
|
||||
var entity = isPool ? scene.EntityPool.Rent<T>() : new T();
|
||||
entity.Scene = scene;
|
||||
entity.Type = typeof(T);
|
||||
entity.SetIsPool(isPool);
|
||||
entity.Id = id;
|
||||
entity.RuntimeId = scene.RuntimeIdFactory.Create;
|
||||
scene.AddEntity(entity);
|
||||
|
||||
if (isRunEvent)
|
||||
{
|
||||
scene.EntityComponent.Awake(entity);
|
||||
scene.EntityComponent.StartUpdate(entity);
|
||||
}
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region AddComponent
|
||||
|
||||
/// <summary>
|
||||
/// 添加一个组件到当前实体上
|
||||
/// </summary>
|
||||
/// <param name="isPool">是否从对象池里创建</param>
|
||||
/// <typeparam name="T">要添加组件的泛型类型</typeparam>
|
||||
/// <returns>返回添加到实体上组件的实例</returns>
|
||||
public T AddComponent<T>(bool isPool = true) where T : Entity, new()
|
||||
{
|
||||
var id = SupportedMultiEntityChecker<T>.IsSupported ? Scene.EntityIdFactory.Create : Id;
|
||||
var entity = Create<T>(Scene, id, isPool, false);
|
||||
AddComponent(entity);
|
||||
Scene.EntityComponent.Awake(entity);
|
||||
Scene.EntityComponent.StartUpdate(entity);
|
||||
return entity;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加一个组件到当前实体上
|
||||
/// </summary>
|
||||
/// <param name="id">要添加组件的Id</param>
|
||||
/// <param name="isPool">是否从对象池里创建</param>
|
||||
/// <typeparam name="T">要添加组件的泛型类型</typeparam>
|
||||
/// <returns>返回添加到实体上组件的实例</returns>
|
||||
public T AddComponent<T>(long id, bool isPool = true) where T : Entity, new()
|
||||
{
|
||||
var entity = Create<T>(Scene, id, isPool, false);
|
||||
AddComponent(entity);
|
||||
Scene.EntityComponent.Awake(entity);
|
||||
Scene.EntityComponent.StartUpdate(entity);
|
||||
return entity;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加一个组件到当前实体上
|
||||
/// </summary>
|
||||
/// <param name="component">要添加的实体实例</param>
|
||||
public void AddComponent(Entity component)
|
||||
{
|
||||
if (this == component)
|
||||
{
|
||||
Log.Error("Cannot add oneself to one's own components");
|
||||
return;
|
||||
}
|
||||
|
||||
if (component.IsDisposed)
|
||||
{
|
||||
Log.Error($"component is Disposed {component.Type.FullName}");
|
||||
return;
|
||||
}
|
||||
|
||||
var type = component.Type;
|
||||
component.Parent?.RemoveComponent(component, false);
|
||||
|
||||
if (component is ISupportedMultiEntity)
|
||||
{
|
||||
_multi ??= Scene.EntitySortedDictionaryPool.Rent();
|
||||
_multi.Add(component.Id, component);
|
||||
}
|
||||
else
|
||||
{
|
||||
var typeHashCode = Scene.EntityComponent.GetHashCode(type);;
|
||||
|
||||
if (_tree == null)
|
||||
{
|
||||
_tree = Scene.EntitySortedDictionaryPool.Rent();
|
||||
}
|
||||
else if (_tree.ContainsKey(typeHashCode))
|
||||
{
|
||||
Log.Error($"type:{type.FullName} If you want to add multiple components of the same type, please implement IMultiEntity");
|
||||
return;
|
||||
}
|
||||
|
||||
_tree.Add(typeHashCode, component);
|
||||
}
|
||||
|
||||
component.Parent = this;
|
||||
component.Scene = Scene;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加一个组件到当前实体上
|
||||
/// </summary>
|
||||
/// <param name="component">要添加的实体实例</param>
|
||||
/// <typeparam name="T">要添加组件的泛型类型</typeparam>
|
||||
public void AddComponent<T>(T component) where T : Entity
|
||||
{
|
||||
var type = typeof(T);
|
||||
|
||||
if (type == typeof(Entity))
|
||||
{
|
||||
Log.Error("Cannot add a generic Entity type as a component. Specify a more specific type.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (this == component)
|
||||
{
|
||||
Log.Error("Cannot add oneself to one's own components");
|
||||
return;
|
||||
}
|
||||
|
||||
if (component.IsDisposed)
|
||||
{
|
||||
Log.Error($"component is Disposed {type.FullName}");
|
||||
return;
|
||||
}
|
||||
|
||||
component.Parent?.RemoveComponent(component, false);
|
||||
|
||||
if (SupportedMultiEntityChecker<T>.IsSupported)
|
||||
{
|
||||
_multi ??= Scene.EntitySortedDictionaryPool.Rent();
|
||||
_multi.Add(component.Id, component);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
var typeHashCode = Scene.EntityComponent.GetHashCode(type);
|
||||
|
||||
if (_tree == null)
|
||||
{
|
||||
_tree = Scene.EntitySortedDictionaryPool.Rent();
|
||||
}
|
||||
else if (_tree.ContainsKey(typeHashCode))
|
||||
{
|
||||
Log.Error($"type:{type.FullName} If you want to add multiple components of the same type, please implement IMultiEntity");
|
||||
return;
|
||||
}
|
||||
|
||||
_tree.Add(typeHashCode, component);
|
||||
}
|
||||
|
||||
component.Parent = this;
|
||||
component.Scene = Scene;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加一个组件到当前实体上
|
||||
/// </summary>
|
||||
/// <param name="type">组件的类型</param>
|
||||
/// <param name="isPool">是否在对象池创建</param>
|
||||
/// <returns></returns>
|
||||
public Entity AddComponent(Type type, bool isPool = true)
|
||||
{
|
||||
var id = typeof(ISupportedMultiEntity).IsAssignableFrom(type) ? Scene.EntityIdFactory.Create : Id;
|
||||
var entity = Entity.Create(Scene, type, id, isPool, false);
|
||||
AddComponent(entity);
|
||||
Scene.EntityComponent.Awake(entity);
|
||||
Scene.EntityComponent.StartUpdate(entity);
|
||||
return entity;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region HasComponent
|
||||
|
||||
/// <summary>
|
||||
/// 当前实体上是否有指定类型的组件
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
public bool HasComponent<T>() where T : Entity, new()
|
||||
{
|
||||
return HasComponent(typeof(T));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当前实体上是否有指定类型的组件
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
public bool HasComponent(Type type)
|
||||
{
|
||||
if (_tree == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return _tree.ContainsKey(Scene.EntityComponent.GetHashCode(type));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当前实体上是否有指定类型的组件
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
public bool HasComponent<T>(long id) where T : Entity, ISupportedMultiEntity, new()
|
||||
{
|
||||
if (_multi == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return _multi.ContainsKey(id);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region GetComponent
|
||||
|
||||
/// <summary>
|
||||
/// 当前实体上查找一个字实体
|
||||
/// </summary>
|
||||
/// <typeparam name="T">要查找实体泛型类型</typeparam>
|
||||
/// <returns>查找的实体实例</returns>
|
||||
public T GetComponent<T>() where T : Entity, new()
|
||||
{
|
||||
if (_tree == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var typeHashCode = Scene.EntityComponent.GetHashCode(typeof(T));
|
||||
return _tree.TryGetValue(typeHashCode, out var component) ? (T)component : null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当前实体上查找一个字实体
|
||||
/// </summary>
|
||||
/// <param name="type">要查找实体类型</param>
|
||||
/// <returns>查找的实体实例</returns>
|
||||
public Entity GetComponent(Type type)
|
||||
{
|
||||
if (_tree == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var typeHashCode = Scene.EntityComponent.GetHashCode(type);
|
||||
return _tree.TryGetValue(typeHashCode, out var component) ? component : null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当前实体上查找一个字实体
|
||||
/// </summary>
|
||||
/// <param name="id">要查找实体的Id</param>
|
||||
/// <typeparam name="T">要查找实体泛型类型</typeparam>
|
||||
/// <returns>查找的实体实例</returns>
|
||||
public T GetComponent<T>(long id) where T : Entity, ISupportedMultiEntity, new()
|
||||
{
|
||||
if (_multi == null)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
return _multi.TryGetValue(id, out var entity) ? (T)entity : default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当前实体上查找一个字实体,如果没有就创建一个新的并添加到当前实体上
|
||||
/// </summary>
|
||||
/// <param name="isPool">是否从对象池创建</param>
|
||||
/// <typeparam name="T">要查找或添加实体泛型类型</typeparam>
|
||||
/// <returns>查找的实体实例</returns>
|
||||
public T GetOrAddComponent<T>(bool isPool = true) where T : Entity, new()
|
||||
{
|
||||
return GetComponent<T>() ?? AddComponent<T>(isPool);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region RemoveComponent
|
||||
|
||||
/// <summary>
|
||||
/// 当前实体下删除一个实体
|
||||
/// </summary>
|
||||
/// <param name="isDispose">是否执行删除实体的Dispose方法</param>
|
||||
/// <typeparam name="T">实体的泛型类型</typeparam>
|
||||
/// <exception cref="NotSupportedException"></exception>
|
||||
public void RemoveComponent<T>(bool isDispose = true) where T : Entity, new()
|
||||
{
|
||||
if (SupportedMultiEntityChecker<T>.IsSupported)
|
||||
{
|
||||
throw new NotSupportedException($"{typeof(T).FullName} message:Cannot delete components that implement the ISupportedMultiEntity interface");
|
||||
}
|
||||
|
||||
if (_tree == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var type = typeof(T);
|
||||
var typeHashCode = Scene.EntityComponent.GetHashCode(type);
|
||||
if (!_tree.TryGetValue(typeHashCode, out var component))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_tree.Remove(typeHashCode);
|
||||
|
||||
if (_tree.Count == 0)
|
||||
{
|
||||
Scene.EntitySortedDictionaryPool.Return(_tree);
|
||||
_tree = null;
|
||||
}
|
||||
|
||||
if (isDispose)
|
||||
{
|
||||
component.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当前实体下删除一个实体
|
||||
/// </summary>
|
||||
/// <param name="id">要删除的实体Id</param>
|
||||
/// <param name="isDispose">是否执行删除实体的Dispose方法</param>
|
||||
/// <typeparam name="T">实体的泛型类型</typeparam>
|
||||
public void RemoveComponent<T>(long id, bool isDispose = true) where T : Entity, ISupportedMultiEntity, new()
|
||||
{
|
||||
if (_multi == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_multi.TryGetValue(id, out var component))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_multi.Remove(component.Id);
|
||||
if (_multi.Count == 0)
|
||||
{
|
||||
Scene.EntitySortedDictionaryPool.Return(_multi);
|
||||
_multi = null;
|
||||
}
|
||||
|
||||
if (isDispose)
|
||||
{
|
||||
component.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当前实体下删除一个实体
|
||||
/// </summary>
|
||||
/// <param name="component">要删除的实体实例</param>
|
||||
/// <param name="isDispose">是否执行删除实体的Dispose方法</param>
|
||||
public void RemoveComponent(Entity component, bool isDispose = true)
|
||||
{
|
||||
if (this == component)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (component is ISupportedMultiEntity)
|
||||
{
|
||||
if (_multi != null)
|
||||
{
|
||||
if (!_multi.ContainsKey(component.Id))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_multi.Remove(component.Id);
|
||||
if (_multi.Count == 0)
|
||||
{
|
||||
Scene.EntitySortedDictionaryPool.Return(_multi);
|
||||
_multi = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (_tree != null)
|
||||
{
|
||||
var typeHashCode = Scene.EntityComponent.GetHashCode(component.Type);
|
||||
if (!_tree.ContainsKey(typeHashCode))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_tree.Remove(typeHashCode);
|
||||
|
||||
if (_tree.Count == 0)
|
||||
{
|
||||
Scene.EntitySortedDictionaryPool.Return(_tree);
|
||||
_tree = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (isDispose)
|
||||
{
|
||||
component.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当前实体下删除一个实体
|
||||
/// </summary>
|
||||
/// <param name="component">要删除的实体实例</param>
|
||||
/// <param name="isDispose">是否执行删除实体的Dispose方法</param>
|
||||
/// <typeparam name="T">实体的泛型类型</typeparam>
|
||||
public void RemoveComponent<T>(T component, bool isDispose = true) where T : Entity
|
||||
{
|
||||
if (this == component)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof(T) == typeof(Entity))
|
||||
{
|
||||
Log.Error("Cannot remove a generic Entity type as a component. Specify a more specific type.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (SupportedMultiEntityChecker<T>.IsSupported)
|
||||
{
|
||||
if (_multi != null)
|
||||
{
|
||||
if (!_multi.ContainsKey(component.Id))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_multi.Remove(component.Id);
|
||||
if (_multi.Count == 0)
|
||||
{
|
||||
Scene.EntitySortedDictionaryPool.Return(_multi);
|
||||
_multi = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (_tree != null)
|
||||
{
|
||||
var typeHashCode = Scene.EntityComponent.GetHashCode(typeof(T));
|
||||
if (!_tree.ContainsKey(typeHashCode))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_tree.Remove(typeHashCode);
|
||||
|
||||
if (_tree.Count == 0)
|
||||
{
|
||||
Scene.EntitySortedDictionaryPool.Return(_tree);
|
||||
_tree = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (isDispose)
|
||||
{
|
||||
component.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Deserialize
|
||||
|
||||
/// <summary>
|
||||
/// 反序列化当前实体,因为在数据库加载过来的或通过协议传送过来的实体并没有跟当前Scene做关联。
|
||||
/// 所以必须要执行一下这个反序列化的方法才可以使用。
|
||||
/// </summary>
|
||||
/// <param name="scene">Scene</param>
|
||||
/// <param name="resetId">是否是重新生成实体的Id,如果是数据库加载过来的一般是不需要的</param>
|
||||
public void Deserialize(Scene scene, bool resetId = false)
|
||||
{
|
||||
if (RuntimeId != 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Scene = scene;
|
||||
Type ??= GetType();
|
||||
RuntimeId = Scene.RuntimeIdFactory.Create;
|
||||
if (resetId)
|
||||
{
|
||||
Id = RuntimeId;
|
||||
}
|
||||
scene.AddEntity(this);
|
||||
scene.EntityComponent.Deserialize(this);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (RuntimeId != 0)
|
||||
{
|
||||
scene.RemoveEntity(RuntimeId);
|
||||
}
|
||||
|
||||
Log.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ForEach
|
||||
|
||||
/// <summary>
|
||||
/// 查询当前实体下的实现了ISupportedMultiEntity接口的实体
|
||||
/// </summary>
|
||||
[BsonIgnore]
|
||||
[JsonIgnore]
|
||||
[IgnoreDataMember]
|
||||
[ProtoIgnore]
|
||||
public IEnumerable<Entity> ForEachMultiEntity
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_multi == null)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
foreach (var (_, supportedMultiEntity) in _multi)
|
||||
{
|
||||
yield return supportedMultiEntity;
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 查找当前实体下的所有实体,不包括实现ISupportedMultiEntity接口的实体
|
||||
/// </summary>
|
||||
[BsonIgnore]
|
||||
[JsonIgnore]
|
||||
[IgnoreDataMember]
|
||||
[ProtoIgnore]
|
||||
public IEnumerable<Entity> ForEachEntity
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_tree == null)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
foreach (var (_, entity) in _tree)
|
||||
{
|
||||
yield return entity;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Dispose
|
||||
|
||||
/// <summary>
|
||||
/// 销毁当前实体,销毁后会自动销毁当前实体下的所有实体。
|
||||
/// </summary>
|
||||
public virtual void Dispose()
|
||||
{
|
||||
if (IsDisposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var scene = Scene;
|
||||
var runTimeId = RuntimeId;
|
||||
RuntimeId = 0;
|
||||
|
||||
if (_tree != null)
|
||||
{
|
||||
foreach (var (_, entity) in _tree)
|
||||
{
|
||||
entity.Dispose();
|
||||
}
|
||||
|
||||
_tree.Clear();
|
||||
scene.EntitySortedDictionaryPool.Return(_tree);
|
||||
_tree = null;
|
||||
}
|
||||
|
||||
if (_multi != null)
|
||||
{
|
||||
foreach (var (_, entity) in _multi)
|
||||
{
|
||||
entity.Dispose();
|
||||
}
|
||||
|
||||
_multi.Clear();
|
||||
scene.EntitySortedDictionaryPool.Return(_multi);
|
||||
_multi = null;
|
||||
}
|
||||
scene.EntityComponent.Destroy(this);
|
||||
|
||||
if (Parent != null && Parent != this && !Parent.IsDisposed)
|
||||
{
|
||||
Parent.RemoveComponent(this, false);
|
||||
Parent = null;
|
||||
}
|
||||
|
||||
Id = 0;
|
||||
Scene = null;
|
||||
Parent = null;
|
||||
scene.RemoveEntity(runTimeId);
|
||||
|
||||
if (IsPool())
|
||||
{
|
||||
scene.EntityPool.Return(Type, this);
|
||||
}
|
||||
|
||||
Type = null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Pool
|
||||
|
||||
/// <summary>
|
||||
/// 获取一个值,该值指示当前实例是否为对象池中的实例。
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool IsPool()
|
||||
{
|
||||
return _isPool;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置一个值,该值指示当前实例是否为对象池中的实例。
|
||||
/// </summary>
|
||||
/// <param name="isPool"></param>
|
||||
public void SetIsPool(bool isPool)
|
||||
{
|
||||
_isPool = isPool;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/NBC/Runtime/Core/Entitas/Entity.cs.meta
Normal file
11
Assets/Scripts/NBC/Runtime/Core/Entitas/Entity.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0a47c9eec9972439e88417f2f4b18482
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
66
Assets/Scripts/NBC/Runtime/Core/Entitas/EntityPool.cs
Normal file
66
Assets/Scripts/NBC/Runtime/Core/Entitas/EntityPool.cs
Normal file
@@ -0,0 +1,66 @@
|
||||
using System.Collections.Generic;
|
||||
using NBC.Pool;
|
||||
|
||||
#pragma warning disable CS8714 // The type cannot be used as type parameter in the generic type or method. Nullability of type argument doesn't match 'notnull' constraint.
|
||||
|
||||
namespace NBC.Entitas
|
||||
{
|
||||
internal sealed class EntityPool : PoolCore
|
||||
{
|
||||
public EntityPool() : base(4096) { }
|
||||
}
|
||||
|
||||
internal sealed class EntityList<T> : List<T>, IPool where T : Entity
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class EntityListPool<T> : PoolCore<EntityList<T>> where T : Entity
|
||||
{
|
||||
public EntityListPool() : base(4096) { }
|
||||
}
|
||||
|
||||
internal sealed class EntitySortedDictionary<TM, TN> : SortedDictionary<TM, TN>, IPool where TN : Entity
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class EntitySortedDictionaryPool<TM, TN> : PoolCore<EntitySortedDictionary<TM, TN>> where TN : Entity
|
||||
{
|
||||
public EntitySortedDictionaryPool() : base(4096) { }
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/NBC/Runtime/Core/Entitas/EntityPool.cs.meta
Normal file
11
Assets/Scripts/NBC/Runtime/Core/Entitas/EntityPool.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f30a1dcea6418429889f3e2216a883c6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
59
Assets/Scripts/NBC/Runtime/Core/Entitas/EntityReference.cs
Normal file
59
Assets/Scripts/NBC/Runtime/Core/Entitas/EntityReference.cs
Normal file
@@ -0,0 +1,59 @@
|
||||
// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
|
||||
#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.
|
||||
#pragma warning disable CS8603 // Possible null reference return.
|
||||
namespace NBC.Entitas
|
||||
{
|
||||
/// <summary>
|
||||
/// 实体引用检查组件
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public struct EntityReference<T> where T : Entity
|
||||
{
|
||||
private T _entity;
|
||||
private readonly long _runTimeId;
|
||||
|
||||
private EntityReference(T t)
|
||||
{
|
||||
if (t == null)
|
||||
{
|
||||
_entity = null;
|
||||
_runTimeId = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
_entity = t;
|
||||
_runTimeId = t.RuntimeId;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将一个实体转换为EntityReference
|
||||
/// </summary>
|
||||
/// <param name="t">实体泛型类型</param>
|
||||
/// <returns>返回一个EntityReference</returns>
|
||||
public static implicit operator EntityReference<T>(T t)
|
||||
{
|
||||
return new EntityReference<T>(t);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将一个EntityReference转换为实体
|
||||
/// </summary>
|
||||
/// <param name="v">实体泛型类型</param>
|
||||
/// <returns>当实体已经被销毁过会返回null</returns>
|
||||
public static implicit operator T(EntityReference<T> v)
|
||||
{
|
||||
if (v._entity == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (v._entity.RuntimeId != v._runTimeId)
|
||||
{
|
||||
v._entity = null;
|
||||
}
|
||||
|
||||
return v._entity;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: aba2430182a244c3393abe66830172b9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/Scripts/NBC/Runtime/Core/Entitas/Interface.meta
Normal file
8
Assets/Scripts/NBC/Runtime/Core/Entitas/Interface.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9b2fb651801ec40d1a0565114e0059d6
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9255f085833224805bf13e026b755fd2
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,17 @@
|
||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||
namespace NBC.Entitas.Interface
|
||||
{
|
||||
/// <summary>
|
||||
/// Entity保存到数据库的时候会根据子组件设置分离存储特性分表存储在不同的集合表中
|
||||
/// </summary>
|
||||
public interface ISingleCollectionRoot { }
|
||||
public static class SingleCollectionRootChecker<T> where T : Entity
|
||||
{
|
||||
public static bool IsSupported { get; }
|
||||
|
||||
static SingleCollectionRootChecker()
|
||||
{
|
||||
IsSupported = typeof(ISingleCollectionRoot).IsAssignableFrom(typeof(T));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 57298dd8265554d6087d79ef5a6e89cc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,19 @@
|
||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||
namespace NBC.Entitas.Interface
|
||||
{
|
||||
/// <summary>
|
||||
/// Entity支持数据库
|
||||
/// </summary>
|
||||
// ReSharper disable once InconsistentNaming
|
||||
public interface ISupportedDataBase { }
|
||||
|
||||
public static class SupportedDataBaseChecker<T> where T : Entity
|
||||
{
|
||||
public static bool IsSupported { get; }
|
||||
|
||||
static SupportedDataBaseChecker()
|
||||
{
|
||||
IsSupported = typeof(ISupportedDataBase).IsAssignableFrom(typeof(T));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ae64989e8b146443e99c66290b20a3c8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||
|
||||
namespace NBC.Entitas.Interface
|
||||
{
|
||||
/// <summary>
|
||||
/// 支持再一个组件里添加多个同类型组件
|
||||
/// </summary>
|
||||
public interface ISupportedMultiEntity : IDisposable { }
|
||||
|
||||
public static class SupportedMultiEntityChecker<T> where T : Entity
|
||||
{
|
||||
public static bool IsSupported { get; }
|
||||
|
||||
static SupportedMultiEntityChecker()
|
||||
{
|
||||
IsSupported = typeof(ISupportedMultiEntity).IsAssignableFrom(typeof(T));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 36105e7ed5c974fdabf37eead97ef95c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,47 @@
|
||||
using System;
|
||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||
namespace NBC.Entitas.Interface
|
||||
{
|
||||
// Entity是单一集合、保存到数据库的时候不会跟随父组件保存在一个集合里、会单独保存在一个集合里
|
||||
// 需要配合SingleCollectionAttribute一起使用、如在Entity类头部定义SingleCollectionAttribute(typeOf(Unit))
|
||||
// SingleCollectionAttribute用来定义这个Entity是属于哪个Entity的子集
|
||||
/// <summary>
|
||||
/// 定义实体支持单一集合存储的接口。当实体需要单独存储在一个集合中,并且在保存到数据库时不会与父组件一起保存在同一个集合中时,应实现此接口。
|
||||
/// </summary>
|
||||
public interface ISupportedSingleCollection { }
|
||||
public static class SupportedSingleCollectionChecker<T> where T : Entity
|
||||
{
|
||||
public static bool IsSupported { get; }
|
||||
|
||||
static SupportedSingleCollectionChecker()
|
||||
{
|
||||
IsSupported = typeof(ISupportedSingleCollection).IsAssignableFrom(typeof(T));
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 表示用于指定实体的单一集合存储属性。此属性用于配合 <see cref="ISupportedSingleCollection"/> 接口使用,
|
||||
/// 用于定义实体属于哪个父实体的子集合,以及在数据库中使用的集合名称。
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = false)]
|
||||
public class SingleCollectionAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取父实体的类型,指示此实体是属于哪个父实体的子集合。
|
||||
/// </summary>
|
||||
public readonly Type RootType;
|
||||
/// <summary>
|
||||
/// 获取在数据库中使用的集合名称。
|
||||
/// </summary>
|
||||
public readonly string CollectionName;
|
||||
/// <summary>
|
||||
/// 初始化 <see cref="SingleCollectionAttribute"/> 类的新实例,指定父实体类型和集合名称。
|
||||
/// </summary>
|
||||
/// <param name="rootType">父实体的类型。</param>
|
||||
/// <param name="collectionName">在数据库中使用的集合名称。</param>
|
||||
public SingleCollectionAttribute(Type rootType, string collectionName)
|
||||
{
|
||||
RootType = rootType;
|
||||
CollectionName = collectionName;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: afd453d04ac254206a9bb83664a888a0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,16 @@
|
||||
namespace NBC.Entitas.Interface
|
||||
{
|
||||
/// <summary>
|
||||
/// Entity支持传送
|
||||
/// </summary>
|
||||
public interface ISupportedTransfer { }
|
||||
public static class SupportedTransferChecker<T> where T : Entity
|
||||
{
|
||||
public static bool IsSupported { get; }
|
||||
|
||||
static SupportedTransferChecker()
|
||||
{
|
||||
IsSupported = typeof(ISupportedTransfer).IsAssignableFrom(typeof(T));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a127a7c6e345a42e3860b804457f0fe5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 275ef1a555d6f41cbb322011303dd57c
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,32 @@
|
||||
using System;
|
||||
using NBC.Async;
|
||||
|
||||
namespace NBC.Entitas.Interface
|
||||
{
|
||||
internal interface IAwakeSystem : IEntitiesSystem { }
|
||||
/// <summary>
|
||||
/// 实体的Awake事件的抽象接口
|
||||
/// </summary>
|
||||
/// <typeparam name="T">实体的泛型类型</typeparam>
|
||||
public abstract class AwakeSystem<T> : IAwakeSystem where T : Entity
|
||||
{
|
||||
/// <summary>
|
||||
/// 实体的类型
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Type EntitiesType() => typeof(T);
|
||||
/// <summary>
|
||||
/// 事件的抽象方法,需要自己实现这个方法
|
||||
/// </summary>
|
||||
/// <param name="self">触发事件的实体实例</param>
|
||||
protected abstract void Awake(T self);
|
||||
/// <summary>
|
||||
/// 框架内部调用的触发Awake的方法。
|
||||
/// </summary>
|
||||
/// <param name="self">触发事件的实体实例</param>
|
||||
public void Invoke(Entity self)
|
||||
{
|
||||
Awake((T) self);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fe2caf80007df454bb76729547780d28
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,59 @@
|
||||
using System;
|
||||
|
||||
namespace NBC.Entitas.Interface
|
||||
{
|
||||
/// <summary>
|
||||
/// 自定义组件事件系统接口
|
||||
/// 如果需要自定义组件事件系统,请继承此接口。
|
||||
/// 这个接口内部使用。不对外开放。
|
||||
/// </summary>
|
||||
internal interface ICustomEntitiesSystem
|
||||
{
|
||||
/// <summary>
|
||||
/// 事件类型
|
||||
/// 用于触发这个组件事件关键因素。
|
||||
/// </summary>
|
||||
int CustomEventType { get; }
|
||||
/// <summary>
|
||||
/// 实体的类型
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Type EntitiesType();
|
||||
/// <summary>
|
||||
/// 框架内部调用的触发事件方法
|
||||
/// </summary>
|
||||
/// <param name="entity"></param>
|
||||
void Invoke(Entity entity);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 自定义组件事件系统抽象类
|
||||
/// 如果需要自定义组件事件系统,请继承此抽象类。
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public abstract class CustomSystem<T> : ICustomEntitiesSystem where T : Entity
|
||||
{
|
||||
/// <summary>
|
||||
/// 这个1表示是一个自定义事件类型,执行这个事件是时候需要用到这个1.
|
||||
/// </summary>
|
||||
public abstract int CustomEventType { get; }
|
||||
/// <summary>
|
||||
/// 事件的抽象方法,需要自己实现这个方法
|
||||
/// </summary>
|
||||
/// <param name="self">触发事件的实体实例</param>
|
||||
protected abstract void Custom(T self);
|
||||
/// <summary>
|
||||
/// 实体的类型
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public abstract Type EntitiesType();
|
||||
/// <summary>
|
||||
/// 框架内部调用的触发Awake的方法。
|
||||
/// </summary>
|
||||
/// <param name="self">触发事件的实体实例</param>
|
||||
public void Invoke(Entity self)
|
||||
{
|
||||
Custom((T) self);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8babd948f5d51430db4d8ac333b25d54
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,32 @@
|
||||
using System;
|
||||
using NBC.Async;
|
||||
|
||||
namespace NBC.Entitas.Interface
|
||||
{
|
||||
internal interface IDeserializeSystem : IEntitiesSystem { }
|
||||
/// <summary>
|
||||
/// 实体的反序列化事件的抽象接口
|
||||
/// </summary>
|
||||
/// <typeparam name="T">实体的泛型数据</typeparam>
|
||||
public abstract class DeserializeSystem<T> : IDeserializeSystem where T : Entity
|
||||
{
|
||||
/// <summary>
|
||||
/// 实体的类型
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Type EntitiesType() => typeof(T);
|
||||
/// <summary>
|
||||
/// 事件的抽象方法,需要自己实现这个方法
|
||||
/// </summary>
|
||||
/// <param name="self">触发事件的实体实例</param>
|
||||
protected abstract void Deserialize(T self);
|
||||
/// <summary>
|
||||
/// 框架内部调用的触发Deserialize的方法
|
||||
/// </summary>
|
||||
/// <param name="self">触发事件的实体实例</param>
|
||||
public void Invoke(Entity self)
|
||||
{
|
||||
Deserialize((T) self);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f9d2fff74aed249e8aa0acbb122614c2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,32 @@
|
||||
using System;
|
||||
using NBC.Async;
|
||||
|
||||
namespace NBC.Entitas.Interface
|
||||
{
|
||||
internal interface IDestroySystem : IEntitiesSystem { }
|
||||
/// <summary>
|
||||
/// 实体销毁事件的抽象接口
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public abstract class DestroySystem<T> : IDestroySystem where T : Entity
|
||||
{
|
||||
/// <summary>
|
||||
/// 实体的类型
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Type EntitiesType() => typeof(T);
|
||||
/// <summary>
|
||||
/// 事件的抽象方法,需要自己实现这个方法
|
||||
/// </summary>
|
||||
/// <param name="self">触发事件的实体实例</param>
|
||||
protected abstract void Destroy(T self);
|
||||
/// <summary>
|
||||
/// 框架内部调用的触发Destroy的方法
|
||||
/// </summary>
|
||||
/// <param name="self"></param>
|
||||
public void Invoke(Entity self)
|
||||
{
|
||||
Destroy((T) self);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 899a57e15b99948c7bcaef5b76cae97c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using NBC.Async;
|
||||
|
||||
namespace NBC.Entitas.Interface
|
||||
{
|
||||
/// <summary>
|
||||
/// ECS事件系统的核心接口,任何事件都是要继承这个接口
|
||||
/// </summary>
|
||||
public interface IEntitiesSystem
|
||||
{
|
||||
/// <summary>
|
||||
/// 实体的类型
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Type EntitiesType();
|
||||
/// <summary>
|
||||
/// 框架内部调用的触发事件方法
|
||||
/// </summary>
|
||||
/// <param name="entity"></param>
|
||||
void Invoke(Entity entity);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 287ae5e33ccda4c28946371bcad4755b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,31 @@
|
||||
using System;
|
||||
|
||||
namespace NBC.Entitas.Interface
|
||||
{
|
||||
internal interface IFrameUpdateSystem : IEntitiesSystem { }
|
||||
/// <summary>
|
||||
/// 帧更新时间的抽象接口
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public abstract class FrameUpdateSystem<T> : IFrameUpdateSystem where T : Entity
|
||||
{
|
||||
/// <summary>
|
||||
/// 实体的类型
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Type EntitiesType() => typeof(T);
|
||||
/// <summary>
|
||||
/// 事件的抽象方法,需要自己实现这个方法
|
||||
/// </summary>
|
||||
/// <param name="self">触发事件的实体实例</param>
|
||||
protected abstract void FrameUpdate(T self);
|
||||
/// <summary>
|
||||
/// 框架内部调用的触发FrameUpdate的方法
|
||||
/// </summary>
|
||||
/// <param name="self"></param>
|
||||
public void Invoke(Entity self)
|
||||
{
|
||||
FrameUpdate((T) self);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b785fffadcd8c4461b1f1fcf397728b9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,31 @@
|
||||
using System;
|
||||
|
||||
namespace NBC.Entitas.Interface
|
||||
{
|
||||
internal interface IUpdateSystem : IEntitiesSystem { }
|
||||
/// <summary>
|
||||
/// Update事件的抽象接口
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public abstract class UpdateSystem<T> : IUpdateSystem where T : Entity
|
||||
{
|
||||
/// <summary>
|
||||
/// 实体的类型
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Type EntitiesType() => typeof(T);
|
||||
/// <summary>
|
||||
/// 事件的抽象方法,需要自己实现这个方法
|
||||
/// </summary>
|
||||
/// <param name="self">触发事件的实体实例</param>
|
||||
protected abstract void Update(T self);
|
||||
/// <summary>
|
||||
/// 框架内部调用的触发Update的方法
|
||||
/// </summary>
|
||||
/// <param name="self">触发事件的实体实例</param>
|
||||
public void Invoke(Entity self)
|
||||
{
|
||||
Update((T) self);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a40db65b7285747ffad3a0346966406c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user