From 5e6ac8cb168bf3deaea95fcfd2a8bb255e8a28c1 Mon Sep 17 00:00:00 2001 From: Mikhail <99481254+DCFApixels@users.noreply.github.com> Date: Wed, 22 Nov 2023 11:53:41 +0800 Subject: [PATCH] add gc-like clearing of deleted entities --- src/Builtin/Systems.cs | 9 ++++++--- src/EcsPipeline.cs | 2 +- src/EcsWorld.cs | 19 ++++++++++++++++++- src/EcsWorld.static.cs | 3 ++- 4 files changed, 27 insertions(+), 6 deletions(-) diff --git a/src/Builtin/Systems.cs b/src/Builtin/Systems.cs index f478cf6..c164dcb 100644 --- a/src/Builtin/Systems.cs +++ b/src/Builtin/Systems.cs @@ -12,14 +12,17 @@ namespace DCFApixels.DragonECS public SystemsLayerMarkerSystem(string name) => this.name = name; } [DebugHide, DebugColor(DebugColor.Grey)] - public class DeleteEmptyEntitesSystem : IEcsRunProcess, IEcsInject + public class EndFrameSystem : IEcsRunProcess, IEcsInject { - private List _worlds = new List(); + private readonly List _worlds = new List(); public void Inject(EcsWorld obj) => _worlds.Add(obj); public void Run(EcsPipeline pipeline) { foreach (var world in _worlds) + { world.DeleteEmptyEntites(); + world.ReleaseDelEntityBuffer(); + } } } [DebugHide, DebugColor(DebugColor.Grey)] @@ -31,7 +34,7 @@ namespace DCFApixels.DragonECS public EcsPool pool; public Aspect(Builder b) => pool = b.Include(); } - List _worlds = new List(); + private readonly List _worlds = new List(); public void Inject(EcsWorld obj) => _worlds.Add(obj); public void Run(EcsPipeline pipeline) { diff --git a/src/EcsPipeline.cs b/src/EcsPipeline.cs index 7d7bb35..a3979ec 100644 --- a/src/EcsPipeline.cs +++ b/src/EcsPipeline.cs @@ -160,7 +160,7 @@ namespace DCFApixels.DragonECS } public EcsPipeline Build() { - Add(new DeleteEmptyEntitesSystem(), EcsConsts.POST_END_LAYER); + Add(new EndFrameSystem(), EcsConsts.POST_END_LAYER); List result = new List(32); List basicBlockList = _systems[_basicLayer]; foreach (var item in _systems) diff --git a/src/EcsWorld.cs b/src/EcsWorld.cs index 9bb781e..b17d31e 100644 --- a/src/EcsWorld.cs +++ b/src/EcsWorld.cs @@ -2,6 +2,7 @@ using DCFApixels.DragonECS.Utils; using System; using System.Collections.Generic; +using System.Diagnostics; using System.Runtime.CompilerServices; namespace DCFApixels.DragonECS @@ -21,6 +22,8 @@ namespace DCFApixels.DragonECS private int[] _delEntBuffer; private int _delEntBufferCount; + private int _delEntBufferMinCount; + private int _usedSpace; private List> _groups = new List>(); private Stack _groupsPool = new Stack(64); @@ -32,6 +35,7 @@ namespace DCFApixels.DragonECS public bool IsDestroyed => _isDestroyed; public int Count => _entitiesCount; public int Capacity => _entitesCapacity; //_denseEntities.Length; + internal int DelBufferCount => _usedSpace - _entitiesCount; //_denseEntities.Length; public EcsReadonlyGroup Entities => _allEntites.Readonly; public ReadOnlySpan AllPools => _pools;// new ReadOnlySpan(pools, 0, _poolsCount); #endregion @@ -59,7 +63,9 @@ namespace DCFApixels.DragonECS ArrayUtility.Fill(_gens, DEATH_GEN_BIT); _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(); } @@ -127,15 +133,23 @@ namespace DCFApixels.DragonECS #endregion #region Entity + + private int FreeSpace => Capacity - _usedSpace; public int NewEmptyEntity() { + if(FreeSpace <= 1 && DelBufferCount > _delEntBufferMinCount) + ReleaseDelEntityBuffer(); + int entityID = _entityDispenser.GetFree(); + _usedSpace++; _entitiesCount++; if (_gens.Length <= entityID) { Array.Resize(ref _gens, _gens.Length << 1); 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); _entitesCapacity = _gens.Length; @@ -213,12 +227,15 @@ namespace DCFApixels.DragonECS } public void ReleaseDelEntityBuffer() { + if (_delEntBufferCount <= 0) + return; ReadOnlySpan buffser = new ReadOnlySpan(_delEntBuffer, 0, _delEntBufferCount); foreach (var pool in _pools) pool.OnReleaseDelEntityBuffer(buffser); _listeners.InvokeOnReleaseDelEntityBuffer(buffser); for (int i = 0; i < _delEntBufferCount; i++) _entityDispenser.Release(_delEntBuffer[i]); + _usedSpace = _entitiesCount; _delEntBufferCount = 0; } public void DeleteEmptyEntites() diff --git a/src/EcsWorld.static.cs b/src/EcsWorld.static.cs index 4b11c25..558804e 100644 --- a/src/EcsWorld.static.cs +++ b/src/EcsWorld.static.cs @@ -18,7 +18,8 @@ namespace DCFApixels.DragonECS { private const short GEN_BITS = 0x7fff; 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 IdDispenser _worldIdDispenser = new IdDispenser(0);