1
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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();
|
||||
}
|
||||
}
|
||||
|
@@ -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
106
Src/Core/ECS/UnityEntity.cs
Normal 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
|
11
Src/Core/ECS/UnityEntity.cs.meta
Normal file
11
Src/Core/ECS/UnityEntity.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 230e015069b45484f9c85d1aba1e901c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Reference in New Issue
Block a user