This commit is contained in:
CortexCore
2025-03-09 13:38:23 +08:00
parent 8261a458e2
commit 18239a5ae4
67 changed files with 8573 additions and 831 deletions

View File

@@ -13,28 +13,49 @@ namespace BITKit.Entities
public class EntitiesService:IEntitiesService,IDisposable
{
private readonly ILogger<EntitiesService> _logger;
private readonly IFixedTicker _ticker;
private static int _count;
public EntitiesService()
{
_count++;
}
public EntitiesService(ILogger<EntitiesService> logger)
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;
IEntity[] IEntitiesService.Entities => Entities.Values.ToArray();
IReadOnlyDictionary<int, IEntity> IEntitiesService.Entities => Entities;
public bool Register(IEntity entity)
{
if (!Entities.TryAdd(entity.Id, entity)) return false;
OnAdd?.Invoke(entity);
OnAddQueue.Enqueue(entity);
return true;
}
@@ -42,8 +63,17 @@ namespace BITKit.Entities
{
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)
@@ -262,6 +292,8 @@ namespace BITKit.Entities
_logger.LogInformation($"已释放,还剩{_count}个实例");
_cancellationTokenSource?.Dispose();
_ticker.Remove(OnTick);
}
}
}

View File

@@ -8,24 +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 => _cancellationTokenSource.Token;
private readonly CancellationTokenSource _cancellationTokenSource = new();
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))
@@ -39,7 +39,6 @@ namespace BITKit.Entities
public void Dispose()
{
_cancellationTokenSource.Cancel();
_serviceProvider.Dispose();
}
}

View File

@@ -1,5 +1,6 @@
using System.Threading;
using System;
using System.Collections.Generic;
using System.ComponentModel.Design;
using Microsoft.Extensions.DependencyInjection;
#if NET5_0_OR_GREATER
@@ -16,7 +17,6 @@ namespace BITKit.Entities
CancellationToken CancellationToken { get; }
IServiceProvider ServiceProvider { get; }
IServiceCollection ServiceCollection { get; }
object[] GetServices();
void Inject(object obj);
}
/// <summary>
@@ -35,7 +35,7 @@ namespace BITKit.Entities
/// <summary>
/// 所有Entity
/// </summary>
IEntity[] Entities { get; }
IReadOnlyDictionary<int,IEntity> Entities { get; }
/// <summary>
/// 注册Entity
/// </summary>

106
Src/Core/ECS/UnityEntity.cs Normal file
View File

@@ -0,0 +1,106 @@
#if UNITY_5_3_OR_NEWER
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using Microsoft.Extensions.DependencyInjection;
using UnityEngine;
using Object = UnityEngine.Object;
namespace BITKit.Entities
{
[DisallowMultipleComponent]
[DefaultExecutionOrder(-1)]
public class UnityEntity : MonoBehaviour,IEntity
{
private IEntitiesService _entitiesService;
private IEntity _entity;
private void Start()
{
_entitiesService = BITApp.ServiceProvider.GetRequiredService<IEntitiesService>();
if (_entitiesService.Entities.ContainsKey(gameObject.GetInstanceID())) return;
var entity = new Entity()
{
Id = gameObject.GetInstanceID(),
CancellationToken = destroyCancellationToken
};
var idComponent = new IdComponent()
{
Id = entity.Id,
Name = gameObject.name,
};
entity.ServiceCollection.AddSingleton(idComponent);
foreach (var component in GetComponents<Component>())
{
var type = component.GetType();
foreach (var x in type.GetInterfaces())
{
entity.ServiceCollection.AddSingleton(x, component);
}
while (type is not null)
{
var baseType = type.BaseType;
try
{
switch (baseType)
{
case null:
case not null when baseType == typeof(object):
case not null when baseType == typeof(Object):
case not null when baseType == typeof(MonoBehaviour):
case not null when baseType == typeof(Behaviour):
case not null when baseType == typeof(Component):
case not null when baseType == typeof(Component):
throw new OperationCanceledException();
}
}
catch (OperationCanceledException)
{
break;
}
entity.ServiceCollection.AddSingleton(baseType, component);
type = type.BaseType;
}
}
entity.ServiceCollection.AddSingleton(gameObject);
entity.ServiceCollection.AddSingleton(transform);
destroyCancellationToken.Register(Dispose);
_entity = entity;
_entitiesService.Register(entity);
}
private void Dispose()
{
_entitiesService?.UnRegister(_entity);
}
public int Id => _entity.Id;
public CancellationToken CancellationToken => _entity.CancellationToken;
public IServiceProvider ServiceProvider => _entity.ServiceProvider;
public IServiceCollection ServiceCollection => _entity.ServiceCollection;
public void Inject(object obj)
{
_entity.Inject(obj);
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 230e015069b45484f9c85d1aba1e901c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: