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; using Microsoft.Extensions.Logging; namespace BITKit.Entities { public class EntitiesService : IEntitiesService, IDisposable { private static int _count; private readonly ILogger _logger; private readonly IFixedTicker _ticker; private readonly ConcurrentQueue _onAddQueue = new(); private readonly ConcurrentDictionary> _typeCaches = new(); public EntitiesService(ILogger logger, IFixedTicker ticker) { _logger = logger; _ticker = ticker; _count++; logger.LogInformation($"已创建EntitiesService,当前有:{_count}个实例"); _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 Entities = new(); public event Action OnAdd; public event Action OnRemove; IReadOnlyDictionary 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 factory) { return Entities.GetOrAdd(id, factory); } public Span QueryComponents() { var pool = ArrayPool.Shared; var hashset = _typeCaches.GetOrCreate(typeof(T).GetHashCode()); var count = hashset.Count; var array = pool.Rent(count); // ✅ 从池中获取数组,避免 GC var i = 0; foreach (var id in hashset) { array[i] = Entities[id].ServiceProvider.GetRequiredService(); i++; } // 🚀 使用 `GCHandle` 固定数组,防止被 GC 移动 var handle = GCHandle.Alloc(array, GCHandleType.Pinned); try { return new Span(array, 0, count); // ✅ 返回 `Span`,无额外拷贝 } finally { handle.Free(); // ✅ 释放 `GCHandle`,防止内存泄漏 pool.Return(array); // ✅ 归还 ArrayPool } } public Span<(T, T1)> QueryComponents() { var pool = ArrayPool<(T, T1)>.Shared; var hashset = _typeCaches.GetOrCreate(typeof(T).GetHashCode()); var t1Set = _typeCaches.GetOrCreate(typeof(T1).GetHashCode()); var count = hashset.Count; var array = pool.Rent(count); var i = 0; foreach (var id in hashset.Intersect(t1Set)) { var entity = Entities[id]; array[i] = (entity.ServiceProvider.GetRequiredService(), entity.ServiceProvider.GetRequiredService()); i++; } var handle = GCHandle.Alloc(array, GCHandleType.Pinned); try { return new Span<(T, T1)>(array, 0, count); } finally { handle.Free(); pool.Return(array); } } public Span<(T, T1, T2)> QueryComponents() { 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)) { var entity = Entities[id]; array[i] = (entity.ServiceProvider.GetRequiredService(), entity.ServiceProvider.GetRequiredService(), entity.ServiceProvider.GetRequiredService()); 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() { 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(), entity.ServiceProvider.GetRequiredService(), entity.ServiceProvider.GetRequiredService(), entity.ServiceProvider.GetRequiredService()); 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() { 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(), entity.ServiceProvider.GetRequiredService(), entity.ServiceProvider.GetRequiredService(), entity.ServiceProvider.GetRequiredService(), entity.ServiceProvider.GetRequiredService()); 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() { 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(), entity.ServiceProvider.GetRequiredService(), entity.ServiceProvider.GetRequiredService(), entity.ServiceProvider.GetRequiredService(), entity.ServiceProvider.GetRequiredService(), entity.ServiceProvider.GetRequiredService() ); 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() { 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(), entity.ServiceProvider.GetRequiredService(), entity.ServiceProvider.GetRequiredService(), entity.ServiceProvider.GetRequiredService(), entity.ServiceProvider.GetRequiredService(), entity.ServiceProvider.GetRequiredService(), entity.ServiceProvider.GetRequiredService() ); 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); } } public void Dispose() { _count--; if (_count <= 0) { Entities.Clear(); } _logger.LogInformation($"已释放,还剩{_count}个实例"); _cancellationTokenSource?.Dispose(); _ticker.Remove(OnTick); } } }