Net.Like.Xue.Tokyo/Assets/BITKit/Core/ECS/EntitiesService.cs

361 lines
13 KiB
C#
Raw Normal View History

2024-11-03 16:42:23 +08:00
using System;
2025-03-10 18:06:44 +08:00
using System.Buffers;
2024-11-03 16:42:23 +08:00
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
2025-03-10 18:06:44 +08:00
using System.Runtime.InteropServices;
2024-11-03 16:42:23 +08:00
using System.Security.AccessControl;
using System.Threading;
2025-02-24 23:03:39 +08:00
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
2024-11-03 16:42:23 +08:00
namespace BITKit.Entities
{
2025-03-10 18:06:44 +08:00
public class EntitiesService : IEntitiesService, IDisposable
2024-11-03 16:42:23 +08:00
{
2025-03-10 18:06:44 +08:00
private static int _count;
2025-02-24 23:03:39 +08:00
private readonly ILogger<EntitiesService> _logger;
2025-03-03 18:44:00 +08:00
private readonly IFixedTicker _ticker;
2025-03-10 18:06:44 +08:00
private readonly ConcurrentQueue<IEntity> _onAddQueue = new();
private readonly ConcurrentDictionary<int, HashSet<int>> _typeCaches = new();
2025-03-03 18:44:00 +08:00
public EntitiesService(ILogger<EntitiesService> logger, IFixedTicker ticker)
2025-02-24 23:03:39 +08:00
{
2025-03-03 18:44:00 +08:00
_logger = logger;
_ticker = ticker;
2025-03-10 18:06:44 +08:00
_count++;
logger.LogInformation($"已创建EntitiesService,当前有:{_count}个实例");
2025-03-03 18:44:00 +08:00
_ticker.Add(OnTick);
2025-02-24 23:03:39 +08:00
}
2025-03-03 18:44:00 +08:00
private void OnTick(float obj)
2025-02-24 23:03:39 +08:00
{
2025-03-10 18:06:44 +08:00
while (_onAddQueue.TryDequeue(out var entity))
2025-03-03 18:44:00 +08:00
{
OnAdd?.Invoke(entity);
2025-03-10 18:06:44 +08:00
foreach (var serviceDescriptor in entity.ServiceCollection)
{
var typeHash = serviceDescriptor.ServiceType.GetHashCode();
var hashSet = _typeCaches.GetOrCreate(typeHash);
hashSet.Add(entity.Id);
}
2025-03-03 18:44:00 +08:00
}
2025-02-24 23:03:39 +08:00
}
2025-03-03 18:44:00 +08:00
2025-03-10 18:06:44 +08:00
2025-02-24 23:03:39 +08:00
private static readonly ConcurrentDictionary<int, IEntity> Entities = new();
2024-11-03 16:42:23 +08:00
public event Action<IEntity> OnAdd;
public event Action<IEntity> OnRemove;
2025-03-03 18:44:00 +08:00
IReadOnlyDictionary<int, IEntity> IEntitiesService.Entities => Entities;
2025-03-10 18:06:44 +08:00
2024-11-03 16:42:23 +08:00
public bool Register(IEntity entity)
{
2025-02-24 23:03:39 +08:00
if (!Entities.TryAdd(entity.Id, entity)) return false;
2025-03-10 18:06:44 +08:00
_onAddQueue.Enqueue(entity);
2024-11-03 16:42:23 +08:00
return true;
}
public bool UnRegister(IEntity entity)
{
2025-02-24 23:03:39 +08:00
if (!Entities.TryRemove(entity.Id, out _)) return false;
2025-03-10 18:06:44 +08:00
OnRemove?.Invoke(entity);
foreach (var serviceDescriptor in entity.ServiceCollection)
{
var typeHash = serviceDescriptor.ServiceType.GetHashCode();
var hashSet = _typeCaches.GetOrCreate(typeHash);
hashSet.Remove(entity.Id);
}
2024-11-03 16:42:23 +08:00
return true;
}
2025-03-10 18:06:44 +08:00
2024-11-03 16:42:23 +08:00
public CancellationToken CancellationToken => _cancellationTokenSource.Token;
private readonly CancellationTokenSource _cancellationTokenSource = new();
2025-03-10 18:06:44 +08:00
2024-11-03 16:42:23 +08:00
public IEntity Get(int id)
{
2025-02-24 23:03:39 +08:00
return Entities[id];
2024-11-03 16:42:23 +08:00
}
public bool TryGetEntity(int id, out IEntity entity)
{
2025-02-24 23:03:39 +08:00
return Entities.TryGetValue(id, out entity);
2024-11-03 16:42:23 +08:00
}
public IEntity GetOrAdd(int id, Func<int, IEntity> factory)
{
2025-02-24 23:03:39 +08:00
return Entities.GetOrAdd(id, factory);
2024-11-03 16:42:23 +08:00
}
2025-03-10 18:06:44 +08:00
public Span<T> QueryComponents<T>()
2024-11-03 16:42:23 +08:00
{
2025-03-10 18:06:44 +08:00
var pool = ArrayPool<T>.Shared;
var hashset = _typeCaches.GetOrCreate(typeof(T).GetHashCode());
2024-11-03 16:42:23 +08:00
2025-03-10 18:06:44 +08:00
var count = hashset.Count;
var array = pool.Rent(count); // ✅ 从池中获取数组,避免 GC
var i = 0;
foreach (var id in hashset)
2025-02-24 23:03:39 +08:00
{
2025-03-10 18:06:44 +08:00
array[i] = Entities[id].ServiceProvider.GetRequiredService<T>();
i++;
2025-02-24 23:03:39 +08:00
}
2025-03-10 18:06:44 +08:00
// 🚀 使用 `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
}
2024-11-03 16:42:23 +08:00
}
2025-02-24 23:03:39 +08:00
2025-03-10 18:06:44 +08:00
public Span<(T, T1)> QueryComponents<T, T1>()
2024-11-03 16:42:23 +08:00
{
2025-03-10 18:06:44 +08:00
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))
2025-02-24 23:03:39 +08:00
{
2025-03-10 18:06:44 +08:00
var entity = Entities[id];
array[i] = (entity.ServiceProvider.GetRequiredService<T>(),
entity.ServiceProvider.GetRequiredService<T1>());
i++;
2025-02-24 23:03:39 +08:00
}
2025-03-10 18:06:44 +08:00
var handle = GCHandle.Alloc(array, GCHandleType.Pinned);
try
2025-02-24 23:03:39 +08:00
{
2025-03-10 18:06:44 +08:00
return new Span<(T, T1)>(array, 0, count);
}
finally
{
handle.Free();
pool.Return(array);
2025-02-24 23:03:39 +08:00
}
2024-11-03 16:42:23 +08:00
}
2025-03-10 18:06:44 +08:00
public Span<(T, T1, T2)> QueryComponents<T, T1, T2>()
2024-11-03 16:42:23 +08:00
{
2025-03-10 18:06:44 +08:00
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))
2025-02-24 23:03:39 +08:00
{
2025-03-10 18:06:44 +08:00
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);
2025-02-24 23:03:39 +08:00
}
2024-11-03 16:42:23 +08:00
}
2025-03-10 18:06:44 +08:00
public Span<(T, T1, T2, T3)> QueryComponents<T, T1, T2, T3>()
2024-11-03 16:42:23 +08:00
{
2025-03-10 18:06:44 +08:00
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))
2025-02-24 23:03:39 +08:00
{
2025-03-10 18:06:44 +08:00
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);
2025-02-24 23:03:39 +08:00
}
2024-11-03 16:42:23 +08:00
}
2025-03-10 18:06:44 +08:00
public Span<(T, T1, T2, T3, T4)> QueryComponents<T, T1, T2, T3, T4>()
2024-11-03 16:42:23 +08:00
{
2025-03-10 18:06:44 +08:00
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))
2025-02-24 23:03:39 +08:00
{
2025-03-10 18:06:44 +08:00
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);
2025-02-24 23:03:39 +08:00
}
2024-11-03 16:42:23 +08:00
}
2025-03-10 18:06:44 +08:00
public Span<(T, T1, T2, T3, T4, T5)> QueryComponents<T, T1, T2, T3, T4, T5>()
2024-11-03 16:42:23 +08:00
{
2025-03-10 18:06:44 +08:00
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))
2025-02-24 23:03:39 +08:00
{
2025-03-10 18:06:44 +08:00
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++;
2025-02-24 23:03:39 +08:00
}
2025-03-10 18:06:44 +08:00
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);
}
2024-11-03 16:42:23 +08:00
}
2025-03-10 18:06:44 +08:00
public Span<(T, T1, T2, T3, T4, T5, T6)> QueryComponents<T, T1, T2, T3, T4, T5, T6>()
2025-02-24 23:03:39 +08:00
{
2025-03-10 18:06:44 +08:00
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))
2025-02-24 23:03:39 +08:00
{
2025-03-10 18:06:44 +08:00
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);
2025-02-24 23:03:39 +08:00
}
}
public void Dispose()
2024-11-03 16:42:23 +08:00
{
2025-02-24 23:03:39 +08:00
_count--;
if (_count <= 0)
{
Entities.Clear();
}
2025-03-10 18:06:44 +08:00
2025-02-24 23:03:39 +08:00
_logger.LogInformation($"已释放,还剩{_count}个实例");
2025-03-10 18:06:44 +08:00
2025-02-24 23:03:39 +08:00
_cancellationTokenSource?.Dispose();
2025-03-10 18:06:44 +08:00
2025-03-03 18:44:00 +08:00
_ticker.Remove(OnTick);
2024-11-03 16:42:23 +08:00
}
}
}