Before 优化 机场
This commit is contained in:
@@ -1,8 +1,10 @@
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.AccessControl;
|
||||
using System.Threading;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
@@ -10,51 +12,77 @@ using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace BITKit.Entities
|
||||
{
|
||||
public class EntitiesService:IEntitiesService,IDisposable
|
||||
public class EntitiesService : IEntitiesService, IDisposable
|
||||
{
|
||||
private static int _count;
|
||||
|
||||
|
||||
private readonly ILogger<EntitiesService> _logger;
|
||||
private readonly IFixedTicker _ticker;
|
||||
private static int _count;
|
||||
private static readonly ConcurrentQueue<IEntity> OnAddQueue = new();
|
||||
|
||||
private readonly ConcurrentQueue<IEntity> _onAddQueue = new();
|
||||
private readonly ConcurrentDictionary<int, HashSet<int>> _typeCaches = new();
|
||||
|
||||
public EntitiesService(ILogger<EntitiesService> logger, IFixedTicker ticker)
|
||||
{
|
||||
_count++;
|
||||
|
||||
_logger = logger;
|
||||
_ticker = ticker;
|
||||
|
||||
|
||||
_count++;
|
||||
|
||||
|
||||
logger.LogInformation($"已创建EntitiesService,当前有:{_count}个实例");
|
||||
|
||||
_ticker.Add(OnTick);
|
||||
}
|
||||
|
||||
private void OnTick(float obj)
|
||||
{
|
||||
while (OnAddQueue.TryDequeue(out var entity))
|
||||
while (_onAddQueue.TryDequeue(out var entity))
|
||||
{
|
||||
OnAdd?.Invoke(entity);
|
||||
|
||||
foreach (var serviceDescriptor in entity.ServiceCollection)
|
||||
{
|
||||
var typeHash = serviceDescriptor.ServiceType.GetHashCode();
|
||||
var hashSet = _typeCaches.GetOrCreate(typeHash);
|
||||
hashSet.Add(entity.Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private static readonly ConcurrentDictionary<int, IEntity> Entities = new();
|
||||
public event Action<IEntity> OnAdd;
|
||||
public event Action<IEntity> OnRemove;
|
||||
IReadOnlyDictionary<int, IEntity> IEntitiesService.Entities => Entities;
|
||||
|
||||
public bool Register(IEntity entity)
|
||||
{
|
||||
if (!Entities.TryAdd(entity.Id, entity)) return false;
|
||||
OnAddQueue.Enqueue(entity);
|
||||
_onAddQueue.Enqueue(entity);
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool UnRegister(IEntity entity)
|
||||
{
|
||||
if (!Entities.TryRemove(entity.Id, out _)) return false;
|
||||
OnRemove?.Invoke(entity);
|
||||
OnRemove?.Invoke(entity);
|
||||
|
||||
foreach (var serviceDescriptor in entity.ServiceCollection)
|
||||
{
|
||||
var typeHash = serviceDescriptor.ServiceType.GetHashCode();
|
||||
var hashSet = _typeCaches.GetOrCreate(typeHash);
|
||||
hashSet.Remove(entity.Id);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public CancellationToken CancellationToken => _cancellationTokenSource.Token;
|
||||
private readonly CancellationTokenSource _cancellationTokenSource = new();
|
||||
|
||||
public IEntity Get(int id)
|
||||
{
|
||||
return Entities[id];
|
||||
@@ -70,194 +98,247 @@ namespace BITKit.Entities
|
||||
return Entities.GetOrAdd(id, factory);
|
||||
}
|
||||
|
||||
public IEntity[] Query<T>()
|
||||
public Span<T> QueryComponents<T>()
|
||||
{
|
||||
throw new NotImplementedException("Obsoleted");
|
||||
}
|
||||
var pool = ArrayPool<T>.Shared;
|
||||
var hashset = _typeCaches.GetOrCreate(typeof(T).GetHashCode());
|
||||
|
||||
public T[] QueryComponents<T>()
|
||||
{
|
||||
var list = new List<T>();
|
||||
foreach (var entity in Entities.Values)
|
||||
var count = hashset.Count;
|
||||
var array = pool.Rent(count); // ✅ 从池中获取数组,避免 GC
|
||||
|
||||
var i = 0;
|
||||
foreach (var id in hashset)
|
||||
{
|
||||
if (entity.ServiceProvider.GetService<T>() is { } t1)
|
||||
{
|
||||
list.Add(t1);
|
||||
}
|
||||
array[i] = Entities[id].ServiceProvider.GetRequiredService<T>();
|
||||
i++;
|
||||
}
|
||||
|
||||
return list.ToArray();
|
||||
// return _queryCache.GetOrAdd(typeof(T), type =>
|
||||
// {
|
||||
// return _entities.Values.Where(entity => entity.TryGetComponent(out T component)).ToArray();
|
||||
// }).Cast<T>().ToArray();
|
||||
// 🚀 使用 `GCHandle` 固定数组,防止被 GC 移动
|
||||
var handle = GCHandle.Alloc(array, GCHandleType.Pinned);
|
||||
try
|
||||
{
|
||||
return new Span<T>(array, 0, count); // ✅ 返回 `Span<T>`,无额外拷贝
|
||||
}
|
||||
finally
|
||||
{
|
||||
handle.Free(); // ✅ 释放 `GCHandle`,防止内存泄漏
|
||||
pool.Return(array); // ✅ 归还 ArrayPool
|
||||
}
|
||||
}
|
||||
|
||||
public (T, T1)[] QueryComponents<T, T1>()
|
||||
{
|
||||
var list = new List<(T, T1)>();
|
||||
foreach (var entity in Entities.Values)
|
||||
{
|
||||
if (entity.ServiceProvider.GetService<T>() is { } t1 &&
|
||||
entity.ServiceProvider.GetService<T1>() is { } t2)
|
||||
{
|
||||
list.Add((t1, t2));
|
||||
}
|
||||
}
|
||||
|
||||
return list.ToArray();
|
||||
// List<(T, T1)> list = new();
|
||||
// foreach (var entity in _entities.Values)
|
||||
// {
|
||||
// if (entity.TryGetComponent(out T t) && entity.TryGetComponent(out T1 t1))
|
||||
// list.Add((t, t1));
|
||||
// }
|
||||
// return list.ToArray();
|
||||
}
|
||||
public (T, T1, T2)[] QueryComponents<T, T1, T2>()
|
||||
{
|
||||
var list = new List<(T, T1, T2)>();
|
||||
foreach (var entity in Entities.Values)
|
||||
{
|
||||
if (entity.ServiceProvider.GetService<T>() is { } t1 &&
|
||||
entity.ServiceProvider.GetService<T1>() is { } t2 &&
|
||||
entity.ServiceProvider.GetService<T2>() is { } t3)
|
||||
{
|
||||
list.Add((t1, t2, t3));
|
||||
}
|
||||
}
|
||||
|
||||
return list.ToArray();
|
||||
// List<(T, T1, T2)> list = new();
|
||||
// foreach (var entity in _entities.Values)
|
||||
// {
|
||||
// if (entity.TryGetComponent(out T t) && entity.TryGetComponent(out T1 t1) && entity.TryGetComponent(out T2 t2))
|
||||
// list.Add((t, t1, t2));
|
||||
// }
|
||||
// return list.ToArray();
|
||||
}
|
||||
|
||||
public (T, T1, T2, T3)[] QueryComponents<T, T1, T2, T3>()
|
||||
public Span<(T, T1)> QueryComponents<T, T1>()
|
||||
{
|
||||
var list = new List<(T, T1, T2, T3)>();
|
||||
foreach (var entity in Entities.Values)
|
||||
{
|
||||
if (entity.ServiceProvider.GetService<T>() is { } t1 &&
|
||||
entity.ServiceProvider.GetService<T1>() is { } t2 &&
|
||||
entity.ServiceProvider.GetService<T2>() is { } t3 &&
|
||||
entity.ServiceProvider.GetService<T3>() is { } t4)
|
||||
{
|
||||
list.Add((t1, t2, t3, t4));
|
||||
}
|
||||
}
|
||||
|
||||
return list.ToArray();
|
||||
// List<(T, T1, T2, T3)> list = new();
|
||||
// foreach (var entity in _entities.Values)
|
||||
// {
|
||||
// if (entity.TryGetComponent(out T t) && entity.TryGetComponent(out T1 t1) && entity.TryGetComponent(out T2 t2) && entity.TryGetComponent(out T3 t3))
|
||||
// list.Add((t, t1, t2, t3));
|
||||
// }
|
||||
// return list.ToArray();
|
||||
}
|
||||
var pool = ArrayPool<(T, T1)>.Shared;
|
||||
var hashset = _typeCaches.GetOrCreate(typeof(T).GetHashCode());
|
||||
var t1Set = _typeCaches.GetOrCreate(typeof(T1).GetHashCode());
|
||||
|
||||
public (T, T1, T2, T3, T4)[] QueryComponents<T, T1, T2, T3, T4>()
|
||||
{
|
||||
var list = new List<(T, T1, T2, T3, T4)>();
|
||||
foreach (var entity in Entities.Values)
|
||||
{
|
||||
if (entity.ServiceProvider.GetService<T>() is { } t1 &&
|
||||
entity.ServiceProvider.GetService<T1>() is { } t2 &&
|
||||
entity.ServiceProvider.GetService<T2>() is { } t3 &&
|
||||
entity.ServiceProvider.GetService<T3>() is { } t4 &&
|
||||
entity.ServiceProvider.GetService<T4>() is { } t5)
|
||||
{
|
||||
list.Add((t1, t2, t3, t4, t5));
|
||||
}
|
||||
}
|
||||
|
||||
return list.ToArray();
|
||||
// List<(T, T1, T2, T3, T4)> list = new();
|
||||
// foreach (var entity in _entities.Values)
|
||||
// {
|
||||
// if (entity.TryGetComponent(out T t) && entity.TryGetComponent(out T1 t1) && entity.TryGetComponent(out T2 t2) && entity.TryGetComponent(out T3 t3) && entity.TryGetComponent(out T4 t4))
|
||||
// list.Add((t, t1, t2, t3, t4));
|
||||
// }
|
||||
// return list.ToArray();
|
||||
}
|
||||
var count = hashset.Count;
|
||||
var array = pool.Rent(count);
|
||||
|
||||
public (T, T1, T2, T3, T4, T5)[] QueryComponents<T, T1, T2, T3, T4, T5>()
|
||||
{
|
||||
var list = new List<(T, T1, T2, T3, T4, T5)>();
|
||||
foreach (var entity in Entities.Values)
|
||||
var i = 0;
|
||||
foreach (var id in hashset.Intersect(t1Set))
|
||||
{
|
||||
if (entity.ServiceProvider.GetService<T>() is { } t1 &&
|
||||
entity.ServiceProvider.GetService<T1>() is { } t2 &&
|
||||
entity.ServiceProvider.GetService<T2>() is { } t3 &&
|
||||
entity.ServiceProvider.GetService<T3>() is { } t4 &&
|
||||
entity.ServiceProvider.GetService<T4>() is { } t5 &&
|
||||
entity.ServiceProvider.GetService<T5>() is { } t6)
|
||||
{
|
||||
list.Add((t1, t2, t3, t4, t5, t6));
|
||||
}
|
||||
}
|
||||
|
||||
return list.ToArray();
|
||||
// List<(T, T1, T2, T3, T4, T5)> list = new();
|
||||
// foreach (var entity in _entities.Values)
|
||||
// {
|
||||
// if (entity.TryGetComponent(out T t) && entity.TryGetComponent(out T1 t1) && entity.TryGetComponent(out T2 t2) && entity.TryGetComponent(out T3 t3) && entity.TryGetComponent(out T4 t4) && entity.TryGetComponent(out T5 t5))
|
||||
// list.Add((t, t1, t2, t3, t4, t5));
|
||||
// }
|
||||
// return list.ToArray();
|
||||
}
|
||||
|
||||
public (T, T1, T2, T3, T4, T5, T6)[] QueryComponents<T, T1, T2, T3, T4, T5, T6>()
|
||||
{
|
||||
var list = new List<(T, T1, T2, T3, T4, T5, T6)>();
|
||||
foreach (var entity in Entities.Values)
|
||||
{
|
||||
if (entity.ServiceProvider.GetService<T>() is { } t1 &&
|
||||
entity.ServiceProvider.GetService<T1>() is { } t2 &&
|
||||
entity.ServiceProvider.GetService<T2>() is { } t3 &&
|
||||
entity.ServiceProvider.GetService<T3>() is { } t4 &&
|
||||
entity.ServiceProvider.GetService<T4>() is { } t5 &&
|
||||
entity.ServiceProvider.GetService<T5>() is { } t6 &&
|
||||
entity.ServiceProvider.GetService<T6>() is { } t7)
|
||||
{
|
||||
list.Add((t1, t2, t3, t4, t5, t6, t7));
|
||||
}
|
||||
var entity = Entities[id];
|
||||
array[i] = (entity.ServiceProvider.GetRequiredService<T>(),
|
||||
entity.ServiceProvider.GetRequiredService<T1>());
|
||||
i++;
|
||||
}
|
||||
|
||||
return list.ToArray();
|
||||
// List<(T, T1, T2, T3, T4, T5, T6)> list = new();
|
||||
// foreach (var entity in _entities.Values)
|
||||
// {
|
||||
// if (entity.TryGetComponent(out T t) && entity.TryGetComponent(out T1 t1) && entity.TryGetComponent(out T2 t2) && entity.TryGetComponent(out T3 t3) && entity.TryGetComponent(out T4 t4) && entity.TryGetComponent(out T5 t5) && entity.TryGetComponent(out T6 t6))
|
||||
// list.Add((t, t1, t2, t3, t4, t5, t6));
|
||||
// }
|
||||
// return list.ToArray();
|
||||
var handle = GCHandle.Alloc(array, GCHandleType.Pinned);
|
||||
try
|
||||
{
|
||||
return new Span<(T, T1)>(array, 0, count);
|
||||
}
|
||||
finally
|
||||
{
|
||||
handle.Free();
|
||||
pool.Return(array);
|
||||
}
|
||||
}
|
||||
|
||||
public ValueTuple<T, T1, T2, T3, T4, T5, T6, TRest>[] QueryComponents<T, T1, T2, T3, T4, T5, T6, TRest>()
|
||||
where TRest : struct
|
||||
public Span<(T, T1, T2)> QueryComponents<T, T1, T2>()
|
||||
{
|
||||
var list = new List<ValueTuple<T, T1, T2, T3, T4, T5, T6, TRest>>();
|
||||
foreach (var entity in Entities.Values)
|
||||
var pool = ArrayPool<(T, T1, T2)>.Shared;
|
||||
var hashset = _typeCaches.GetOrCreate(typeof(T).GetHashCode());
|
||||
var t1Set = _typeCaches.GetOrCreate(typeof(T1).GetHashCode());
|
||||
var t2Set = _typeCaches.GetOrCreate(typeof(T2).GetHashCode());
|
||||
|
||||
var count = hashset.Count;
|
||||
var array = pool.Rent(count);
|
||||
|
||||
var i = 0;
|
||||
foreach (var id in hashset.Intersect(t1Set).Intersect(t2Set))
|
||||
{
|
||||
if (entity.ServiceProvider.GetService<T>() is { } t1 &&
|
||||
entity.ServiceProvider.GetService<T1>() is { } t2 &&
|
||||
entity.ServiceProvider.GetService<T2>() is { } t3 &&
|
||||
entity.ServiceProvider.GetService<T3>() is { } t4 &&
|
||||
entity.ServiceProvider.GetService<T4>() is { } t5 &&
|
||||
entity.ServiceProvider.GetService<T5>() is { } t6 &&
|
||||
entity.ServiceProvider.GetService<T6>() is { } t7 &&
|
||||
entity.ServiceProvider.GetService<TRest>() is { } t8)
|
||||
{
|
||||
list.Add(new ValueTuple<T, T1, T2, T3, T4, T5, T6, TRest>(t1, t2, t3, t4, t5, t6, t7, t8));
|
||||
}
|
||||
var entity = Entities[id];
|
||||
array[i] = (entity.ServiceProvider.GetRequiredService<T>(),
|
||||
entity.ServiceProvider.GetRequiredService<T1>(),
|
||||
entity.ServiceProvider.GetRequiredService<T2>());
|
||||
i++;
|
||||
}
|
||||
|
||||
var handle = GCHandle.Alloc(array, GCHandleType.Pinned);
|
||||
try
|
||||
{
|
||||
return new Span<(T, T1, T2)>(array, 0, count);
|
||||
}
|
||||
finally
|
||||
{
|
||||
handle.Free();
|
||||
pool.Return(array);
|
||||
}
|
||||
}
|
||||
|
||||
public Span<(T, T1, T2, T3)> QueryComponents<T, T1, T2, T3>()
|
||||
{
|
||||
var pool = ArrayPool<(T, T1, T2, T3)>.Shared;
|
||||
var hashset = _typeCaches.GetOrCreate(typeof(T).GetHashCode());
|
||||
var t1Set = _typeCaches.GetOrCreate(typeof(T1).GetHashCode());
|
||||
var t2Set = _typeCaches.GetOrCreate(typeof(T2).GetHashCode());
|
||||
var t3Set = _typeCaches.GetOrCreate(typeof(T3).GetHashCode());
|
||||
|
||||
var count = hashset.Count;
|
||||
var array = pool.Rent(count);
|
||||
|
||||
var i = 0;
|
||||
foreach (var id in hashset.Intersect(t1Set).Intersect(t2Set).Intersect(t3Set))
|
||||
{
|
||||
var entity = Entities[id];
|
||||
array[i] = (entity.ServiceProvider.GetRequiredService<T>(),
|
||||
entity.ServiceProvider.GetRequiredService<T1>(),
|
||||
entity.ServiceProvider.GetRequiredService<T2>(),
|
||||
entity.ServiceProvider.GetRequiredService<T3>());
|
||||
i++;
|
||||
}
|
||||
|
||||
var handle = GCHandle.Alloc(array, GCHandleType.Pinned);
|
||||
try
|
||||
{
|
||||
return new Span<(T, T1, T2, T3)>(array, 0, count);
|
||||
}
|
||||
finally
|
||||
{
|
||||
handle.Free();
|
||||
pool.Return(array);
|
||||
}
|
||||
}
|
||||
|
||||
public Span<(T, T1, T2, T3, T4)> QueryComponents<T, T1, T2, T3, T4>()
|
||||
{
|
||||
var pool = ArrayPool<(T, T1, T2, T3, T4)>.Shared;
|
||||
var hashset = _typeCaches.GetOrCreate(typeof(T).GetHashCode());
|
||||
var t1Set = _typeCaches.GetOrCreate(typeof(T1).GetHashCode());
|
||||
var t2Set = _typeCaches.GetOrCreate(typeof(T2).GetHashCode());
|
||||
var t3Set = _typeCaches.GetOrCreate(typeof(T3).GetHashCode());
|
||||
var t4Set = _typeCaches.GetOrCreate(typeof(T4).GetHashCode());
|
||||
|
||||
var count = hashset.Count;
|
||||
var array = pool.Rent(count);
|
||||
|
||||
var i = 0;
|
||||
foreach (var id in hashset.Intersect(t1Set).Intersect(t2Set).Intersect(t3Set).Intersect(t4Set))
|
||||
{
|
||||
var entity = Entities[id];
|
||||
array[i] = (entity.ServiceProvider.GetRequiredService<T>(),
|
||||
entity.ServiceProvider.GetRequiredService<T1>(),
|
||||
entity.ServiceProvider.GetRequiredService<T2>(),
|
||||
entity.ServiceProvider.GetRequiredService<T3>(),
|
||||
entity.ServiceProvider.GetRequiredService<T4>());
|
||||
i++;
|
||||
}
|
||||
|
||||
var handle = GCHandle.Alloc(array, GCHandleType.Pinned);
|
||||
try
|
||||
{
|
||||
return new Span<(T, T1, T2, T3, T4)>(array, 0, count);
|
||||
}
|
||||
finally
|
||||
{
|
||||
handle.Free();
|
||||
pool.Return(array);
|
||||
}
|
||||
}
|
||||
|
||||
public Span<(T, T1, T2, T3, T4, T5)> QueryComponents<T, T1, T2, T3, T4, T5>()
|
||||
{
|
||||
var pool = ArrayPool<(T, T1, T2, T3, T4, T5)>.Shared;
|
||||
var hashset = _typeCaches.GetOrCreate(typeof(T).GetHashCode());
|
||||
var t1Set = _typeCaches.GetOrCreate(typeof(T1).GetHashCode());
|
||||
var t2Set = _typeCaches.GetOrCreate(typeof(T2).GetHashCode());
|
||||
var t3Set = _typeCaches.GetOrCreate(typeof(T3).GetHashCode());
|
||||
var t4Set = _typeCaches.GetOrCreate(typeof(T4).GetHashCode());
|
||||
var t5Set = _typeCaches.GetOrCreate(typeof(T5).GetHashCode());
|
||||
|
||||
var count = hashset.Count;
|
||||
var array = pool.Rent(count);
|
||||
|
||||
var i = 0;
|
||||
foreach (var id in hashset.Intersect(t1Set).Intersect(t2Set).Intersect(t3Set).Intersect(t4Set)
|
||||
.Intersect(t5Set))
|
||||
{
|
||||
var entity = Entities[id];
|
||||
array[i] = (entity.ServiceProvider.GetRequiredService<T>(),
|
||||
entity.ServiceProvider.GetRequiredService<T1>(),
|
||||
entity.ServiceProvider.GetRequiredService<T2>(),
|
||||
entity.ServiceProvider.GetRequiredService<T3>(),
|
||||
entity.ServiceProvider.GetRequiredService<T4>(),
|
||||
entity.ServiceProvider.GetRequiredService<T5>()
|
||||
);
|
||||
i++;
|
||||
}
|
||||
|
||||
var handle = GCHandle.Alloc(array, GCHandleType.Pinned);
|
||||
try
|
||||
{
|
||||
return new Span<(T, T1, T2, T3, T4, T5)>(array, 0, count);
|
||||
}
|
||||
finally
|
||||
{
|
||||
handle.Free();
|
||||
pool.Return(array);
|
||||
}
|
||||
}
|
||||
|
||||
public Span<(T, T1, T2, T3, T4, T5, T6)> QueryComponents<T, T1, T2, T3, T4, T5, T6>()
|
||||
{
|
||||
var pool = ArrayPool<(T, T1, T2, T3, T4, T5, T6)>.Shared;
|
||||
var hashset = _typeCaches.GetOrCreate(typeof(T).GetHashCode());
|
||||
var t1Set = _typeCaches.GetOrCreate(typeof(T1).GetHashCode());
|
||||
var t2Set = _typeCaches.GetOrCreate(typeof(T2).GetHashCode());
|
||||
var t3Set = _typeCaches.GetOrCreate(typeof(T3).GetHashCode());
|
||||
var t4Set = _typeCaches.GetOrCreate(typeof(T4).GetHashCode());
|
||||
var t5Set = _typeCaches.GetOrCreate(typeof(T5).GetHashCode());
|
||||
var t6Set = _typeCaches.GetOrCreate(typeof(T6).GetHashCode());
|
||||
|
||||
var count = hashset.Count;
|
||||
var array = pool.Rent(count);
|
||||
|
||||
var i = 0;
|
||||
foreach (var id in hashset.Intersect(t1Set).Intersect(t2Set).Intersect(t3Set).Intersect(t4Set)
|
||||
.Intersect(t5Set).Intersect(t6Set))
|
||||
{
|
||||
var entity = Entities[id];
|
||||
array[i] = (entity.ServiceProvider.GetRequiredService<T>(),
|
||||
entity.ServiceProvider.GetRequiredService<T1>(),
|
||||
entity.ServiceProvider.GetRequiredService<T2>(),
|
||||
entity.ServiceProvider.GetRequiredService<T3>(),
|
||||
entity.ServiceProvider.GetRequiredService<T4>(),
|
||||
entity.ServiceProvider.GetRequiredService<T5>(),
|
||||
entity.ServiceProvider.GetRequiredService<T6>()
|
||||
);
|
||||
i++;
|
||||
}
|
||||
|
||||
var handle = GCHandle.Alloc(array, GCHandleType.Pinned);
|
||||
try
|
||||
{
|
||||
return new Span<(T, T1, T2, T3, T4, T5, T6)>(array, 0, count);
|
||||
}
|
||||
finally
|
||||
{
|
||||
handle.Free();
|
||||
pool.Return(array);
|
||||
}
|
||||
return list.ToArray();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
@@ -267,11 +348,11 @@ namespace BITKit.Entities
|
||||
{
|
||||
Entities.Clear();
|
||||
}
|
||||
|
||||
|
||||
_logger.LogInformation($"已释放,还剩{_count}个实例");
|
||||
|
||||
|
||||
_cancellationTokenSource?.Dispose();
|
||||
|
||||
|
||||
_ticker.Remove(OnTick);
|
||||
}
|
||||
}
|
||||
|
@@ -8,23 +8,24 @@ namespace BITKit.Entities
|
||||
{
|
||||
public class Entity : IEntity, IDisposable
|
||||
{
|
||||
public Entity()
|
||||
{
|
||||
ServiceCollection.AddSingleton<IEntity>(this);
|
||||
}
|
||||
public void WaitForInitializationComplete()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
public int Id { get; set; } = Guid.NewGuid().GetHashCode();
|
||||
public CancellationToken CancellationToken { get; set; }
|
||||
|
||||
public IServiceProvider ServiceProvider => _serviceProvider ??= ServiceCollection.BuildServiceProvider();
|
||||
private ServiceProvider _serviceProvider;
|
||||
public IServiceCollection ServiceCollection { get; } = new ServiceCollection();
|
||||
public IServiceCollection ServiceCollection
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_serviceCollection is not null) return _serviceCollection;
|
||||
_serviceCollection = new ServiceCollection();
|
||||
_serviceCollection.AddSingleton<IEntity>(this);
|
||||
return _serviceCollection;
|
||||
}
|
||||
}
|
||||
|
||||
private IServiceCollection _serviceCollection;
|
||||
|
||||
public object[] GetServices() => ServiceCollection.ToArray()
|
||||
.Select(x => _serviceProvider.GetService(x.ServiceType)).ToArray();
|
||||
public void Inject(object obj)
|
||||
{
|
||||
foreach (var fieldInfo in obj.GetType().GetFields(ReflectionHelper.Flags))
|
||||
|
@@ -66,19 +66,13 @@ namespace BITKit.Entities
|
||||
/// 通过Id获取或添加Entity
|
||||
/// </summary>
|
||||
IEntity GetOrAdd(int id,Func<int,IEntity> factory);
|
||||
|
||||
/// <summary>
|
||||
/// 查询Entity,例如
|
||||
/// </summary>
|
||||
/// <para>var rotationEntities=EntitiesService.Query<RotationComponent></para>
|
||||
IEntity[] Query<T>();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 查询1个组件
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
T[] QueryComponents<T>();
|
||||
Span<T> QueryComponents<T>();
|
||||
|
||||
/// <summary>
|
||||
/// 查询2个组件
|
||||
@@ -86,7 +80,7 @@ namespace BITKit.Entities
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <typeparam name="T1"></typeparam>
|
||||
/// <returns></returns>
|
||||
ValueTuple<T, T1>[] QueryComponents<T, T1>();
|
||||
Span<ValueTuple<T, T1>> QueryComponents<T, T1>();
|
||||
|
||||
/// <summary>
|
||||
/// 查询3个组件
|
||||
@@ -95,7 +89,7 @@ namespace BITKit.Entities
|
||||
/// <typeparam name="T1"></typeparam>
|
||||
/// <typeparam name="T2"></typeparam>
|
||||
/// <returns></returns>
|
||||
ValueTuple<T, T1, T2>[] QueryComponents<T, T1, T2>();
|
||||
Span<ValueTuple<T, T1, T2>> QueryComponents<T, T1, T2>();
|
||||
|
||||
/// <summary>
|
||||
/// 查询4个组件
|
||||
@@ -105,7 +99,7 @@ namespace BITKit.Entities
|
||||
/// <typeparam name="T2"></typeparam>
|
||||
/// <typeparam name="T3"></typeparam>
|
||||
/// <returns></returns>
|
||||
ValueTuple<T, T1, T2, T3>[] QueryComponents<T, T1, T2, T3>();
|
||||
Span<ValueTuple<T, T1, T2, T3>> QueryComponents<T, T1, T2, T3>();
|
||||
|
||||
/// <summary>
|
||||
/// 查询5个组件
|
||||
@@ -116,7 +110,7 @@ namespace BITKit.Entities
|
||||
/// <typeparam name="T3"></typeparam>
|
||||
/// <typeparam name="T4"></typeparam>
|
||||
/// <returns></returns>
|
||||
ValueTuple<T, T1, T2, T3, T4>[] QueryComponents<T, T1, T2, T3, T4>();
|
||||
Span<ValueTuple<T, T1, T2, T3, T4>> QueryComponents<T, T1, T2, T3, T4>();
|
||||
/// <summary>
|
||||
/// 查询6个组件
|
||||
/// </summary>
|
||||
@@ -127,7 +121,7 @@ namespace BITKit.Entities
|
||||
/// <typeparam name="T4"></typeparam>
|
||||
/// <typeparam name="T5"></typeparam>
|
||||
/// <returns></returns>
|
||||
ValueTuple<T, T1, T2, T3, T4, T5>[] QueryComponents<T, T1, T2, T3, T4, T5>();
|
||||
Span<ValueTuple<T, T1, T2, T3, T4, T5>> QueryComponents<T, T1, T2, T3, T4, T5>();
|
||||
|
||||
/// <summary>
|
||||
/// 查询7个组件
|
||||
@@ -140,7 +134,7 @@ namespace BITKit.Entities
|
||||
/// <typeparam name="T5"></typeparam>
|
||||
/// <typeparam name="T6"></typeparam>
|
||||
/// <returns></returns>
|
||||
ValueTuple<T, T1, T2, T3, T4, T5, T6>[] QueryComponents<T, T1, T2, T3, T4, T5, T6>();
|
||||
Span<ValueTuple<T, T1, T2, T3, T4, T5, T6>> QueryComponents<T, T1, T2, T3, T4, T5, T6>();
|
||||
|
||||
/// <summary>
|
||||
/// 查询8个组件
|
||||
@@ -154,6 +148,6 @@ namespace BITKit.Entities
|
||||
/// <typeparam name="T6"></typeparam>
|
||||
/// <typeparam name="TRest">剩余实例</typeparam>
|
||||
/// <returns></returns>
|
||||
ValueTuple<T, T1, T2, T3, T4, T5, T6, TRest>[] QueryComponents<T, T1, T2, T3, T4, T5, T6, TRest>() where TRest : struct;
|
||||
//Span<ValueTuple<T, T1, T2, T3, T4, T5, T6, TRest>> QueryComponents<T, T1, T2, T3, T4, T5, T6, TRest>() where TRest : struct;
|
||||
}
|
||||
}
|
8
Assets/BITKit/Core/Localization.meta
Normal file
8
Assets/BITKit/Core/Localization.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c9f4b5601bd64124a9efdee9cf9c7226
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
79
Assets/BITKit/Core/Localization/CsvLocalizationService.cs
Normal file
79
Assets/BITKit/Core/Localization/CsvLocalizationService.cs
Normal file
@@ -0,0 +1,79 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net.Http;
|
||||
using BITKit;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Net.BITKit.Localization
|
||||
{
|
||||
public class CsvLocalizationService
|
||||
{
|
||||
public string Url { get; set; } =
|
||||
@"http://server.bitfall.icu:21982/com.project.b/net.project.b.localization.csv";
|
||||
|
||||
private readonly ILogger<CsvLocalizationService> _logger;
|
||||
private readonly ILocalizationService _localizationService;
|
||||
|
||||
public CsvLocalizationService(ILocalizationService localizationService, ILogger<CsvLocalizationService> logger)
|
||||
{
|
||||
_localizationService = localizationService;
|
||||
_logger = logger;
|
||||
|
||||
_localizationService.OnLanguageChangeAsync += OnLanguageChangeAsync;
|
||||
}
|
||||
|
||||
public static Dictionary<string, Dictionary<string, string>> ParseCsvToDictionary(string csvData)
|
||||
{
|
||||
var dict = new Dictionary<string, Dictionary<string, string>>();
|
||||
using var reader = new StringReader(csvData);
|
||||
|
||||
var headerLine = reader.ReadLine();
|
||||
if (headerLine == null) return dict;
|
||||
|
||||
var headers = headerLine.Split(',');
|
||||
|
||||
for (var i = 1; i < headers.Length; i++) // 跳过 "Key" 列
|
||||
{
|
||||
dict[headers[i]] = new Dictionary<string, string>();
|
||||
}
|
||||
|
||||
string? line;
|
||||
while ((line = reader.ReadLine()) != null)
|
||||
{
|
||||
var columns = line.Split(',');
|
||||
if (columns.Length < 2) continue;
|
||||
|
||||
var key = columns[0]; // 取 Key 值
|
||||
for (var i = 1; i < columns.Length; i++)
|
||||
{
|
||||
dict[headers[i]][key] = columns[i]; // 填充语言数据
|
||||
}
|
||||
}
|
||||
|
||||
return dict;
|
||||
}
|
||||
|
||||
private async UniTask OnLanguageChangeAsync(string arg1, string arg2)
|
||||
{
|
||||
var csv = await new HttpClient().GetStringAsync(Url);
|
||||
|
||||
_logger.LogInformation($"下载完成:\n{csv}");
|
||||
|
||||
foreach (var (lang, dictionary) in ParseCsvToDictionary(csv))
|
||||
{
|
||||
if (_localizationService.LocalizedStrings.TryGetValue(lang, out var currentDictionary) is false)
|
||||
{
|
||||
currentDictionary = new Dictionary<string, string>();
|
||||
_localizationService.LocalizedStrings.Add(lang,currentDictionary);
|
||||
}
|
||||
foreach (var (key, value) in dictionary)
|
||||
{
|
||||
currentDictionary.Set(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0a0edc8f5d75b3646a7b405ef830a52d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
111
Assets/BITKit/Core/Localization/ILocalizationService.cs
Normal file
111
Assets/BITKit/Core/Localization/ILocalizationService.cs
Normal file
@@ -0,0 +1,111 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using BITKit;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Net.BITKit.Localization
|
||||
{
|
||||
/// <summary>
|
||||
/// 本地化
|
||||
/// </summary>
|
||||
public interface ILocalizationService
|
||||
{
|
||||
public string Prefix { get; }
|
||||
/// <summary>
|
||||
/// 当前语言
|
||||
/// </summary>
|
||||
public string CurrentLanguage { get; }
|
||||
/// <summary>
|
||||
/// 更改回调,通常在此检查并下载语言包
|
||||
/// </summary>
|
||||
public event Func<string,string,UniTask> OnLanguageChangeAsync;
|
||||
/// <summary>
|
||||
/// 语言更改完成回调,UI和World执行更新
|
||||
/// </summary>
|
||||
public event Action<string,string> OnLanguageChanged;
|
||||
/// <summary>
|
||||
/// 获取翻译文本,返回无复制的引用
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="language">语言,默认为当前CultureInfo.Name</param>
|
||||
/// <returns></returns>
|
||||
public string GetLocalizedString(string key,string language=null);
|
||||
public UniTask ChangeLanguageAsync(string newLanguage);
|
||||
public IDictionary<string, IDictionary<string, string>> LocalizedStrings { get; }
|
||||
}
|
||||
|
||||
public class LocalizationService : ILocalizationService,IDisposable
|
||||
{
|
||||
private static LocalizationService _singleton;
|
||||
public string Prefix => "#";
|
||||
private char _prefix = '#';
|
||||
public string CurrentLanguage { get; private set; }
|
||||
|
||||
public event Func<string, string, UniTask> OnLanguageChangeAsync;
|
||||
public event Action<string, string> OnLanguageChanged;
|
||||
|
||||
private readonly ILogger<LocalizationService> _logger;
|
||||
|
||||
public IDictionary<string, IDictionary<string, string>> LocalizedStrings { get; } =
|
||||
new Dictionary<string, IDictionary<string, string>>();
|
||||
|
||||
private readonly ValidHandle _isBusy = new();
|
||||
|
||||
private readonly HashSet<string> _untranslatedKeys = new();
|
||||
|
||||
public LocalizationService(ILogger<LocalizationService> logger)
|
||||
{
|
||||
if (_singleton is not null)
|
||||
{
|
||||
logger.LogError("LocalizationService can only be one singleton");
|
||||
return;
|
||||
}
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
|
||||
public string GetLocalizedString(string key, string language = null)
|
||||
{
|
||||
language ??= CurrentLanguage; // 默认使用当前语言
|
||||
|
||||
if (key[0] != _prefix)
|
||||
{
|
||||
key = _prefix + key;
|
||||
}
|
||||
if (LocalizedStrings.TryGetValue(language, out var langDict) && langDict.TryGetValue(key, out var value))
|
||||
{
|
||||
return value;
|
||||
}
|
||||
_untranslatedKeys.Add(key);
|
||||
return key.Replace(Prefix,string.Empty).Replace("_"," "); // 如果找不到翻译,就返回 key 本身(常见策略)
|
||||
}
|
||||
public async UniTask ChangeLanguageAsync(string newLanguage)
|
||||
{
|
||||
if (CurrentLanguage == newLanguage) return;
|
||||
var oldLanguage = CurrentLanguage;
|
||||
CurrentLanguage = newLanguage;
|
||||
|
||||
await _isBusy;
|
||||
using var _ = _isBusy.GetHandle();
|
||||
|
||||
await UniTask.SwitchToMainThread();
|
||||
|
||||
await OnLanguageChangeAsync.UniTaskFunc(oldLanguage, newLanguage);
|
||||
|
||||
// 触发同步事件(例如更新 UI)
|
||||
OnLanguageChanged?.Invoke(oldLanguage, newLanguage);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_isBusy?.Dispose();
|
||||
_singleton = null;
|
||||
_logger.LogInformation("Untranslated keys:\n"+string.Join("\n", _untranslatedKeys));
|
||||
_untranslatedKeys.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
11
Assets/BITKit/Core/Localization/ILocalizationService.cs.meta
Normal file
11
Assets/BITKit/Core/Localization/ILocalizationService.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: baab5c8590ad6ee44acbc258eeacdc8b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -9,13 +9,16 @@ namespace BITKit.Pool
|
||||
/// </summary>
|
||||
public interface IPoolService
|
||||
{
|
||||
public int DefaultCapacity { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 生成对象
|
||||
/// </summary>
|
||||
/// <param name="path">可寻址路径</param>
|
||||
/// <param name="prefab">直接提供的预制体</param>
|
||||
/// <typeparam name="T">类型</typeparam>
|
||||
/// <returns></returns>
|
||||
UniTask<T> Spawn<T>(string path) where T : class;
|
||||
UniTask<T> Spawn<T>(string path,object prefab=null) where T : class;
|
||||
/// <summary>
|
||||
/// 回收对象
|
||||
/// </summary>
|
||||
|
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
@@ -24,7 +25,6 @@ namespace BITKit.StateMachine
|
||||
|
||||
public bool Enabled { get; set; } = true;
|
||||
public T CurrentState { get;private set; }
|
||||
public T NextOrCurrentState => _nextTargetState.IfNotAllow(CurrentState);
|
||||
public event Action<T, T> OnStateChanging;
|
||||
public event Func<T, T, UniTask> OnStateChangeAsync;
|
||||
public event Action<T, T> OnStateChanged;
|
||||
@@ -35,7 +35,13 @@ namespace BITKit.StateMachine
|
||||
public readonly ValidHandle IsBusy=new();
|
||||
private readonly CancellationTokenSource _cancellationTokenSource=new();
|
||||
private readonly Dictionary<int, T> _dictionary = new();
|
||||
private readonly Optional<T> _nextTargetState = new();
|
||||
|
||||
private readonly HashSet<int> _isRegistered = new();
|
||||
|
||||
private CancellationTokenSource _transitionCts;
|
||||
|
||||
private T _entryCompletedState;
|
||||
|
||||
public async void Initialize()
|
||||
{
|
||||
await IsBusy;
|
||||
@@ -43,33 +49,27 @@ namespace BITKit.StateMachine
|
||||
using var _ = IsBusy.GetHandle();
|
||||
foreach (var (_,value) in StateDictionary)
|
||||
{
|
||||
await value.InitializeAsync();
|
||||
value.Initialize();
|
||||
if (_isRegistered.Add(value.Identifier))
|
||||
{
|
||||
await value.InitializeAsync();
|
||||
value.Initialize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public async void UpdateState(float deltaTime)
|
||||
{
|
||||
if (CurrentState is null) return;
|
||||
if (_entryCompletedState is null) return;
|
||||
using var _ = IsBusy.GetHandle();
|
||||
CurrentState.OnStateUpdate(deltaTime);
|
||||
await CurrentState.OnStateUpdateAsync(deltaTime);
|
||||
_entryCompletedState.OnStateUpdate(deltaTime);
|
||||
await _entryCompletedState.OnStateUpdateAsync(deltaTime);
|
||||
}
|
||||
|
||||
|
||||
public async void DisposeState()
|
||||
public void DisposeState()
|
||||
{
|
||||
await IsBusy;
|
||||
if (_cancellationTokenSource.IsCancellationRequested) return;
|
||||
if (CurrentState is null) return;
|
||||
using var _ = IsBusy.GetHandle();
|
||||
CurrentState.Enabled = false;
|
||||
await CurrentState.OnStateExitAsync(CurrentState, null);
|
||||
CurrentState.OnStateExit(CurrentState, null);
|
||||
CurrentState = null;
|
||||
TransitionState(null);
|
||||
}
|
||||
|
||||
public T TransitionState<TState>() where TState : T
|
||||
{
|
||||
T nextState;
|
||||
@@ -96,50 +96,60 @@ namespace BITKit.StateMachine
|
||||
nextState.Identifier = nextState.GetHashCode();
|
||||
}
|
||||
}
|
||||
|
||||
if (Equals(nextState, CurrentState)) return;
|
||||
if(_nextTargetState.Allow && Equals(_nextTargetState.Value,nextState))return;
|
||||
if (_nextTargetState.Allow)
|
||||
{
|
||||
_nextTargetState.Value = nextState;
|
||||
return;
|
||||
}
|
||||
_nextTargetState.SetValueThenAllow(nextState);
|
||||
await IsBusy;
|
||||
|
||||
if(CurrentState==nextState)return;
|
||||
if(_cancellationTokenSource.IsCancellationRequested)return;
|
||||
using var _ = IsBusy.GetHandle();
|
||||
|
||||
OnStateChanging?.Invoke(CurrentState,nextState);
|
||||
await OnStateChangeAsync.UniTaskFunc(CurrentState,nextState);
|
||||
|
||||
if (nextState is not null && _dictionary.TryAdd(nextState.Identifier, nextState))
|
||||
{
|
||||
await nextState.InitializeAsync();
|
||||
if(_cancellationTokenSource.IsCancellationRequested)return;
|
||||
nextState.Initialize();
|
||||
}
|
||||
if (CurrentState is not null)
|
||||
{
|
||||
CurrentState.Enabled = false;
|
||||
await CurrentState.OnStateExitAsync(CurrentState, nextState);
|
||||
if(_cancellationTokenSource.IsCancellationRequested)return;
|
||||
CurrentState.OnStateExit(CurrentState,nextState);
|
||||
}
|
||||
|
||||
if (_nextTargetState.Allow && _nextTargetState.Value != nextState)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var tempState = CurrentState;
|
||||
CurrentState = _nextTargetState.Value;
|
||||
_nextTargetState.Clear();
|
||||
nextState.Enabled = true;
|
||||
await nextState.OnStateEntryAsync(tempState);
|
||||
if(_cancellationTokenSource.IsCancellationRequested)return;
|
||||
nextState.OnStateEntry(tempState);
|
||||
OnStateChanged?.Invoke(tempState,nextState);
|
||||
|
||||
CurrentState = nextState;
|
||||
|
||||
_transitionCts?.Cancel();
|
||||
_transitionCts = new CancellationTokenSource();
|
||||
|
||||
var ct = _transitionCts.Token;
|
||||
|
||||
await IsBusy;
|
||||
using var _ = IsBusy.GetHandle();
|
||||
if(ct.IsCancellationRequested||_cancellationTokenSource.IsCancellationRequested)return;
|
||||
|
||||
OnStateChanging?.Invoke(tempState,nextState);
|
||||
|
||||
if (tempState is not null)
|
||||
{
|
||||
if (_entryCompletedState == tempState)
|
||||
{
|
||||
_entryCompletedState = null;
|
||||
}
|
||||
|
||||
tempState.Enabled = false;
|
||||
await tempState.OnStateExitAsync(tempState, nextState);
|
||||
tempState.OnStateExit(tempState,nextState);
|
||||
if(_cancellationTokenSource.IsCancellationRequested)return;
|
||||
}
|
||||
|
||||
if(ct.IsCancellationRequested)return;
|
||||
|
||||
await OnStateChangeAsync.UniTaskFunc(CurrentState,nextState);
|
||||
|
||||
if(ct.IsCancellationRequested)return;
|
||||
|
||||
if (nextState is not null)
|
||||
{
|
||||
if (_isRegistered.Add(nextState.Identifier))
|
||||
{
|
||||
await RegisterAsync(nextState);
|
||||
if(ct.IsCancellationRequested || _cancellationTokenSource.IsCancellationRequested)return;
|
||||
}
|
||||
|
||||
nextState.Enabled = true;
|
||||
await nextState.OnStateEntryAsync(CurrentState);
|
||||
nextState.OnStateEntry(CurrentState);
|
||||
if(ct.IsCancellationRequested || _cancellationTokenSource.IsCancellationRequested)return;
|
||||
|
||||
_entryCompletedState = nextState;
|
||||
}
|
||||
|
||||
OnStateChanged?.Invoke(tempState, nextState);
|
||||
|
||||
}
|
||||
public T TransitionState(T nextState)
|
||||
@@ -148,27 +158,49 @@ namespace BITKit.StateMachine
|
||||
return nextState;
|
||||
}
|
||||
|
||||
private async UniTask RegisterAsync(T newState)
|
||||
{
|
||||
StateDictionary.TryAdd(newState.GetType(),newState);
|
||||
|
||||
_dictionary.TryAdd(newState.Identifier, newState);
|
||||
|
||||
|
||||
newState.Initialize();
|
||||
await newState.InitializeAsync();
|
||||
}
|
||||
|
||||
public async void Register(T newState)
|
||||
{
|
||||
await IsBusy;
|
||||
using var _ = IsBusy.GetHandle();
|
||||
await RegisterAsync(newState);
|
||||
}
|
||||
public async void UnRegister(T newState)
|
||||
{
|
||||
if (newState is null) return;
|
||||
if (Dictionary.ContainsKey(newState.Identifier) is false) return;
|
||||
_dictionary.Remove(newState.Identifier);
|
||||
|
||||
await IsBusy;
|
||||
using var _ = IsBusy.GetHandle();
|
||||
|
||||
if (Equals(CurrentState, newState))
|
||||
{
|
||||
await CurrentState.OnStateExitAsync(CurrentState, null);
|
||||
CurrentState.OnStateExit(CurrentState, null);
|
||||
if (CurrentState is IAsyncDisposable asyncDisposable)
|
||||
{
|
||||
await asyncDisposable.DisposeAsync();
|
||||
}
|
||||
if (CurrentState is IDisposable disposable)
|
||||
{
|
||||
disposable.Dispose();
|
||||
}
|
||||
|
||||
CurrentState = null;
|
||||
}
|
||||
|
||||
if (newState is IAsyncDisposable asyncDisposable)
|
||||
{
|
||||
await asyncDisposable.DisposeAsync();
|
||||
}
|
||||
if (newState is IDisposable disposable)
|
||||
{
|
||||
disposable.Dispose();
|
||||
}
|
||||
|
||||
OnStateUnRegistered?.Invoke(newState);
|
||||
}
|
||||
public void Dispose()
|
||||
|
@@ -7,7 +7,6 @@ namespace BITKit.UX
|
||||
public interface IUXDialogue
|
||||
{
|
||||
void Show(string content,string title = "Alert",Action confirmAction=null,Action<bool> onChoose=null);
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user