301 lines
12 KiB
C#
301 lines
12 KiB
C#
using System;
|
|
using System.Collections.Concurrent;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Runtime.CompilerServices;
|
|
using System.Security.AccessControl;
|
|
using System.Threading;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
namespace BITKit.Entities
|
|
{
|
|
public class EntitiesService:IEntitiesService,IDisposable
|
|
{
|
|
private readonly ILogger<EntitiesService> _logger;
|
|
private readonly IFixedTicker _ticker;
|
|
private static int _count;
|
|
private static readonly ConcurrentQueue<IEntity> OnAddQueue = new();
|
|
private static ConcurrentDictionary<int, HashSet<int>> TypeCaches = new();
|
|
public EntitiesService(ILogger<EntitiesService> logger, IFixedTicker ticker)
|
|
{
|
|
if (_count > 0)
|
|
{
|
|
throw new MulticastNotSupportedException();
|
|
}
|
|
_count++;
|
|
|
|
_logger = logger;
|
|
_ticker = ticker;
|
|
|
|
_ticker.Add(OnTick);
|
|
}
|
|
|
|
private void OnTick(float obj)
|
|
{
|
|
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);
|
|
return true;
|
|
}
|
|
|
|
public bool UnRegister(IEntity entity)
|
|
{
|
|
if (!Entities.TryRemove(entity.Id, out _)) return false;
|
|
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];
|
|
}
|
|
|
|
public bool TryGetEntity(int id, out IEntity entity)
|
|
{
|
|
return Entities.TryGetValue(id, out entity);
|
|
}
|
|
|
|
public IEntity GetOrAdd(int id, Func<int, IEntity> factory)
|
|
{
|
|
return Entities.GetOrAdd(id, factory);
|
|
}
|
|
|
|
public IEntity[] Query<T>()
|
|
{
|
|
throw new NotImplementedException("Obsoleted");
|
|
}
|
|
|
|
public T[] QueryComponents<T>()
|
|
{
|
|
var list = new List<T>();
|
|
foreach (var entity in Entities.Values)
|
|
{
|
|
if (entity.ServiceProvider.GetService<T>() is { } t1)
|
|
{
|
|
list.Add(t1);
|
|
}
|
|
}
|
|
|
|
return list.ToArray();
|
|
// return _queryCache.GetOrAdd(typeof(T), type =>
|
|
// {
|
|
// return _entities.Values.Where(entity => entity.TryGetComponent(out T component)).ToArray();
|
|
// }).Cast<T>().ToArray();
|
|
}
|
|
|
|
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>()
|
|
{
|
|
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();
|
|
}
|
|
|
|
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();
|
|
}
|
|
|
|
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)
|
|
{
|
|
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));
|
|
}
|
|
}
|
|
|
|
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();
|
|
}
|
|
|
|
public ValueTuple<T, T1, T2, T3, T4, T5, T6, TRest>[] QueryComponents<T, T1, T2, T3, T4, T5, T6, TRest>()
|
|
where TRest : struct
|
|
{
|
|
var list = new List<ValueTuple<T, T1, T2, T3, T4, T5, T6, TRest>>();
|
|
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 &&
|
|
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));
|
|
}
|
|
}
|
|
return list.ToArray();
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
_count--;
|
|
if (_count <= 0)
|
|
{
|
|
Entities.Clear();
|
|
}
|
|
|
|
_logger.LogInformation($"已释放,还剩{_count}个实例");
|
|
|
|
_cancellationTokenSource?.Dispose();
|
|
|
|
_ticker.Remove(OnTick);
|
|
}
|
|
}
|
|
}
|
|
|