add gc-like clearing of deleted entities

This commit is contained in:
Mikhail 2023-11-22 11:53:41 +08:00
parent de88b0a8dd
commit 5e6ac8cb16
4 changed files with 27 additions and 6 deletions

View File

@ -12,14 +12,17 @@ namespace DCFApixels.DragonECS
public SystemsLayerMarkerSystem(string name) => this.name = name; public SystemsLayerMarkerSystem(string name) => this.name = name;
} }
[DebugHide, DebugColor(DebugColor.Grey)] [DebugHide, DebugColor(DebugColor.Grey)]
public class DeleteEmptyEntitesSystem : IEcsRunProcess, IEcsInject<EcsWorld> public class EndFrameSystem : IEcsRunProcess, IEcsInject<EcsWorld>
{ {
private 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(EcsPipeline pipeline)
{ {
foreach (var world in _worlds) foreach (var world in _worlds)
{
world.DeleteEmptyEntites(); world.DeleteEmptyEntites();
world.ReleaseDelEntityBuffer();
}
} }
} }
[DebugHide, DebugColor(DebugColor.Grey)] [DebugHide, DebugColor(DebugColor.Grey)]
@ -31,7 +34,7 @@ namespace DCFApixels.DragonECS
public EcsPool<TComponent> pool; public EcsPool<TComponent> pool;
public Aspect(Builder b) => pool = b.Include<TComponent>(); public Aspect(Builder b) => pool = b.Include<TComponent>();
} }
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(EcsPipeline pipeline)
{ {

View File

@ -160,7 +160,7 @@ namespace DCFApixels.DragonECS
} }
public EcsPipeline Build() public EcsPipeline Build()
{ {
Add(new DeleteEmptyEntitesSystem(), EcsConsts.POST_END_LAYER); Add(new EndFrameSystem(), EcsConsts.POST_END_LAYER);
List<IEcsProcess> result = new List<IEcsProcess>(32); List<IEcsProcess> result = new List<IEcsProcess>(32);
List<IEcsProcess> basicBlockList = _systems[_basicLayer]; List<IEcsProcess> basicBlockList = _systems[_basicLayer];
foreach (var item in _systems) foreach (var item in _systems)

View File

@ -2,6 +2,7 @@
using DCFApixels.DragonECS.Utils; using DCFApixels.DragonECS.Utils;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
namespace DCFApixels.DragonECS namespace DCFApixels.DragonECS
@ -21,6 +22,8 @@ namespace DCFApixels.DragonECS
private int[] _delEntBuffer; private int[] _delEntBuffer;
private int _delEntBufferCount; private int _delEntBufferCount;
private int _delEntBufferMinCount;
private int _usedSpace;
private List<WeakReference<EcsGroup>> _groups = new List<WeakReference<EcsGroup>>(); private List<WeakReference<EcsGroup>> _groups = new List<WeakReference<EcsGroup>>();
private Stack<EcsGroup> _groupsPool = new Stack<EcsGroup>(64); private Stack<EcsGroup> _groupsPool = new Stack<EcsGroup>(64);
@ -32,6 +35,7 @@ namespace DCFApixels.DragonECS
public bool IsDestroyed => _isDestroyed; public bool IsDestroyed => _isDestroyed;
public int Count => _entitiesCount; public int Count => _entitiesCount;
public int Capacity => _entitesCapacity; //_denseEntities.Length; public int Capacity => _entitesCapacity; //_denseEntities.Length;
internal int DelBufferCount => _usedSpace - _entitiesCount; //_denseEntities.Length;
public EcsReadonlyGroup Entities => _allEntites.Readonly; public EcsReadonlyGroup Entities => _allEntites.Readonly;
public ReadOnlySpan<IEcsPoolImplementation> AllPools => _pools;// new ReadOnlySpan<IEcsPoolImplementation>(pools, 0, _poolsCount); public ReadOnlySpan<IEcsPoolImplementation> AllPools => _pools;// new ReadOnlySpan<IEcsPoolImplementation>(pools, 0, _poolsCount);
#endregion #endregion
@ -59,7 +63,9 @@ namespace DCFApixels.DragonECS
ArrayUtility.Fill(_gens, DEATH_GEN_BIT); ArrayUtility.Fill(_gens, DEATH_GEN_BIT);
_delEntBufferCount = 0; _delEntBufferCount = 0;
_delEntBuffer = new int[_entitesCapacity >> DEL_ENT_BUFFER_SIZE_OFFSET]; //_delEntBuffer = new int[_entitesCapacity >> DEL_ENT_BUFFER_SIZE_OFFSET];
_delEntBuffer = new int[_entitesCapacity];
_delEntBufferMinCount = Math.Max(_delEntBuffer.Length >> DEL_ENT_BUFFER_SIZE_OFFSET, DEL_ENT_BUFFER_MIN_SIZE);
_allEntites = GetFreeGroup(); _allEntites = GetFreeGroup();
} }
@ -127,15 +133,23 @@ namespace DCFApixels.DragonECS
#endregion #endregion
#region Entity #region Entity
private int FreeSpace => Capacity - _usedSpace;
public int NewEmptyEntity() public int NewEmptyEntity()
{ {
if(FreeSpace <= 1 && DelBufferCount > _delEntBufferMinCount)
ReleaseDelEntityBuffer();
int entityID = _entityDispenser.GetFree(); int entityID = _entityDispenser.GetFree();
_usedSpace++;
_entitiesCount++; _entitiesCount++;
if (_gens.Length <= entityID) if (_gens.Length <= entityID)
{ {
Array.Resize(ref _gens, _gens.Length << 1); Array.Resize(ref _gens, _gens.Length << 1);
Array.Resize(ref _componentCounts, _gens.Length); Array.Resize(ref _componentCounts, _gens.Length);
Array.Resize(ref _delEntBuffer, _gens.Length);
_delEntBufferMinCount = Math.Max(_delEntBuffer.Length >> DEL_ENT_BUFFER_SIZE_OFFSET, DEL_ENT_BUFFER_MIN_SIZE);
ArrayUtility.Fill(_gens, DEATH_GEN_BIT, _entitesCapacity); ArrayUtility.Fill(_gens, DEATH_GEN_BIT, _entitesCapacity);
_entitesCapacity = _gens.Length; _entitesCapacity = _gens.Length;
@ -213,12 +227,15 @@ namespace DCFApixels.DragonECS
} }
public void ReleaseDelEntityBuffer() public void ReleaseDelEntityBuffer()
{ {
if (_delEntBufferCount <= 0)
return;
ReadOnlySpan<int> buffser = new ReadOnlySpan<int>(_delEntBuffer, 0, _delEntBufferCount); ReadOnlySpan<int> buffser = new ReadOnlySpan<int>(_delEntBuffer, 0, _delEntBufferCount);
foreach (var pool in _pools) foreach (var pool in _pools)
pool.OnReleaseDelEntityBuffer(buffser); pool.OnReleaseDelEntityBuffer(buffser);
_listeners.InvokeOnReleaseDelEntityBuffer(buffser); _listeners.InvokeOnReleaseDelEntityBuffer(buffser);
for (int i = 0; i < _delEntBufferCount; i++) for (int i = 0; i < _delEntBufferCount; i++)
_entityDispenser.Release(_delEntBuffer[i]); _entityDispenser.Release(_delEntBuffer[i]);
_usedSpace = _entitiesCount;
_delEntBufferCount = 0; _delEntBufferCount = 0;
} }
public void DeleteEmptyEntites() public void DeleteEmptyEntites()

View File

@ -18,7 +18,8 @@ namespace DCFApixels.DragonECS
{ {
private const short GEN_BITS = 0x7fff; private const short GEN_BITS = 0x7fff;
private const short DEATH_GEN_BIT = short.MinValue; private const short DEATH_GEN_BIT = short.MinValue;
private const int DEL_ENT_BUFFER_SIZE_OFFSET = 2; private const int DEL_ENT_BUFFER_SIZE_OFFSET = 5;
private const int DEL_ENT_BUFFER_MIN_SIZE = 64;
private static EcsWorld[] Worlds = new EcsWorld[4]; private static EcsWorld[] Worlds = new EcsWorld[4];
private static IdDispenser _worldIdDispenser = new IdDispenser(0); private static IdDispenser _worldIdDispenser = new IdDispenser(0);