remove "pipeline" argument from base processes
add PoolsMediator
update component mask
This commit is contained in:
Mikhail 2023-12-06 18:58:06 +08:00
parent cf18d104f8
commit 6e16e2962e
11 changed files with 123 additions and 425 deletions

View File

@ -7,19 +7,19 @@ namespace DCFApixels.DragonECS
#region Interfaces #region Interfaces
public interface IEcsPreInitProcess : IEcsProcess public interface IEcsPreInitProcess : IEcsProcess
{ {
void PreInit(EcsPipeline pipeline); void PreInit();
} }
public interface IEcsInitProcess : IEcsProcess public interface IEcsInitProcess : IEcsProcess
{ {
void Init(EcsPipeline pipeline); void Init();
} }
public interface IEcsRunProcess : IEcsProcess public interface IEcsRunProcess : IEcsProcess
{ {
void Run(EcsPipeline pipeline); void Run();
} }
public interface IEcsDestroyProcess : IEcsProcess public interface IEcsDestroyProcess : IEcsProcess
{ {
void Destroy(EcsPipeline pipeline); void Destroy();
} }
#endregion #endregion
@ -40,7 +40,7 @@ namespace DCFApixels.DragonECS
} }
} }
#endif #endif
public void PreInit(EcsPipeline pipeline) public void PreInit()
{ {
#if DEBUG && !DISABLE_DEBUG #if DEBUG && !DISABLE_DEBUG
for (int i = 0; i < targets.Length && targets.Length <= _markers.Length; i++) for (int i = 0; i < targets.Length && targets.Length <= _markers.Length; i++)
@ -48,7 +48,7 @@ namespace DCFApixels.DragonECS
_markers[i].Begin(); _markers[i].Begin();
try try
{ {
targets[i].PreInit(pipeline); targets[i].PreInit();
} }
catch (Exception e) catch (Exception e)
{ {
@ -62,7 +62,7 @@ namespace DCFApixels.DragonECS
#else #else
foreach (var item in targets) foreach (var item in targets)
{ {
try { item.PreInit(pipeline); } try { item.PreInit(); }
catch (Exception e) catch (Exception e)
{ {
#if DISABLE_CATH_EXCEPTIONS #if DISABLE_CATH_EXCEPTIONS
@ -88,7 +88,7 @@ namespace DCFApixels.DragonECS
} }
} }
#endif #endif
public void Init(EcsPipeline pipeline) public void Init()
{ {
#if DEBUG && !DISABLE_DEBUG #if DEBUG && !DISABLE_DEBUG
for (int i = 0; i < targets.Length && targets.Length <= _markers.Length; i++) for (int i = 0; i < targets.Length && targets.Length <= _markers.Length; i++)
@ -96,7 +96,7 @@ namespace DCFApixels.DragonECS
_markers[i].Begin(); _markers[i].Begin();
try try
{ {
targets[i].Init(pipeline); targets[i].Init();
} }
catch (Exception e) catch (Exception e)
{ {
@ -110,7 +110,7 @@ namespace DCFApixels.DragonECS
#else #else
foreach (var item in targets) foreach (var item in targets)
{ {
try { item.Init(pipeline); } try { item.Init(); }
catch (Exception e) catch (Exception e)
{ {
#if DISABLE_CATH_EXCEPTIONS #if DISABLE_CATH_EXCEPTIONS
@ -136,7 +136,7 @@ namespace DCFApixels.DragonECS
} }
} }
#endif #endif
public void Run(EcsPipeline pipeline) public void Run()
{ {
#if DEBUG && !DISABLE_DEBUG #if DEBUG && !DISABLE_DEBUG
for (int i = 0; i < targets.Length && targets.Length <= _markers.Length; i++) for (int i = 0; i < targets.Length && targets.Length <= _markers.Length; i++)
@ -144,7 +144,7 @@ namespace DCFApixels.DragonECS
_markers[i].Begin(); _markers[i].Begin();
try try
{ {
targets[i].Run(pipeline); targets[i].Run();
} }
catch (Exception e) catch (Exception e)
{ {
@ -158,7 +158,7 @@ namespace DCFApixels.DragonECS
#else #else
foreach (var item in targets) foreach (var item in targets)
{ {
try { item.Run(pipeline); } try { item.Run(); }
catch (Exception e) catch (Exception e)
{ {
#if DISABLE_CATH_EXCEPTIONS #if DISABLE_CATH_EXCEPTIONS
@ -184,7 +184,7 @@ namespace DCFApixels.DragonECS
} }
} }
#endif #endif
public void Destroy(EcsPipeline pipeline) public void Destroy()
{ {
#if DEBUG && !DISABLE_DEBUG #if DEBUG && !DISABLE_DEBUG
for (int i = 0; i < targets.Length && targets.Length <= _markers.Length; i++) for (int i = 0; i < targets.Length && targets.Length <= _markers.Length; i++)
@ -192,7 +192,7 @@ namespace DCFApixels.DragonECS
_markers[i].Begin(); _markers[i].Begin();
try try
{ {
targets[i].Destroy(pipeline); targets[i].Destroy();
} }
catch (Exception e) catch (Exception e)
{ {
@ -206,7 +206,7 @@ namespace DCFApixels.DragonECS
#else #else
foreach (var item in targets) foreach (var item in targets)
{ {
try { item.Destroy(pipeline); } try { item.Destroy(); }
catch (Exception e) catch (Exception e)
{ {
#if DISABLE_CATH_EXCEPTIONS #if DISABLE_CATH_EXCEPTIONS

View File

@ -102,32 +102,36 @@ namespace DCFApixels.DragonECS
} }
public class InjectSystemBase { } public class InjectSystemBase { }
[DebugHide, DebugColor(DebugColor.Gray)] [DebugHide, DebugColor(DebugColor.Gray)]
public class InjectSystem<T> : InjectSystemBase, IEcsPreInitProcess, IEcsInject<PreInitInjectController>, IEcsPreInitInjectProcess public class InjectSystem<T> : InjectSystemBase, IEcsInject<EcsPipeline>, IEcsPreInitProcess, IEcsInject<PreInitInjectController>, IEcsPreInitInjectProcess
{ {
private T _injectedData; private EcsPipeline _pipeline;
void IEcsInject<EcsPipeline>.Inject(EcsPipeline obj) => _pipeline = obj;
private PreInitInjectController _injectController; private PreInitInjectController _injectController;
void IEcsInject<PreInitInjectController>.Inject(PreInitInjectController obj) => _injectController = obj; void IEcsInject<PreInitInjectController>.Inject(PreInitInjectController obj) => _injectController = obj;
private T _injectedData;
public InjectSystem(T injectedData) public InjectSystem(T injectedData)
{ {
if (injectedData == null) Throw.ArgumentNull(); if (injectedData == null) Throw.ArgumentNull();
_injectedData = injectedData; _injectedData = injectedData;
} }
public void PreInit(EcsPipeline pipeline) public void PreInit()
{ {
if (_injectedData == null) return; if (_injectedData == null) return;
if (_injectController == null) if (_injectController == null)
{ {
_injectController = new PreInitInjectController(pipeline); _injectController = new PreInitInjectController(_pipeline);
var injectMapRunner = pipeline.GetRunner<IEcsInject<PreInitInjectController>>(); var injectMapRunner = _pipeline.GetRunner<IEcsInject<PreInitInjectController>>();
pipeline.GetRunner<IEcsPreInitInjectProcess>().OnPreInitInjectionBefore(); _pipeline.GetRunner<IEcsPreInitInjectProcess>().OnPreInitInjectionBefore();
injectMapRunner.Inject(_injectController); injectMapRunner.Inject(_injectController);
} }
var injectRunnerGeneric = pipeline.GetRunner<IEcsInject<T>>(); var injectRunnerGeneric = _pipeline.GetRunner<IEcsInject<T>>();
injectRunnerGeneric.Inject(_injectedData); injectRunnerGeneric.Inject(_injectedData);
if (_injectController.OnInject()) if (_injectController.OnInject())
{ {
_injectController.Destroy(); _injectController.Destroy();
var injectCallbacksRunner = pipeline.GetRunner<IEcsPreInitInjectProcess>(); var injectCallbacksRunner = _pipeline.GetRunner<IEcsPreInitInjectProcess>();
injectCallbacksRunner.OnPreInitInjectionAfter(); injectCallbacksRunner.OnPreInitInjectionAfter();
EcsRunner.Destroy(injectCallbacksRunner); EcsRunner.Destroy(injectCallbacksRunner);
} }

View File

@ -16,7 +16,7 @@ namespace DCFApixels.DragonECS
{ {
private readonly List<EcsWorld> _worlds = new List<EcsWorld>(); private readonly List<EcsWorld> _worlds = new List<EcsWorld>();
public void Inject(EcsWorld obj) => _worlds.Add(obj); public void Inject(EcsWorld obj) => _worlds.Add(obj);
public void Run(EcsPipeline pipeline) public void Run()
{ {
foreach (var world in _worlds) foreach (var world in _worlds)
{ {
@ -29,6 +29,7 @@ namespace DCFApixels.DragonECS
public class DeleteOneFrameComponentSystem<TComponent> : IEcsRunProcess, IEcsInject<EcsWorld> public class DeleteOneFrameComponentSystem<TComponent> : IEcsRunProcess, IEcsInject<EcsWorld>
where TComponent : struct, IEcsComponent where TComponent : struct, IEcsComponent
{ {
public EcsPipeline pipeline { get; set; }
private sealed class Aspect : EcsAspect private sealed class Aspect : EcsAspect
{ {
public EcsPool<TComponent> pool; public EcsPool<TComponent> pool;
@ -36,7 +37,7 @@ namespace DCFApixels.DragonECS
} }
private readonly List<EcsWorld> _worlds = new List<EcsWorld>(); private readonly List<EcsWorld> _worlds = new List<EcsWorld>();
public void Inject(EcsWorld obj) => _worlds.Add(obj); public void Inject(EcsWorld obj) => _worlds.Add(obj);
public void Run(EcsPipeline pipeline) public void Run()
{ {
for (int i = 0, iMax = _worlds.Count; i < iMax; i++) for (int i = 0, iMax = _worlds.Count; i < iMax; i++)
{ {

View File

@ -67,10 +67,10 @@ namespace DCFApixels.DragonECS
ecsPipelineInjectRunner.Inject(this); ecsPipelineInjectRunner.Inject(this);
EcsRunner.Destroy(ecsPipelineInjectRunner); EcsRunner.Destroy(ecsPipelineInjectRunner);
var preInitRunner = GetRunner<IEcsPreInitProcess>(); var preInitRunner = GetRunner<IEcsPreInitProcess>();
preInitRunner.PreInit(this); preInitRunner.PreInit();
EcsRunner.Destroy(preInitRunner); EcsRunner.Destroy(preInitRunner);
var initRunner = GetRunner<IEcsInitProcess>(); var initRunner = GetRunner<IEcsInitProcess>();
initRunner.Init(this); initRunner.Init();
EcsRunner.Destroy(initRunner); EcsRunner.Destroy(initRunner);
_runRunnerCache = GetRunner<IEcsRunProcess>(); _runRunnerCache = GetRunner<IEcsRunProcess>();
@ -85,7 +85,7 @@ namespace DCFApixels.DragonECS
if (!_isInit) Throw.Pipeline_MethodCalledBeforeInitialisation(nameof(Run)); if (!_isInit) Throw.Pipeline_MethodCalledBeforeInitialisation(nameof(Run));
if (_isDestoryed) Throw.Pipeline_MethodCalledAfterDestruction(nameof(Run)); if (_isDestoryed) Throw.Pipeline_MethodCalledAfterDestruction(nameof(Run));
#endif #endif
_runRunnerCache.Run(this); _runRunnerCache.Run();
} }
public void Destroy() public void Destroy()
{ {
@ -98,7 +98,7 @@ namespace DCFApixels.DragonECS
return; return;
} }
_isDestoryed = true; _isDestoryed = true;
GetRunner<IEcsDestroyProcess>().Destroy(this); GetRunner<IEcsDestroyProcess>().Destroy();
} }
#endregion #endregion

View File

@ -3,6 +3,7 @@ using DCFApixels.DragonECS.Utils;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using static DCFApixels.DragonECS.EcsWorld;
namespace DCFApixels.DragonECS namespace DCFApixels.DragonECS
{ {
@ -32,6 +33,8 @@ namespace DCFApixels.DragonECS
internal int[][] _entitiesComponentMasks; internal int[][] _entitiesComponentMasks;
private readonly PoolsMediator _poolsMediator;
#region Properties #region Properties
public bool IsDestroyed => _isDestroyed; public bool IsDestroyed => _isDestroyed;
public int Count => _entitiesCount; public int Count => _entitiesCount;
@ -47,6 +50,8 @@ namespace DCFApixels.DragonECS
public EcsWorld() : this(true) { } public EcsWorld() : this(true) { }
internal EcsWorld(bool isIndexable) internal EcsWorld(bool isIndexable)
{ {
_poolsMediator = new PoolsMediator(this);
_entitesCapacity = 512; _entitesCapacity = 512;
if (isIndexable) if (isIndexable)
@ -268,20 +273,18 @@ namespace DCFApixels.DragonECS
//public void CloneEntity(int fromEntityID, EcsWorld toWorld, int toEntityID) //public void CloneEntity(int fromEntityID, EcsWorld toWorld, int toEntityID)
#endregion #endregion
#region Components Increment #region Components Register
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void IncrementEntityComponentCount(int entityID, int componentID) private void RegisterEntityComponent(int entityID, int componentTypeID, EcsMaskBit maskBit)
{ {
_componentCounts[entityID]++; _componentCounts[entityID]++;
EcsMaskBit bit = EcsMaskBit.FromID(componentID); _entitiesComponentMasks[entityID][maskBit.chankIndex] |= maskBit.mask;
_entitiesComponentMasks[entityID][bit.chankIndex] |= bit.mask;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void DecrementEntityComponentCount(int entityID, int componentID) private void UnregisterEntityComponent(int entityID, int componentTypeID, EcsMaskBit maskBit)
{ {
var count = --_componentCounts[entityID]; var count = --_componentCounts[entityID];
EcsMaskBit bit = EcsMaskBit.FromID(componentID); _entitiesComponentMasks[entityID][maskBit.chankIndex] &= ~maskBit.mask;
_entitiesComponentMasks[entityID][bit.chankIndex] &= ~bit.mask;
if (count == 0 && _allEntites.Has(entityID)) if (count == 0 && _allEntites.Has(entityID))
DelEntity(entityID); DelEntity(entityID);
@ -382,6 +385,34 @@ namespace DCFApixels.DragonECS
} }
} }
#endregion #endregion
public readonly struct PoolsMediator
{
private readonly EcsWorld _world;
public PoolsMediator(EcsWorld world)
{
if (world == null)
{
throw new ArgumentNullException();
}
if (world._poolsMediator._world != null)
{
throw new MethodAccessException("Нельзя создавать вручную");
}
_world = world;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void RegisterComponent(int entityID, int componentTypeID, EcsMaskBit maskBit)
{
_world.RegisterEntityComponent(entityID, componentTypeID, maskBit);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void UnregisterComponent(int entityID, int componentTypeID, EcsMaskBit maskBit)
{
_world.UnregisterEntityComponent(entityID, componentTypeID, maskBit);
}
}
} }
#region Callbacks Interface #region Callbacks Interface
@ -433,9 +464,4 @@ namespace DCFApixels.DragonECS
public static entlong ToEntityLong(this int self, EcsWorld world) => world.GetEntityLong(self); public static entlong ToEntityLong(this int self, EcsWorld world) => world.GetEntityLong(self);
} }
#endregion #endregion
public class PoolsController
{
}
} }

View File

@ -77,15 +77,15 @@ namespace DCFApixels.DragonECS
Type componentType = typeof(TPool).GetInterfaces().First(o => o.IsGenericType && o.GetGenericTypeDefinition() == typeof(IEcsPoolImplementation<>)).GetGenericArguments()[0]; Type componentType = typeof(TPool).GetInterfaces().First(o => o.IsGenericType && o.GetGenericTypeDefinition() == typeof(IEcsPoolImplementation<>)).GetGenericArguments()[0];
int componentTypeCode = EcsTypeCode.Get(componentType); int componentTypeCode = EcsTypeCode.Get(componentType);
if (_componentIds.TryGetValue(componentTypeCode, out int componentID)) if (_componentIds.TryGetValue(componentTypeCode, out int componentTypeID))
{ {
_poolIds[poolTypeCode] = componentID; _poolIds[poolTypeCode] = componentTypeID;
} }
else else
{ {
componentID = _poolsCount++; componentTypeID = _poolsCount++;
_poolIds[poolTypeCode] = componentID; _poolIds[poolTypeCode] = componentTypeID;
_componentIds[componentTypeCode] = componentID; _componentIds[componentTypeCode] = componentTypeID;
} }
if (_poolsCount >= _pools.Length) if (_poolsCount >= _pools.Length)
@ -98,13 +98,13 @@ namespace DCFApixels.DragonECS
Array.Resize(ref _entitiesComponentMasks[i], _pools.Length / 32 + 1); Array.Resize(ref _entitiesComponentMasks[i], _pools.Length / 32 + 1);
} }
if (_pools[componentID] == _nullPool) if (_pools[componentTypeID] == _nullPool)
{ {
var pool = new TPool(); var pool = new TPool();
_pools[componentID] = pool; _pools[componentTypeID] = pool;
pool.OnInit(this, componentID); pool.OnInit(this, _poolsMediator, componentTypeID);
} }
return (TPool)_pools[componentID]; return (TPool)_pools[componentTypeID];
} }
#endregion #endregion
} }

View File

@ -20,7 +20,8 @@ namespace DCFApixels.DragonECS
where T : IEcsHybridComponent where T : IEcsHybridComponent
{ {
private EcsWorld _source; private EcsWorld _source;
private int _componentID; private int _componentTypeID;
private EcsMaskBit _maskBit;
private int[] _mapping;// index = entityID / value = itemIndex;/ value = 0 = no entityID private int[] _mapping;// index = entityID / value = itemIndex;/ value = 0 = no entityID
private T[] _items; //dense private T[] _items; //dense
@ -32,10 +33,12 @@ namespace DCFApixels.DragonECS
private List<IEcsPoolEventListener> _listeners = new List<IEcsPoolEventListener>(); private List<IEcsPoolEventListener> _listeners = new List<IEcsPoolEventListener>();
private EcsWorld.PoolsMediator _mediator;
#region Properites #region Properites
public int Count => _itemsCount; public int Count => _itemsCount;
public int Capacity => _items.Length; public int Capacity => _items.Length;
public int ComponentID => _componentID; public int ComponentID => _componentTypeID;
public Type ComponentType => typeof(T); public Type ComponentType => typeof(T);
public EcsWorld World => _source; public EcsWorld World => _source;
#endregion #endregion
@ -65,7 +68,7 @@ namespace DCFApixels.DragonECS
Array.Resize(ref _entities, _items.Length); Array.Resize(ref _entities, _items.Length);
} }
} }
this.IncrementEntityComponentCount(entityID, _componentID); _mediator.RegisterComponent(entityID, _componentTypeID, _maskBit);
_listeners.InvokeOnAdd(entityID); _listeners.InvokeOnAdd(entityID);
if(isMain) if(isMain)
component.OnAddToPool(_source.GetEntityLong(entityID)); component.OnAddToPool(_source.GetEntityLong(entityID));
@ -126,7 +129,7 @@ namespace DCFApixels.DragonECS
_mapping[entityID] = 0; _mapping[entityID] = 0;
_entities[itemIndex] = 0; _entities[itemIndex] = 0;
_itemsCount--; _itemsCount--;
this.DecrementEntityComponentCount(entityID, _componentID); _mediator.UnregisterComponent(entityID, _componentTypeID, _maskBit);
_listeners.InvokeOnDel(entityID); _listeners.InvokeOnDel(entityID);
} }
public void Del(int entityID) public void Del(int entityID)
@ -167,10 +170,12 @@ namespace DCFApixels.DragonECS
#endregion #endregion
#region Callbacks #region Callbacks
void IEcsPoolImplementation.OnInit(EcsWorld world, int componentID) void IEcsPoolImplementation.OnInit(EcsWorld world, EcsWorld.PoolsMediator mediator, int componentTypeID)
{ {
_source = world; _source = world;
_componentID = componentID; _mediator = mediator;
_componentTypeID = componentTypeID;
_maskBit = EcsMaskBit.FromID(componentTypeID);
const int capacity = 512; const int capacity = 512;
@ -286,16 +291,15 @@ namespace DCFApixels.DragonECS
} }
} }
public partial class EcsWorld public abstract partial class EcsWorld
{ {
private Dictionary<Type, HybridMapping> _mappings = new Dictionary<Type, HybridMapping>(); private Dictionary<Type, HybridMapping> _hybridMapping = new Dictionary<Type, HybridMapping>();
internal HybridMapping GetHybridMapping(Type type) internal HybridMapping GetHybridMapping(Type type)
{ {
if(!_mappings.TryGetValue(type, out HybridMapping mapping)) if(!_hybridMapping.TryGetValue(type, out HybridMapping mapping))
{ {
mapping = new HybridMapping(this, type); mapping = new HybridMapping(this, type);
_mappings.Add(type, mapping); _hybridMapping.Add(type, mapping);
} }
return mapping; return mapping;
} }
@ -313,7 +317,6 @@ namespace DCFApixels.DragonECS
private static Type hybridPoolType = typeof(EcsHybridPool<>); private static Type hybridPoolType = typeof(EcsHybridPool<>);
private static MethodInfo getHybridPoolMethod = typeof(EcsHybridPoolExtensions).GetMethod($"{nameof(EcsHybridPoolExtensions.GetPool)}", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); private static MethodInfo getHybridPoolMethod = typeof(EcsHybridPoolExtensions).GetMethod($"{nameof(EcsHybridPoolExtensions.GetPool)}", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
private static HashSet<Type> _hybridComponents = new HashSet<Type>(); private static HashSet<Type> _hybridComponents = new HashSet<Type>();
static HybridMapping() static HybridMapping()
{ {

View File

@ -11,7 +11,7 @@ namespace DCFApixels.DragonECS
where T : struct, IEcsComponent where T : struct, IEcsComponent
{ {
private EcsWorld _source; private EcsWorld _source;
private int _componentID; private int _componentTypeID;
private EcsMaskBit _maskBit; private EcsMaskBit _maskBit;
private int[] _mapping;// index = entityID / value = itemIndex;/ value = 0 = no entityID private int[] _mapping;// index = entityID / value = itemIndex;/ value = 0 = no entityID
@ -25,10 +25,12 @@ namespace DCFApixels.DragonECS
private List<IEcsPoolEventListener> _listeners = new List<IEcsPoolEventListener>(); private List<IEcsPoolEventListener> _listeners = new List<IEcsPoolEventListener>();
private EcsWorld.PoolsMediator _mediator;
#region Properites #region Properites
public int Count => _itemsCount; public int Count => _itemsCount;
public int Capacity => _items.Length; public int Capacity => _items.Length;
public int ComponentID => _componentID; public int ComponentID => _componentTypeID;
public Type ComponentType => typeof(T); public Type ComponentType => typeof(T);
public EcsWorld World => _source; public EcsWorld World => _source;
#endregion #endregion
@ -51,7 +53,7 @@ namespace DCFApixels.DragonECS
if (itemIndex >= _items.Length) if (itemIndex >= _items.Length)
Array.Resize(ref _items, _items.Length << 1); Array.Resize(ref _items, _items.Length << 1);
} }
this.IncrementEntityComponentCount(entityID, _componentID); _mediator.RegisterComponent(entityID, _componentTypeID, _maskBit);
_listeners.InvokeOnAddAndGet(entityID); _listeners.InvokeOnAddAndGet(entityID);
return ref _items[itemIndex]; return ref _items[itemIndex];
} }
@ -88,7 +90,7 @@ namespace DCFApixels.DragonECS
if (itemIndex >= _items.Length) if (itemIndex >= _items.Length)
Array.Resize(ref _items, _items.Length << 1); Array.Resize(ref _items, _items.Length << 1);
} }
this.IncrementEntityComponentCount(entityID, _componentID); _mediator.RegisterComponent(entityID, _componentTypeID, _maskBit);
_listeners.InvokeOnAdd(entityID); _listeners.InvokeOnAdd(entityID);
} }
_listeners.InvokeOnGet(entityID); _listeners.InvokeOnGet(entityID);
@ -111,7 +113,7 @@ namespace DCFApixels.DragonECS
_recycledItems[_recycledItemsCount++] = itemIndex; _recycledItems[_recycledItemsCount++] = itemIndex;
_mapping[entityID] = 0; _mapping[entityID] = 0;
_itemsCount--; _itemsCount--;
this.DecrementEntityComponentCount(entityID, _componentID); _mediator.UnregisterComponent(entityID, _componentTypeID, _maskBit);
_listeners.InvokeOnDel(entityID); _listeners.InvokeOnDel(entityID);
} }
public void TryDel(int entityID) public void TryDel(int entityID)
@ -135,12 +137,12 @@ namespace DCFApixels.DragonECS
#endregion #endregion
#region Callbacks #region Callbacks
void IEcsPoolImplementation.OnInit(EcsWorld world, int componentID) void IEcsPoolImplementation.OnInit(EcsWorld world, EcsWorld.PoolsMediator mediator, int componentTypeID)
{ {
_source = world; _source = world;
_componentID = componentID; _mediator = mediator;
_componentTypeID = componentTypeID;
_maskBit = EcsMaskBit.FromID(componentID); _maskBit = EcsMaskBit.FromID(componentTypeID);
const int capacity = 512; const int capacity = 512;

View File

@ -49,7 +49,7 @@ namespace DCFApixels.DragonECS
/// <summary>Only used to implement a custom pool. In other contexts use IEcsPool or IEcsPool<T>.</summary> /// <summary>Only used to implement a custom pool. In other contexts use IEcsPool or IEcsPool<T>.</summary>
public interface IEcsPoolImplementation : IEcsPool public interface IEcsPoolImplementation : IEcsPool
{ {
void OnInit(EcsWorld world, int componentID); void OnInit(EcsWorld world, EcsWorld.PoolsMediator mediator, int componentTypeID);
void OnWorldResize(int newSize); void OnWorldResize(int newSize);
void OnReleaseDelEntityBuffer(ReadOnlySpan<int> buffer); void OnReleaseDelEntityBuffer(ReadOnlySpan<int> buffer);
void OnWorldDestroy(); void OnWorldDestroy();
@ -71,17 +71,6 @@ namespace DCFApixels.DragonECS
} }
public static class IEcsPoolImplementationExtensions public static class IEcsPoolImplementationExtensions
{ {
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void IncrementEntityComponentCount<T>(this IEcsPoolImplementation<T> self, int entityID, int componentID)
{
self.World.IncrementEntityComponentCount(entityID, componentID);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void DecrementEntityComponentCount<T>(this IEcsPoolImplementation<T> self, int entityID, int componentID)
{
self.World.DecrementEntityComponentCount(entityID, componentID);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsNullOrDummy(this IEcsPool self) public static bool IsNullOrDummy(this IEcsPool self)
{ {
@ -116,7 +105,7 @@ namespace DCFApixels.DragonECS
#endregion #endregion
#region Callbacks #region Callbacks
void IEcsPoolImplementation.OnInit(EcsWorld world, int componentID) { } void IEcsPoolImplementation.OnInit(EcsWorld world, EcsWorld.PoolsMediator mediator, int componentTypeID) { }
void IEcsPoolImplementation.OnWorldDestroy() { } void IEcsPoolImplementation.OnWorldDestroy() { }
void IEcsPoolImplementation.OnWorldResize(int newSize) { } void IEcsPoolImplementation.OnWorldResize(int newSize) { }
void IEcsPoolImplementation.OnReleaseDelEntityBuffer(ReadOnlySpan<int> buffer) { } void IEcsPoolImplementation.OnReleaseDelEntityBuffer(ReadOnlySpan<int> buffer) { }

View File

@ -10,7 +10,8 @@ namespace DCFApixels.DragonECS
where T : struct, IEcsTagComponent where T : struct, IEcsTagComponent
{ {
private EcsWorld _source; private EcsWorld _source;
private int _componentID; private int _componentTypeID;
private EcsMaskBit _maskBit;
private bool[] _mapping;// index = entityID / value = itemIndex;/ value = 0 = no entityID private bool[] _mapping;// index = entityID / value = itemIndex;/ value = 0 = no entityID
private int _count; private int _count;
@ -18,8 +19,9 @@ namespace DCFApixels.DragonECS
private List<IEcsPoolEventListener> _listeners = new List<IEcsPoolEventListener>(); private List<IEcsPoolEventListener> _listeners = new List<IEcsPoolEventListener>();
private T _fakeComponent; private T _fakeComponent;
private EcsWorld.PoolsMediator _mediator;
#region Constructors
private static bool _isInvalidType; private static bool _isInvalidType;
static EcsTagPool() static EcsTagPool()
{ {
@ -30,11 +32,12 @@ namespace DCFApixels.DragonECS
if (_isInvalidType) if (_isInvalidType)
throw new EcsFrameworkException($"{typeof(T).Name} type must not contain any data."); throw new EcsFrameworkException($"{typeof(T).Name} type must not contain any data.");
} }
#endregion
#region Properites #region Properites
public int Count => _count; public int Count => _count;
int IEcsPool.Capacity => -1; int IEcsPool.Capacity => -1;
public int ComponentID => _componentID; public int ComponentID => _componentTypeID;
public Type ComponentType => typeof(T); public Type ComponentType => typeof(T);
public EcsWorld World => _source; public EcsWorld World => _source;
#endregion #endregion
@ -47,7 +50,7 @@ namespace DCFApixels.DragonECS
#endif #endif
_count++; _count++;
_mapping[entityID] = true; _mapping[entityID] = true;
this.IncrementEntityComponentCount(entityID, _componentID); _mediator.RegisterComponent(entityID, _componentTypeID, _maskBit);
_listeners.InvokeOnAdd(entityID); _listeners.InvokeOnAdd(entityID);
} }
public void TryAdd(int entityID) public void TryAdd(int entityID)
@ -56,7 +59,7 @@ namespace DCFApixels.DragonECS
{ {
_count++; _count++;
_mapping[entityID] = true; _mapping[entityID] = true;
this.IncrementEntityComponentCount(entityID, _componentID); _mediator.RegisterComponent(entityID, _componentTypeID, _maskBit);
_listeners.InvokeOnAdd(entityID); _listeners.InvokeOnAdd(entityID);
} }
} }
@ -72,7 +75,7 @@ namespace DCFApixels.DragonECS
#endif #endif
_mapping[entityID] = false; _mapping[entityID] = false;
_count--; _count--;
this.DecrementEntityComponentCount(entityID, _componentID); _mediator.UnregisterComponent(entityID, _componentTypeID, _maskBit);
_listeners.InvokeOnDel(entityID); _listeners.InvokeOnDel(entityID);
} }
public void TryDel(int entityID) public void TryDel(int entityID)
@ -116,10 +119,12 @@ namespace DCFApixels.DragonECS
#endregion #endregion
#region Callbacks #region Callbacks
void IEcsPoolImplementation.OnInit(EcsWorld world, int componentID) void IEcsPoolImplementation.OnInit(EcsWorld world, EcsWorld.PoolsMediator mediator, int componentTypeID)
{ {
_source = world; _source = world;
_componentID = componentID; _mediator = mediator;
_componentTypeID = componentTypeID;
_maskBit = EcsMaskBit.FromID(componentTypeID);
_mapping = new bool[world.Capacity]; _mapping = new bool[world.Capacity];
_count = 0; _count = 0;

View File

@ -1,332 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace DCFApixels.DragonECS
{
/// <summary>Pool for IEcsComponent components</summary>
public sealed class EcsTestPool<T> : IEcsPoolImplementation<T>, IEcsStructPool<T>, IEnumerable<T> //IEnumerable<T> - IntelliSense hack
where T : struct, IEcsTestComponent
{
private EcsWorld _source;
private int _componentID;
public const int MIN_CAPACITY_BITS_OFFSET = 4;
public const int MIN_CAPACITY = 1 << MIN_CAPACITY_BITS_OFFSET;
private const int EMPTY = -1;
private int[] _buckets = Array.Empty<int>();
private Entry[] _entries = Array.Empty<Entry>();
private int _count;
private int _freeList;
private int _freeCount;
private int _modBitMask;
private IEcsComponentReset<T> _componentResetHandler = EcsComponentResetHandler<T>.instance;
private IEcsComponentCopy<T> _componentCopyHandler = EcsComponentCopyHandler<T>.instance;
private List<IEcsPoolEventListener> _listeners = new List<IEcsPoolEventListener>();
#region Properites
public int Count => _count;
public int Capacity => _entries.Length;
public int ComponentID => _componentID;
public Type ComponentType => typeof(T);
public EcsWorld World => _source;
#endregion
#region Methods
public void Copy(int fromEntityID, int toEntityID)
{
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
if (!Has(fromEntityID)) EcsPoolThrowHalper.ThrowNotHaveComponent<T>(fromEntityID);
#endif
_componentCopyHandler.Copy(ref Get(fromEntityID), ref TryAddOrGet(toEntityID));
}
public void Copy(int fromEntityID, EcsWorld toWorld, int toEntityID)
{
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
if (!Has(fromEntityID)) EcsPoolThrowHalper.ThrowNotHaveComponent<T>(fromEntityID);
#endif
_componentCopyHandler.Copy(ref Get(fromEntityID), ref toWorld.GetPool<T>().TryAddOrGet(toEntityID));
}
#endregion
#region Callbacks
void IEcsPoolImplementation.OnInit(EcsWorld world, int componentID)
{
_source = world;
_componentID = componentID;
int minCapacity = 512;
minCapacity = NormalizeCapacity(minCapacity);
_buckets = new int[minCapacity];
for (int i = 0; i < minCapacity; i++)
_buckets[i] = EMPTY;
_entries = new Entry[minCapacity];
_modBitMask = (minCapacity - 1) & 0x7FFFFFFF;
}
void IEcsPoolImplementation.OnWorldResize(int newSize) { }
void IEcsPoolImplementation.OnWorldDestroy() { }
void IEcsPoolImplementation.OnReleaseDelEntityBuffer(ReadOnlySpan<int> buffer)
{
foreach (var entityID in buffer)
TryDel(entityID);
}
#endregion
#region Other
void IEcsPool.AddRaw(int entityID, object dataRaw) => Add(entityID) = (T)dataRaw;
object IEcsPool.GetRaw(int entityID) => Read(entityID);
void IEcsPool.SetRaw(int entityID, object dataRaw) => Get(entityID) = (T)dataRaw;
ref readonly T IEcsStructPool<T>.Read(int entityID) => ref Read(entityID);
ref T IEcsStructPool<T>.Get(int entityID) => ref Get(entityID);
#endregion
#region Listeners
public void AddListener(IEcsPoolEventListener listener)
{
if (listener == null) { throw new ArgumentNullException("listener is null"); }
_listeners.Add(listener);
}
public void RemoveListener(IEcsPoolEventListener listener)
{
if (listener == null) { throw new ArgumentNullException("listener is null"); }
_listeners.Remove(listener);
}
#endregion
#region IEnumerator - IntelliSense hack
IEnumerator<T> IEnumerable<T>.GetEnumerator() => throw new NotImplementedException();
IEnumerator IEnumerable.GetEnumerator() => throw new NotImplementedException();
#endregion
#region Find/Insert/Remove
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private int FindEntry(long x, long y)
{
return FindEntry(x << 32 | y);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private int FindEntry(long key)
{
for (int i = _buckets[unchecked((int)key & _modBitMask)]; i >= 0; i = _entries[i].next)
if (_entries[i].key == key) return i;
return -1;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Has(int entityID) => Has(entityID, entityID);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private bool Has(long x, long y) => Has(x << 32 | y);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private bool Has(long key) {
for (int i = _buckets[unchecked((int)key & _modBitMask)]; i >= 0; i = _entries[i].next)
if (_entries[i].key == key) return true;
return false;
}
public ref T Add(int entityID) => ref Add(entityID, entityID);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private ref T Add(long x, long y) => ref Add(x << 32 | y);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private ref T Add(long key)
{
int entityID = unchecked((int)key);
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
if (Has(key: key)) EcsPoolThrowHalper.ThrowAlreadyHasComponent<T>(entityID);
#endif
int index;
if (_freeCount > 0)
{
index = _freeList;
_freeList = _entries[index].next;
_freeCount--;
}
else
{
if (_count == _entries.Length)
Resize();
index = _count++;
}
int targetBucket = unchecked((int)key & _modBitMask);
ref var entry = ref _entries[index];
entry.next = _buckets[targetBucket];
entry.key = key;
entry.value = default;
_buckets[targetBucket] = index;
this.IncrementEntityComponentCount(entityID, _componentID);
_listeners.InvokeOnAddAndGet(entityID);
return ref entry.value;
}
public ref T TryAddOrGet(int entityID)
{
throw new NotImplementedException();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref T Get(int entityID) => ref Get(entityID, entityID);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private ref T Get(long x, long y) => ref Get(x << 32 | y);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private ref T Get(long key)
{
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
if (!Has(key: key)) EcsPoolThrowHalper.ThrowNotHaveComponent<T>(unchecked((int)key));
#endif
_listeners.InvokeOnGet(unchecked((int)key));
//return ref _entries[FindEntry(key)].value;
for (int i = _buckets[unchecked((int)key & _modBitMask)]; i >= 0; i = _entries[i].next)
if (_entries[i].key == key) return ref _entries[i].value; // return i;
#pragma warning disable CS0251 // Èíäåêñàöèÿ ìàññèâà ñ îòðèöàòåëüíûì èíäåêñîì
return ref _entries[-1].value; //ïðè íîðìàëüíîé ðàáîòå ýòî íåäîñòèæèìûé êîä.
#pragma warning restore CS0251 // Èíäåêñàöèÿ ìàññèâà ñ îòðèöàòåëüíûì èíäåêñîì
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref readonly T Read(int entityID) => ref Read(entityID, entityID);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref readonly T Read(long x, long y) => ref Read(x << 32 | y);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref readonly T Read(long key)
{
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
if (!Has(key: key)) EcsPoolThrowHalper.ThrowNotHaveComponent<T>(unchecked((int)key));
#endif
return ref _entries[FindEntry(key)].value;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Del(int entityID) => Del(entityID, entityID);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void Del(long keyX, long keyY) => Del(keyX + (keyY << 32));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void Del(long key)
{
int entityID = unchecked((int)key);
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
if (!Has(key: key)) EcsPoolThrowHalper.ThrowNotHaveComponent<T>(entityID);
#endif
int bucket = unchecked((int)key & _modBitMask);
int last = -1;
for (int i = _buckets[bucket]; i >= 0; last = i, i = _entries[i].next)
{
if (_entries[i].key == key)
{
if (last < 0)
{
_buckets[bucket] = _entries[i].next;
}
else
{
_entries[last].next = _entries[i].next;
}
_entries[i].next = _freeList;
_entries[i].key = -1;
//_entries[i].value = default;
_componentResetHandler.Reset(ref _entries[i].value);
_freeList = i;
_freeCount++;
this.DecrementEntityComponentCount(entityID, _componentID);
_listeners.InvokeOnDel(entityID);
return;
}
}
}
public void TryDel(int entityID)
{
if (Has(entityID)) Del(entityID);
}
#endregion
#region Resize
private void Resize()
{
int newSize = _buckets.Length << 1;
_modBitMask = (newSize - 1) & 0x7FFFFFFF;
Contract.Assert(newSize >= _entries.Length);
int[] newBuckets = new int[newSize];
for (int i = 0; i < newBuckets.Length; i++)
newBuckets[i] = EMPTY;
Entry[] newEntries = new Entry[newSize];
Array.Copy(_entries, 0, newEntries, 0, _count);
for (int i = 0; i < _count; i++)
{
if (newEntries[i].key >= 0)
{
int bucket = unchecked((int)newEntries[i].key & _modBitMask);
newEntries[i].next = newBuckets[bucket];
newBuckets[bucket] = i;
}
}
_buckets = newBuckets;
_entries = newEntries;
}
private int NormalizeCapacity(int capacity)
{
int result = MIN_CAPACITY;
while (result < capacity) result <<= 1;
return result;
}
#endregion
#region Utils
[StructLayout(LayoutKind.Sequential, Pack = 4)]
private struct Entry
{
public int next; // Index of next entry, -1 if last
public long key;
public T value;
}
#endregion
}
/// <summary>Standard component</summary>
public interface IEcsTestComponent { }
public static class EcsTestPoolExt
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static EcsTestPool<TComponent> GetPool<TComponent>(this EcsWorld self) where TComponent : struct, IEcsTestComponent
{
return self.GetPool<EcsTestPool<TComponent>>();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static EcsTestPool<TComponent> GetPoolUnchecked<TComponent>(this EcsWorld self) where TComponent : struct, IEcsTestComponent
{
return self.GetPoolUnchecked<EcsTestPool<TComponent>>();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static EcsTestPool<TComponent> Include<TComponent>(this EcsAspectBuilderBase self) where TComponent : struct, IEcsTestComponent
{
return self.Include<EcsTestPool<TComponent>>();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static EcsTestPool<TComponent> Exclude<TComponent>(this EcsAspectBuilderBase self) where TComponent : struct, IEcsTestComponent
{
return self.Exclude<EcsTestPool<TComponent>>();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static EcsTestPool<TComponent> Optional<TComponent>(this EcsAspectBuilderBase self) where TComponent : struct, IEcsTestComponent
{
return self.Optional<EcsTestPool<TComponent>>();
}
}
}