From 6ebda350a391b83e68f7a368f08ff23a5f433a79 Mon Sep 17 00:00:00 2001 From: Mikhail <99481254+DCFApixels@users.noreply.github.com> Date: Thu, 11 Jan 2024 00:48:39 +0800 Subject: [PATCH 01/16] update --- src/DataInterfaces.cs | 48 ++++++++++++++-- src/EcsAspect.cs | 9 +-- src/EcsMask.cs | 124 ++++++++++++++++++++++++++--------------- src/EcsWorld.pools.cs | 8 +++ src/EcsWorld.static.cs | 2 - 5 files changed, 132 insertions(+), 59 deletions(-) diff --git a/src/DataInterfaces.cs b/src/DataInterfaces.cs index 5255dd5..260f507 100644 --- a/src/DataInterfaces.cs +++ b/src/DataInterfaces.cs @@ -1,7 +1,26 @@ using System; using System.Linq; using System.Runtime.CompilerServices; +using static DCFApixels.DragonECS.Internal.DataInterfaceHalper; +namespace DCFApixels.DragonECS.Internal +{ + #region DataInterfaceHalper + public static class DataInterfaceHalper + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void CheckFakeInstanceValide(T fakeInstnace) + { +#if DEBUG + if (fakeInstnace.Equals(default) == false) + { + throw new Exception("Не правильное применение интерфейса, менять нужно передаваемое по ref значение"); + } +#endif + } + } + #endregion +} namespace DCFApixels.DragonECS { #region IEcsWorldComponent @@ -34,13 +53,22 @@ namespace DCFApixels.DragonECS public void OnDestroy(ref T component, EcsWorld world) { } } } - internal class WorldComponentHandler : IEcsWorldComponent - where T : IEcsWorldComponent + internal sealed class WorldComponentHandler : IEcsWorldComponent + where T : struct, IEcsWorldComponent { private T _fakeInstnace = default; [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Init(ref T component, EcsWorld world) => _fakeInstnace.Init(ref component, world); - public void OnDestroy(ref T component, EcsWorld world) => _fakeInstnace.OnDestroy(ref component, world); + public void Init(ref T component, EcsWorld world) + { + _fakeInstnace.Init(ref component, world); + CheckFakeInstanceValide(_fakeInstnace); + } + public void OnDestroy(ref T component, EcsWorld world) + { + _fakeInstnace.OnDestroy(ref component, world); + CheckFakeInstanceValide(_fakeInstnace); + } + } #endregion @@ -77,7 +105,11 @@ namespace DCFApixels.DragonECS { private T _fakeInstnace = default; [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Reset(ref T component) => _fakeInstnace.Reset(ref component); + public void Reset(ref T component) + { + _fakeInstnace.Reset(ref component); + CheckFakeInstanceValide(_fakeInstnace); + } } #endregion @@ -114,7 +146,11 @@ namespace DCFApixels.DragonECS { private T _fakeInstnace = default; [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Copy(ref T from, ref T to) => _fakeInstnace.Copy(ref from, ref to); + public void Copy(ref T from, ref T to) + { + _fakeInstnace.Copy(ref from, ref to); + CheckFakeInstanceValide(_fakeInstnace); + } } #endregion } diff --git a/src/EcsAspect.cs b/src/EcsAspect.cs index 17c6369..08eb851 100644 --- a/src/EcsAspect.cs +++ b/src/EcsAspect.cs @@ -40,7 +40,7 @@ namespace DCFApixels.DragonECS private Builder(EcsWorld world) { _world = world; - _maskBuilder = new EcsMask.Builder(world); + _maskBuilder = EcsMask.New(world); } internal static unsafe TAspect New(EcsWorld world) where TAspect : EcsAspect { @@ -113,16 +113,11 @@ namespace DCFApixels.DragonECS public TOtherAspect Combine(int order = 0) where TOtherAspect : EcsAspect { var result = _world.GetAspect(); - _maskBuilder.CombineWith(result.Mask); + _maskBuilder.Combine(result.Mask); return result; } #endregion - public EcsWorldCmp GetWorldData() where T : struct - { - return new EcsWorldCmp(_world.id); - } - private void Build(out EcsMask mask) { mask = _maskBuilder.Build(); diff --git a/src/EcsMask.cs b/src/EcsMask.cs index f6c27b2..e79144e 100644 --- a/src/EcsMask.cs +++ b/src/EcsMask.cs @@ -7,20 +7,6 @@ using System.Runtime.CompilerServices; namespace DCFApixels.DragonECS { - public abstract partial class EcsWorld - { - private Dictionary _masks = new Dictionary(256); - internal EcsMask GetMask_Internal(EcsMask.BuilderMaskKey maskKey) - { - if (!_masks.TryGetValue(maskKey, out EcsMask result)) - { - result = new EcsMask(_masks.Count, id, maskKey.inc, maskKey.exc); - _masks.Add(maskKey, result); - } - return result; - } - } - [DebuggerTypeProxy(typeof(DebuggerProxy))] public sealed class EcsMask : IEquatable { @@ -42,6 +28,10 @@ namespace DCFApixels.DragonECS #endregion #region Constructors + public static Builder New(EcsWorld world) + { + return new Builder(world); + } internal EcsMask(int id, int worldID, int[] inc, int[] exc) { #if DEBUG @@ -168,19 +158,69 @@ namespace DCFApixels.DragonECS #endregion #region Builder - public readonly struct BuilderMaskKey : IEquatable + private readonly struct WorldMaskComponent : IEcsWorldComponent + { + private readonly EcsWorld _world; + private readonly Dictionary _masks; + + #region Constructor/Destructor + public WorldMaskComponent(EcsWorld world, Dictionary masks) + { + _world = world; + _masks = masks; + } + public void Init(ref WorldMaskComponent component, EcsWorld world) + { + component = new WorldMaskComponent(world, new Dictionary(256)); + } + public void OnDestroy(ref WorldMaskComponent component, EcsWorld world) + { + component._masks.Clear(); + component = default; + } + #endregion + + #region GetMask + internal EcsMask GetMask(Key maskKey) + { + if (!_masks.TryGetValue(maskKey, out EcsMask result)) + { + result = new EcsMask(_masks.Count, _world.id, maskKey.inc, maskKey.exc); + _masks.Add(maskKey, result); + } + return result; + } + #endregion + } + private readonly struct Key : IEquatable { public readonly int[] inc; public readonly int[] exc; public readonly int hash; - public BuilderMaskKey(int[] inc, int[] exc, int hash) + + #region Constructors + public Key(int[] inc, int[] exc) { this.inc = inc; this.exc = exc; - this.hash = hash; + unchecked + { + hash = inc.Length + exc.Length; + for (int i = 0, iMax = inc.Length; i < iMax; i++) + { + hash = hash * EcsConsts.MAGIC_PRIME + inc[i]; + } + for (int i = 0, iMax = exc.Length; i < iMax; i++) + { + hash = hash * EcsConsts.MAGIC_PRIME - exc[i]; + } + } } + #endregion + + #region Object [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(BuilderMaskKey other) + public bool Equals(Key other) { if (inc.Length != other.inc.Length) { @@ -204,16 +244,11 @@ namespace DCFApixels.DragonECS return false; } } -#if DEBUG - if (other.hash != hash) - { - throw new Exception("other.hash != hash"); - } -#endif return true; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public override int GetHashCode() => hash; + #endregion } public class Builder @@ -223,49 +258,58 @@ namespace DCFApixels.DragonECS private readonly HashSet _exc = new HashSet(); private readonly List _combined = new List(); + #region Constrcutors internal Builder(EcsWorld world) { _world = world; } + #endregion - public void Include() + #region Include/Exclude/Combine + public Builder Include() { int id = _world.GetComponentID(); #if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS if (_inc.Contains(id) || _exc.Contains(id)) Throw.ConstraintIsAlreadyContainedInMask(typeof(T)); #endif _inc.Add(id); + return this; } - public void Exclude() + public Builder Exclude() { int id = _world.GetComponentID(); #if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS if (_inc.Contains(id) || _exc.Contains(id)) Throw.ConstraintIsAlreadyContainedInMask(typeof(T)); #endif _exc.Add(id); + return this; } - public void Include(Type type) + public Builder Include(Type type) { int id = _world.GetComponentID(type); #if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS if (_inc.Contains(id) || _exc.Contains(id)) Throw.ConstraintIsAlreadyContainedInMask(type); #endif _inc.Add(id); + return this; } - public void Exclude(Type type) + public Builder Exclude(Type type) { int id = _world.GetComponentID(type); #if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS if (_inc.Contains(id) || _exc.Contains(id)) Throw.ConstraintIsAlreadyContainedInMask(type); #endif _exc.Add(id); + return this; } - - public void CombineWith(EcsMask mask, int order = 0) + public Builder Combine(EcsMask mask, int order = 0) { _combined.Add(new Combined(mask, order)); + return this; } + #endregion + #region Build public EcsMask Build() { HashSet combinedInc; @@ -296,24 +340,16 @@ namespace DCFApixels.DragonECS var inc = combinedInc.ToArray(); Array.Sort(inc); + _inc.Clear(); var exc = combinedExc.ToArray(); Array.Sort(exc); + _exc.Clear(); - unchecked - { - int keyHash = inc.Length + exc.Length; - for (int i = 0, iMax = inc.Length; i < iMax; i++) - { - keyHash = keyHash * EcsConsts.MAGIC_PRIME + inc[i]; - } - for (int i = 0, iMax = exc.Length; i < iMax; i++) - { - keyHash = keyHash * EcsConsts.MAGIC_PRIME - exc[i]; - } - BuilderMaskKey key = new BuilderMaskKey(inc, exc, keyHash); - return _world.GetMask_Internal(key); - } + _combined.Clear(); + + return _world.Get().GetMask(new Key(inc, exc)); } + #endregion } private readonly struct Combined diff --git a/src/EcsWorld.pools.cs b/src/EcsWorld.pools.cs index 06af5e4..a9c371d 100644 --- a/src/EcsWorld.pools.cs +++ b/src/EcsWorld.pools.cs @@ -23,6 +23,14 @@ namespace DCFApixels.DragonECS public int GetComponentID(Type type) => DeclareComponentType(EcsTypeCode.Get(type)); public bool IsComponentTypeDeclared() => _componentIds.Contains(EcsTypeCode.Get()); public bool IsComponentTypeDeclared(Type type) => _componentIds.Contains(EcsTypeCode.Get(type)); + public bool IsComponentTypeDeclared(int componentTypeID) + { + if(componentTypeID >= 0 && componentTypeID < _pools.Length) + { + return _pools[componentTypeID] != _nullPool; + } + return false; + } public Type GetComponentType(int componentID) => _pools[componentID].ComponentType; #endregion diff --git a/src/EcsWorld.static.cs b/src/EcsWorld.static.cs index dd52fea..0970229 100644 --- a/src/EcsWorld.static.cs +++ b/src/EcsWorld.static.cs @@ -81,9 +81,7 @@ namespace DCFApixels.DragonECS if (_mapping.Length < Worlds.Length) { Array.Resize(ref _mapping, Worlds.Length); - } - ref short itemIndex = ref _mapping[worldID]; if (itemIndex <= 0) { From 266da2d85d88a767afb9d48abc0d097ff0f808c0 Mon Sep 17 00:00:00 2001 From: Mikhail <99481254+DCFApixels@users.noreply.github.com> Date: Thu, 11 Jan 2024 00:53:15 +0800 Subject: [PATCH 02/16] fix --- src/DataInterfaces.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/DataInterfaces.cs b/src/DataInterfaces.cs index 260f507..6fb0316 100644 --- a/src/DataInterfaces.cs +++ b/src/DataInterfaces.cs @@ -12,7 +12,8 @@ namespace DCFApixels.DragonECS.Internal public static void CheckFakeInstanceValide(T fakeInstnace) { #if DEBUG - if (fakeInstnace.Equals(default) == false) + T nil = default; + if (fakeInstnace.Equals(nil) == false) { throw new Exception("Не правильное применение интерфейса, менять нужно передаваемое по ref значение"); } From 21ee6aee00a945c7e4466ea413b1c237a214699e Mon Sep 17 00:00:00 2001 From: Mikhail <99481254+DCFApixels@users.noreply.github.com> Date: Thu, 18 Jan 2024 21:25:26 +0800 Subject: [PATCH 03/16] fix --- src/Debug/EcsDebugUtility.cs | 1 + src/Pools/EcsHybridPool.cs | 16 ++++++++++++---- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/Debug/EcsDebugUtility.cs b/src/Debug/EcsDebugUtility.cs index af4b262..bef2053 100644 --- a/src/Debug/EcsDebugUtility.cs +++ b/src/Debug/EcsDebugUtility.cs @@ -49,6 +49,7 @@ namespace DCFApixels.DragonECS } private static string AutoToString(object target, Type type, bool isWriteName) { + //TODO сделать специальный вывод в виде названий констант для Enum-ов var fields = type.GetFields(RFL_FLAGS); string[] values = new string[fields.Length]; for (int i = 0; i < fields.Length; i++) diff --git a/src/Pools/EcsHybridPool.cs b/src/Pools/EcsHybridPool.cs index 7c40337..2009d88 100644 --- a/src/Pools/EcsHybridPool.cs +++ b/src/Pools/EcsHybridPool.cs @@ -71,16 +71,18 @@ namespace DCFApixels.DragonECS _mediator.RegisterComponent(entityID, _componentTypeID, _maskBit); _listeners.InvokeOnAdd(entityID); if (isMain) + { component.OnAddToPool(_source.GetEntityLong(entityID)); + } _items[itemIndex] = component; _entities[itemIndex] = entityID; } public void Add(int entityID, T component) { HybridMapping mapping = _source.GetHybridMapping(component.GetType()); - mapping.GetTargetTypePool().AddRefInternal(entityID, component, false); + mapping.GetTargetTypePool().AddRefInternal(entityID, component, true); foreach (var pool in mapping.GetPools()) - pool.AddRefInternal(entityID, component, true); + pool.AddRefInternal(entityID, component, false); } public void Set(int entityID, T component) { @@ -122,9 +124,13 @@ namespace DCFApixels.DragonECS ref int itemIndex = ref _mapping[entityID]; T component = _items[itemIndex]; if (isMain) + { component.OnDelFromPool(_source.GetEntityLong(entityID)); + } if (_recycledItemsCount >= _recycledItems.Length) + { Array.Resize(ref _recycledItems, _recycledItems.Length << 1); + } _recycledItems[_recycledItemsCount++] = itemIndex; _mapping[entityID] = 0; _entities[itemIndex] = 0; @@ -136,9 +142,11 @@ namespace DCFApixels.DragonECS { var component = Get(entityID); HybridMapping mapping = _source.GetHybridMapping(component.GetType()); - mapping.GetTargetTypePool().DelInternal(entityID, false); + mapping.GetTargetTypePool().DelInternal(entityID, true); foreach (var pool in mapping.GetPools()) - pool.DelInternal(entityID, true); + { + pool.DelInternal(entityID, false); + } } public void TryDel(int entityID) { From 294a3af4ac03f7ca596518e7f37fd016adae9aa1 Mon Sep 17 00:00:00 2001 From: Mikhail <99481254+DCFApixels@users.noreply.github.com> Date: Thu, 25 Jan 2024 20:11:06 +0800 Subject: [PATCH 04/16] rework data interfaces --- src/DataInterfaces.cs | 82 +++++-------------------------------------- 1 file changed, 9 insertions(+), 73 deletions(-) diff --git a/src/DataInterfaces.cs b/src/DataInterfaces.cs index 6fb0316..4fed4d3 100644 --- a/src/DataInterfaces.cs +++ b/src/DataInterfaces.cs @@ -1,27 +1,5 @@ -using System; -using System.Linq; using System.Runtime.CompilerServices; -using static DCFApixels.DragonECS.Internal.DataInterfaceHalper; -namespace DCFApixels.DragonECS.Internal -{ - #region DataInterfaceHalper - public static class DataInterfaceHalper - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void CheckFakeInstanceValide(T fakeInstnace) - { -#if DEBUG - T nil = default; - if (fakeInstnace.Equals(nil) == false) - { - throw new Exception("Не правильное применение интерфейса, менять нужно передаваемое по ref значение"); - } -#endif - } - } - #endregion -} namespace DCFApixels.DragonECS { #region IEcsWorldComponent @@ -36,11 +14,10 @@ namespace DCFApixels.DragonECS public static readonly bool isHasHandler; static EcsWorldComponentHandler() { - Type targetType = typeof(T); - isHasHandler = targetType.GetInterfaces().Contains(typeof(IEcsWorldComponent<>).MakeGenericType(targetType)); - if (isHasHandler) + T def = default; + if (def is IEcsWorldComponent intrf) { - instance = (IEcsWorldComponent)Activator.CreateInstance(typeof(WorldComponentHandler<>).MakeGenericType(targetType)); + instance = intrf; } else { @@ -54,23 +31,6 @@ namespace DCFApixels.DragonECS public void OnDestroy(ref T component, EcsWorld world) { } } } - internal sealed class WorldComponentHandler : IEcsWorldComponent - where T : struct, IEcsWorldComponent - { - private T _fakeInstnace = default; - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Init(ref T component, EcsWorld world) - { - _fakeInstnace.Init(ref component, world); - CheckFakeInstanceValide(_fakeInstnace); - } - public void OnDestroy(ref T component, EcsWorld world) - { - _fakeInstnace.OnDestroy(ref component, world); - CheckFakeInstanceValide(_fakeInstnace); - } - - } #endregion #region IEcsComponentReset @@ -84,11 +44,10 @@ namespace DCFApixels.DragonECS public static readonly bool isHasHandler; static EcsComponentResetHandler() { - Type targetType = typeof(T); - isHasHandler = targetType.GetInterfaces().Contains(typeof(IEcsComponentReset<>).MakeGenericType(targetType)); - if (isHasHandler) + T def = default; + if (def is IEcsComponentReset intrf) { - instance = (IEcsComponentReset)Activator.CreateInstance(typeof(ComponentResetHandler<>).MakeGenericType(targetType)); + instance = intrf; } else { @@ -101,17 +60,6 @@ namespace DCFApixels.DragonECS public void Reset(ref T component) => component = default; } } - internal sealed class ComponentResetHandler : IEcsComponentReset - where T : IEcsComponentReset - { - private T _fakeInstnace = default; - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Reset(ref T component) - { - _fakeInstnace.Reset(ref component); - CheckFakeInstanceValide(_fakeInstnace); - } - } #endregion #region IEcsComponentCopy @@ -125,11 +73,10 @@ namespace DCFApixels.DragonECS public static readonly bool isHasHandler; static EcsComponentCopyHandler() { - Type targetType = typeof(T); - isHasHandler = targetType.GetInterfaces().Contains(typeof(IEcsComponentCopy<>).MakeGenericType(targetType)); - if (isHasHandler) + T def = default; + if(def is IEcsComponentCopy intrf) { - instance = (IEcsComponentCopy)Activator.CreateInstance(typeof(ComponentCopyHandler<>).MakeGenericType(targetType)); + instance = intrf; } else { @@ -142,16 +89,5 @@ namespace DCFApixels.DragonECS public void Copy(ref T from, ref T to) => to = from; } } - internal sealed class ComponentCopyHandler : IEcsComponentCopy - where T : IEcsComponentCopy - { - private T _fakeInstnace = default; - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Copy(ref T from, ref T to) - { - _fakeInstnace.Copy(ref from, ref to); - CheckFakeInstanceValide(_fakeInstnace); - } - } #endregion } From 5760dd55d05da4dbcfbf9ba7818b8979b3862834 Mon Sep 17 00:00:00 2001 From: Mikhail <99481254+DCFApixels@users.noreply.github.com> Date: Thu, 25 Jan 2024 20:11:28 +0800 Subject: [PATCH 05/16] disable CS8981 in longent --- src/entlong.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/entlong.cs b/src/entlong.cs index 8ccdfd8..8b2a4d3 100644 --- a/src/entlong.cs +++ b/src/entlong.cs @@ -1,4 +1,5 @@ #pragma warning disable IDE1006 +#pragma warning disable CS8981 using DCFApixels.DragonECS.Internal; using System; using System.Collections.Generic; From 36d5c15817dd4c16cf9242b8b35e40d16bf9cbff Mon Sep 17 00:00:00 2001 From: Mikhail <99481254+DCFApixels@users.noreply.github.com> Date: Fri, 26 Jan 2024 02:26:17 +0800 Subject: [PATCH 06/16] add IInjectionBlock --- src/Builtin/InjectSystem.cs | 63 ++++++++++++++++++++++++++----------- src/EcsPipeline.cs | 7 ++++- src/EcsRunner.cs | 13 +++++--- 3 files changed, 60 insertions(+), 23 deletions(-) diff --git a/src/Builtin/InjectSystem.cs b/src/Builtin/InjectSystem.cs index b9ab4e1..2fe8a5e 100644 --- a/src/Builtin/InjectSystem.cs +++ b/src/Builtin/InjectSystem.cs @@ -5,6 +5,23 @@ using System.Linq; namespace DCFApixels.DragonECS { + public readonly struct Injector + { + private readonly EcsPipeline _pipeline; + public Injector(EcsPipeline pipeline) + { + _pipeline = pipeline; + } + public void Inject(T data) + { + _pipeline.Inject(data); + } + } + public interface IInjectionBlock + { + void InjectTo(Injector i); + } + [MetaName(nameof(PreInject))] [BindWithEcsRunner(typeof(EcsPreInjectRunner))] public interface IEcsPreInject : IEcsProcess @@ -56,7 +73,14 @@ namespace DCFApixels.DragonECS { void IEcsPreInject.PreInject(object obj) { - foreach (var item in targets) item.PreInject(obj); + if (obj is IInjectionBlock container) + { + container.InjectTo(new Injector(Pipeline)); + } + foreach (var item in targets) + { + item.PreInject(obj); + } } } [MetaTags(MetaTags.HIDDEN)] @@ -74,9 +98,9 @@ namespace DCFApixels.DragonECS { Type baseType = typeof(T).BaseType; if (baseType != typeof(object) && baseType != typeof(ValueType) && baseType != null) - _baseTypeInjectRunner = (EcsBaseTypeInjectRunner)Activator.CreateInstance(typeof(EcsBaseTypeInjectRunner<>).MakeGenericType(baseType), Source); + _baseTypeInjectRunner = (EcsBaseTypeInjectRunner)Activator.CreateInstance(typeof(EcsBaseTypeInjectRunner<>).MakeGenericType(baseType), Pipeline); else - _baseTypeInjectRunner = new EcsObjectTypePreInjectRunner(Source); + _baseTypeInjectRunner = new EcsObjectTypePreInjectRunner(Pipeline); } } internal abstract class EcsBaseTypeInjectRunner @@ -155,7 +179,10 @@ namespace DCFApixels.DragonECS public static partial class EcsPipelineExtensions { - public static void Inject(EcsPipeline self, T data) => self.GetRunner>().Inject(data); + public static void Inject(this EcsPipeline self, T data) + { + self.GetRunner>().Inject(data); + } } public static partial class EcsPipelineBuilderExtensions { @@ -167,33 +194,33 @@ namespace DCFApixels.DragonECS self.AddModule(module); return self; } - public static EcsPipeline.Builder Inject(this EcsPipeline.Builder self, A a, B b) + public static EcsPipeline.Builder Inject(this EcsPipeline.Builder self, T0 d0, T1 d1) { - return self.Inject(a).Inject(b); + return self.Inject(d0).Inject(d1); } - public static EcsPipeline.Builder Inject(this EcsPipeline.Builder self, A a, B b, C c) + public static EcsPipeline.Builder Inject(this EcsPipeline.Builder self, T0 d0, T1 d1, T2 d2) { - return self.Inject(a).Inject(b).Inject(c); + return self.Inject(d0).Inject(d1).Inject(d2); } - public static EcsPipeline.Builder Inject(this EcsPipeline.Builder self, A a, B b, C c, D d) + public static EcsPipeline.Builder Inject(this EcsPipeline.Builder self, T0 d0, T1 d1, T2 d2, T3 d3) { - return self.Inject(a).Inject(b).Inject(c).Inject(d); + return self.Inject(d0).Inject(d1).Inject(d2).Inject(d3); } - public static EcsPipeline.Builder Inject(this EcsPipeline.Builder self, A a, B b, C c, D d, E e) + public static EcsPipeline.Builder Inject(this EcsPipeline.Builder self, T0 d0, T1 d1, T2 d2, T3 d3, T4 d4) { - return self.Inject(a).Inject(b).Inject(c).Inject(d).Inject(e); + return self.Inject(d0).Inject(d1).Inject(d2).Inject(d3).Inject(d4); } - public static EcsPipeline.Builder Inject(this EcsPipeline.Builder self, A a, B b, C c, D d, E e, F f) + public static EcsPipeline.Builder Inject(this EcsPipeline.Builder self, T0 d0, T1 d1, T2 d2, T3 d3, T4 d4, T5 f) { - return self.Inject(a).Inject(b).Inject(c).Inject(d).Inject(e).Inject(f); + return self.Inject(d0).Inject(d1).Inject(d2).Inject(d3).Inject(d4).Inject(f); } - public static EcsPipeline.Builder Inject(this EcsPipeline.Builder self, A a, B b, C c, D d, E e, F f, G g) + public static EcsPipeline.Builder Inject(this EcsPipeline.Builder self, T0 d0, T1 d1, T2 d2, T3 d3, T4 d4, T5 f, T6 d6) { - return self.Inject(a).Inject(b).Inject(c).Inject(d).Inject(e).Inject(f).Inject(g); + return self.Inject(d0).Inject(d1).Inject(d2).Inject(d3).Inject(d4).Inject(f).Inject(d6); } - public static EcsPipeline.Builder Inject(this EcsPipeline.Builder self, A a, B b, C c, D d, E e, F f, G g, H h) + public static EcsPipeline.Builder Inject(this EcsPipeline.Builder self, T0 d0, T1 d1, T2 d2, T3 d3, T4 d4, T5 f, T6 d6, T7 d7) { - return self.Inject(a).Inject(b).Inject(c).Inject(d).Inject(e).Inject(f).Inject(g).Inject(h); + return self.Inject(d0).Inject(d1).Inject(d2).Inject(d3).Inject(d4).Inject(f).Inject(d6).Inject(d7); } } } diff --git a/src/EcsPipeline.cs b/src/EcsPipeline.cs index b77cccc..98ea570 100644 --- a/src/EcsPipeline.cs +++ b/src/EcsPipeline.cs @@ -38,16 +38,21 @@ namespace DCFApixels.DragonECS #endregion #region Runners + public T[] GetSystems() where T : IEcsProcess + { + return _allSystems.Where(o => o is T).Select(o => (T)o).ToArray(); + } public T GetRunner() where T : IEcsProcess { Type type = typeof(T); if (_runners.TryGetValue(type, out IEcsRunner result)) + { return (T)result; + } result = (IEcsRunner)EcsRunner.Instantiate(this); _runners.Add(type, result); return (T)result; } - internal void OnRunnerDestroy(IEcsRunner runner) { _runners.Remove(runner.Interface); diff --git a/src/EcsRunner.cs b/src/EcsRunner.cs index 46bdd3f..9a0dd8c 100644 --- a/src/EcsRunner.cs +++ b/src/EcsRunner.cs @@ -54,9 +54,9 @@ namespace DCFApixels.DragonECS { public interface IEcsRunner { - EcsPipeline Source { get; } + EcsPipeline Pipeline { get; } Type Interface { get; } - IList Targets { get; } + IList TargetsRaw { get; } object Filter { get; } bool IsHasFilter { get; } bool IsDestroyed { get; } @@ -203,9 +203,10 @@ namespace DCFApixels.DragonECS private bool _isDestroyed; #region Properties - public EcsPipeline Source => _source; + public EcsPipeline Pipeline => _source; public Type Interface => typeof(TInterface); - public IList Targets => _targetsSealed; + public IList TargetsRaw => _targetsSealed; + public ReadOnlySpan Targets => targets; public object Filter => _filter; public bool IsHasFilter => _isHasFilter; public bool IsDestroyed => _isDestroyed; @@ -225,9 +226,13 @@ namespace DCFApixels.DragonECS internal void Rebuild() { if (_isHasFilter) + { Set(_source, FilterSystems(_source.AllSystems), _isHasFilter, _filter); + } else + { Set(_source, FilterSystems(_source.AllSystems, _filter), _isHasFilter, _filter); + } } public void Destroy() { From 9ae92c7cdf5ea06d3fe70a14a430a58267e71c8d Mon Sep 17 00:00:00 2001 From: Mikhail <99481254+DCFApixels@users.noreply.github.com> Date: Fri, 26 Jan 2024 18:58:54 +0800 Subject: [PATCH 07/16] add Deconstruct to entlong --- src/entlong.cs | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/entlong.cs b/src/entlong.cs index 8b2a4d3..af2c556 100644 --- a/src/entlong.cs +++ b/src/entlong.cs @@ -155,9 +155,27 @@ namespace DCFApixels.DragonECS [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator entlong(long a) => new entlong(a); - [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator int(entlong a) => a.ID; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Deconstruct(out int id, out int gen, out int world) + { +#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS + if (!IsAlive) Throw.Ent_ThrowIsNotAlive(this); +#endif + id = this.id; + gen = this.gen; + world = this.world; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Deconstruct(out int id, out int world) + { +#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS + if (!IsAlive) Throw.Ent_ThrowIsNotAlive(this); +#endif + id = this.id; + world = this.world; + } #endregion #region Other From 0356302d9085e5d69928153bff66c457faf75e4c Mon Sep 17 00:00:00 2001 From: Mikhail <99481254+DCFApixels@users.noreply.github.com> Date: Fri, 26 Jan 2024 18:59:07 +0800 Subject: [PATCH 08/16] Update Exceptions.cs --- src/Utils/Exceptions.cs | 143 ++++++++++++++++++++-------------------- 1 file changed, 72 insertions(+), 71 deletions(-) diff --git a/src/Utils/Exceptions.cs b/src/Utils/Exceptions.cs index ed4e955..b883552 100644 --- a/src/Utils/Exceptions.cs +++ b/src/Utils/Exceptions.cs @@ -2,89 +2,90 @@ using System.Runtime.CompilerServices; using System.Runtime.Serialization; -namespace DCFApixels.DragonECS + +namespace DCFApixels.DragonECS.Internal { - namespace Internal + internal static class Throw { - internal static class Throw + [MethodImpl(MethodImplOptions.NoInlining)] + internal static void ArgumentNull() { - [MethodImpl(MethodImplOptions.NoInlining)] - internal static void ArgumentNull() - { - throw new ArgumentNullException(); - } + throw new ArgumentNullException(); + } - [MethodImpl(MethodImplOptions.NoInlining)] - internal static void ConstraintIsAlreadyContainedInMask(Type type) - { - throw new EcsFrameworkException($"The {EcsDebugUtility.GetGenericTypeName(type)} constraint is already contained in the mask."); - } + [MethodImpl(MethodImplOptions.NoInlining)] + internal static void ConstraintIsAlreadyContainedInMask(Type type) + { + throw new EcsFrameworkException($"The {EcsDebugUtility.GetGenericTypeName(type)} constraint is already contained in the mask."); + } - //[MethodImpl(MethodImplOptions.NoInlining)] - //public static void ArgumentDifferentWorldsException() - //{ - // throw new ArgumentException("The groups belong to different worlds."); - //} - [MethodImpl(MethodImplOptions.NoInlining)] - internal static void ArgumentOutOfRange() - { - throw new ArgumentOutOfRangeException($"index is less than 0 or is equal to or greater than Count."); - } + //[MethodImpl(MethodImplOptions.NoInlining)] + //public static void ArgumentDifferentWorldsException() + //{ + // throw new ArgumentException("The groups belong to different worlds."); + //} + [MethodImpl(MethodImplOptions.NoInlining)] + internal static void ArgumentOutOfRange() + { + throw new ArgumentOutOfRangeException($"index is less than 0 or is equal to or greater than Count."); + } - [MethodImpl(MethodImplOptions.NoInlining)] - internal static void Group_AlreadyContains(int entityID) - { - throw new EcsFrameworkException($"This group already contains entity {entityID}."); - } - [MethodImpl(MethodImplOptions.NoInlining)] - internal static void Group_DoesNotContain(int entityID) - { - throw new EcsFrameworkException($"This group does not contain entity {entityID}."); - } - [MethodImpl(MethodImplOptions.NoInlining)] - internal static void Group_ArgumentDifferentWorldsException() - { - throw new ArgumentException("The groups belong to different worlds."); - } + [MethodImpl(MethodImplOptions.NoInlining)] + internal static void Group_AlreadyContains(int entityID) + { + throw new EcsFrameworkException($"This group already contains entity {entityID}."); + } + [MethodImpl(MethodImplOptions.NoInlining)] + internal static void Group_DoesNotContain(int entityID) + { + throw new EcsFrameworkException($"This group does not contain entity {entityID}."); + } + [MethodImpl(MethodImplOptions.NoInlining)] + internal static void Group_ArgumentDifferentWorldsException() + { + throw new ArgumentException("The groups belong to different worlds."); + } - [MethodImpl(MethodImplOptions.NoInlining)] - internal static void Pipeline_MethodCalledAfterInitialisation(string methodName) - { - throw new MethodAccessException($"It is forbidden to call {methodName}, after initialization {nameof(EcsPipeline)}."); - } - [MethodImpl(MethodImplOptions.NoInlining)] - internal static void Pipeline_MethodCalledBeforeInitialisation(string methodName) - { - throw new MethodAccessException($"It is forbidden to call {methodName}, before initialization {nameof(EcsPipeline)}."); - } - [MethodImpl(MethodImplOptions.NoInlining)] - internal static void Pipeline_MethodCalledAfterDestruction(string methodName) - { - throw new MethodAccessException($"It is forbidden to call {methodName}, after destroying {nameof(EcsPipeline)}."); - } + [MethodImpl(MethodImplOptions.NoInlining)] + internal static void Pipeline_MethodCalledAfterInitialisation(string methodName) + { + throw new MethodAccessException($"It is forbidden to call {methodName}, after initialization {nameof(EcsPipeline)}."); + } + [MethodImpl(MethodImplOptions.NoInlining)] + internal static void Pipeline_MethodCalledBeforeInitialisation(string methodName) + { + throw new MethodAccessException($"It is forbidden to call {methodName}, before initialization {nameof(EcsPipeline)}."); + } + [MethodImpl(MethodImplOptions.NoInlining)] + internal static void Pipeline_MethodCalledAfterDestruction(string methodName) + { + throw new MethodAccessException($"It is forbidden to call {methodName}, after destroying {nameof(EcsPipeline)}."); + } - [MethodImpl(MethodImplOptions.NoInlining)] - internal static void World_InvalidIncrementComponentsBalance() - { - throw new MethodAccessException("Invalid increment components balance."); - } - [MethodImpl(MethodImplOptions.NoInlining)] - internal static void World_GroupDoesNotBelongWorld() - { - throw new MethodAccessException("The Group does not belong in this world."); - } + [MethodImpl(MethodImplOptions.NoInlining)] + internal static void World_InvalidIncrementComponentsBalance() + { + throw new MethodAccessException("Invalid increment components balance."); + } + [MethodImpl(MethodImplOptions.NoInlining)] + internal static void World_GroupDoesNotBelongWorld() + { + throw new MethodAccessException("The Group does not belong in this world."); + } - [MethodImpl(MethodImplOptions.NoInlining)] - internal static void Ent_ThrowIsNotAlive(entlong entity) - { - if (entity.IsNull) - throw new EcsFrameworkException($"The {entity} is null."); - else - throw new EcsFrameworkException($"The {entity} is not alive."); - } + [MethodImpl(MethodImplOptions.NoInlining)] + internal static void Ent_ThrowIsNotAlive(entlong entity) + { + if (entity.IsNull) + throw new EcsFrameworkException($"The {entity} is null."); + else + throw new EcsFrameworkException($"The {entity} is not alive."); } } +} +namespace DCFApixels.DragonECS +{ [Serializable] public class EcsFrameworkException : Exception { From 5fac3fd97cfa8cc6fb45fac7dd52cd0d2859f9b8 Mon Sep 17 00:00:00 2001 From: Mikhail <99481254+DCFApixels@users.noreply.github.com> Date: Mon, 29 Jan 2024 01:09:17 +0800 Subject: [PATCH 09/16] simple renaming & refactoring --- src/Collections/EcsGroup.cs | 27 ++++++++++++++------------- src/EcsWorld.static.cs | 3 ++- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/Collections/EcsGroup.cs b/src/Collections/EcsGroup.cs index 2909f45..3a7848d 100644 --- a/src/Collections/EcsGroup.cs +++ b/src/Collections/EcsGroup.cs @@ -29,7 +29,7 @@ namespace DCFApixels.DragonECS public int WorldID { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => _source.World.id; + get => _source.WorldID; } public EcsWorld World { @@ -106,17 +106,18 @@ namespace DCFApixels.DragonECS [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool IsSubsetOf(EcsReadonlyGroup group) => _source.IsSubsetOf(group._source); + [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool IsSubsetOf(EcsGroup group) => _source.IsSubsetOf(group); [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool IsSupersetOf(EcsReadonlyGroup group) => _source.IsSupersetOf(group._source); + [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool IsSupersetOf(EcsGroup group) => _source.IsSupersetOf(group); #endregion #region Internal [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal EcsGroup GetGroupInternal() => _source; - + internal EcsGroup GetSource_Internal() => _source; #endregion #region Other @@ -293,7 +294,7 @@ namespace DCFApixels.DragonECS #region CopyFrom/Clone/Bake/ToSpan [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void CopyFrom(EcsReadonlyGroup group) => CopyFrom(group.GetGroupInternal()); + public void CopyFrom(EcsReadonlyGroup group) => CopyFrom(group.GetSource_Internal()); public void CopyFrom(EcsGroup group) { #if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS @@ -347,7 +348,7 @@ namespace DCFApixels.DragonECS #region UnionWith /// as Union sets [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void UnionWith(EcsReadonlyGroup group) => UnionWith(group.GetGroupInternal()); + public void UnionWith(EcsReadonlyGroup group) => UnionWith(group.GetSource_Internal()); /// as Union sets public void UnionWith(EcsGroup group) { @@ -374,7 +375,7 @@ namespace DCFApixels.DragonECS #region ExceptWith /// as Except sets [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ExceptWith(EcsReadonlyGroup group) => ExceptWith(group.GetGroupInternal()); + public void ExceptWith(EcsReadonlyGroup group) => ExceptWith(group.GetSource_Internal()); /// as Except sets public void ExceptWith(EcsGroup group) { @@ -432,7 +433,7 @@ namespace DCFApixels.DragonECS #region IntersectWith /// as Intersect sets [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void IntersectWith(EcsReadonlyGroup group) => IntersectWith(group.GetGroupInternal()); + public void IntersectWith(EcsReadonlyGroup group) => IntersectWith(group.GetSource_Internal()); /// as Intersect sets public void IntersectWith(EcsGroup group) { @@ -451,7 +452,7 @@ namespace DCFApixels.DragonECS #region SymmetricExceptWith /// as Symmetric Except sets [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void SymmetricExceptWith(EcsReadonlyGroup group) => SymmetricExceptWith(group.GetGroupInternal()); + public void SymmetricExceptWith(EcsReadonlyGroup group) => SymmetricExceptWith(group.GetSource_Internal()); /// as Symmetric Except sets public void SymmetricExceptWith(EcsGroup group) { @@ -479,7 +480,7 @@ namespace DCFApixels.DragonECS #region SetEquals [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool SetEquals(EcsReadonlyGroup group) => SetEquals(group.GetGroupInternal()); + public bool SetEquals(EcsReadonlyGroup group) => SetEquals(group.GetSource_Internal()); public bool SetEquals(EcsGroup group) { #if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS @@ -508,7 +509,7 @@ namespace DCFApixels.DragonECS #region Overlaps [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Overlaps(EcsReadonlyGroup group) => Overlaps(group.GetGroupInternal()); + public bool Overlaps(EcsReadonlyGroup group) => Overlaps(group.GetSource_Internal()); public bool Overlaps(EcsGroup group) { #if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS @@ -542,7 +543,7 @@ namespace DCFApixels.DragonECS #region IsSubsetOf [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool IsSubsetOf(EcsReadonlyGroup group) => IsSubsetOf(group.GetGroupInternal()); + public bool IsSubsetOf(EcsReadonlyGroup group) => IsSubsetOf(group.GetSource_Internal()); public bool IsSubsetOf(EcsGroup group) { #if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS @@ -559,7 +560,7 @@ namespace DCFApixels.DragonECS #region IsSupersetOf [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool IsSupersetOf(EcsReadonlyGroup group) => IsSupersetOf(group.GetGroupInternal()); + public bool IsSupersetOf(EcsReadonlyGroup group) => IsSupersetOf(group.GetSource_Internal()); public bool IsSupersetOf(EcsGroup group) { #if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS @@ -764,7 +765,7 @@ namespace DCFApixels.DragonECS public int CapacitySparce => _group.CapacitySparce; public override string ToString() => _group.ToString(); public DebuggerProxy(EcsGroup group) => _group = group; - public DebuggerProxy(EcsReadonlyGroup group) : this(group.GetGroupInternal()) { } + public DebuggerProxy(EcsReadonlyGroup group) : this(group.GetSource_Internal()) { } } #endregion } diff --git a/src/EcsWorld.static.cs b/src/EcsWorld.static.cs index 0970229..af03e07 100644 --- a/src/EcsWorld.static.cs +++ b/src/EcsWorld.static.cs @@ -25,6 +25,7 @@ namespace DCFApixels.DragonECS private static IdDispenser _worldIdDispenser = new IdDispenser(0); private static List _dataReleaseres = new List(); + //public static int Copacity => Worlds.Length; static EcsWorld() { @@ -41,7 +42,7 @@ namespace DCFApixels.DragonECS [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ref T GetData(int worldID) => ref WorldComponentPool.GetForWorld(worldID); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ref T UncheckedGetData(int worldID) => ref WorldComponentPool.GetForWorldUnchecked(worldID); + public static ref T GetDataUnchecked(int worldID) => ref WorldComponentPool.GetForWorldUnchecked(worldID); private abstract class DataReleaser { From ff6d8cba5ada407de020f0a34d829ff7d6eb8645 Mon Sep 17 00:00:00 2001 From: Mikhail <99481254+DCFApixels@users.noreply.github.com> Date: Mon, 29 Jan 2024 01:10:05 +0800 Subject: [PATCH 10/16] update profile markers for DefaultDebugService --- src/Debug/EcsDebug.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Debug/EcsDebug.cs b/src/Debug/EcsDebug.cs index de0dba5..bb7bbef 100644 --- a/src/Debug/EcsDebug.cs +++ b/src/Debug/EcsDebug.cs @@ -176,7 +176,11 @@ namespace DCFApixels.DragonECS } public override void ProfilerMarkBegin(int id) { + var color = Console.ForegroundColor; + Console.ForegroundColor = ConsoleColor.DarkGray; _stopwatchs[id].Start(); + Print("ProfilerMark", $"{_stopwatchsNames[id]} start <"); + Console.ForegroundColor = color; } public override void ProfilerMarkEnd(int id) { @@ -185,7 +189,7 @@ namespace DCFApixels.DragonECS _stopwatchs[id].Stop(); var time = _stopwatchs[id].Elapsed; _stopwatchs[id].Reset(); - Print("ProfilerMark", _stopwatchsNames[id] + " s:" + time.TotalSeconds); + Print("ProfilerMark", $"> {_stopwatchsNames[id]} s:{time.TotalSeconds}"); Console.ForegroundColor = color; } protected override void OnDelProfilerMark(int id) From df24a2d26a7c0a7726a0f44c2da49c00c8051d8b Mon Sep 17 00:00:00 2001 From: Mikhail <99481254+DCFApixels@users.noreply.github.com> Date: Mon, 29 Jan 2024 01:10:52 +0800 Subject: [PATCH 11/16] update auto release del buffer & refactoring --- src/EcsWorld.cs | 76 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 57 insertions(+), 19 deletions(-) diff --git a/src/EcsWorld.cs b/src/EcsWorld.cs index 137665c..4bc4059 100644 --- a/src/EcsWorld.cs +++ b/src/EcsWorld.cs @@ -23,7 +23,7 @@ namespace DCFApixels.DragonECS private int _delEntBufferCount; private int _delEntBufferMinCount; private int _freeSpace; - private bool _isEnableReleaseDelEntBuffer = true; + private bool _isEnableAutoReleaseDelEntBuffer = true; private List> _groups = new List>(); private Stack _groupsPool = new Stack(64); @@ -36,15 +36,51 @@ namespace DCFApixels.DragonECS private readonly PoolsMediator _poolsMediator; #region Properties - public bool IsDestroyed => _isDestroyed; - public int Count => _entitiesCount; - public int Capacity => _entitesCapacity; //_denseEntities.Length; + public bool IsDestroyed + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return _isDestroyed; } + } + public int Count + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return _entitiesCount; } + } + public int Capacity + { + //_denseEntities.Length; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return _entitesCapacity; } + } + public int DelEntBufferCount + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return _delEntBufferCount; } + } + public bool IsEnableReleaseDelEntBuffer + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return _isEnableAutoReleaseDelEntBuffer; } + } - public int DelEntBufferCount => _delEntBufferCount; - public bool IsEnableReleaseDelEntBuffer => _isEnableReleaseDelEntBuffer; - - public EcsReadonlyGroup Entities => _allEntites.Readonly; - public ReadOnlySpan AllPools => _pools;// new ReadOnlySpan(pools, 0, _poolsCount); + public EcsReadonlyGroup Entities + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + if (_isEnableAutoReleaseDelEntBuffer) + { + ReleaseDelEntityBufferAll(); + } + return _allEntites.Readonly; + } + } + public ReadOnlySpan AllPools + { + // new ReadOnlySpan(pools, 0, _poolsCount); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return _pools; } + } #endregion #region Constructors/Destroy @@ -60,7 +96,9 @@ namespace DCFApixels.DragonECS { id = (short)_worldIdDispenser.UseFree(); if (id >= Worlds.Length) + { Array.Resize(ref Worlds, Worlds.Length << 1); + } Worlds[id] = this; } @@ -142,7 +180,7 @@ namespace DCFApixels.DragonECS #region Where Query public EcsReadonlyGroup WhereToGroupFor(EcsSpan span, out TAspect aspect) where TAspect : EcsAspect { - if (_isEnableReleaseDelEntBuffer) + if (_isEnableAutoReleaseDelEntBuffer) { ReleaseDelEntityBufferAll(); } @@ -152,7 +190,7 @@ namespace DCFApixels.DragonECS } public EcsReadonlyGroup WhereToGroupFor(EcsSpan span) where TAspect : EcsAspect { - if (_isEnableReleaseDelEntBuffer) + if (_isEnableAutoReleaseDelEntBuffer) { ReleaseDelEntityBufferAll(); } @@ -160,7 +198,7 @@ namespace DCFApixels.DragonECS } public EcsReadonlyGroup WhereToGroup(out TAspect aspect) where TAspect : EcsAspect { - if (_isEnableReleaseDelEntBuffer) + if (_isEnableAutoReleaseDelEntBuffer) { ReleaseDelEntityBufferAll(); } @@ -170,7 +208,7 @@ namespace DCFApixels.DragonECS } public EcsReadonlyGroup WhereToGroup() where TAspect : EcsAspect { - if (_isEnableReleaseDelEntBuffer) + if (_isEnableAutoReleaseDelEntBuffer) { ReleaseDelEntityBufferAll(); } @@ -179,7 +217,7 @@ namespace DCFApixels.DragonECS public EcsSpan WhereFor(EcsSpan span, out TAspect aspect) where TAspect : EcsAspect { - if (_isEnableReleaseDelEntBuffer) + if (_isEnableAutoReleaseDelEntBuffer) { ReleaseDelEntityBufferAll(); } @@ -189,7 +227,7 @@ namespace DCFApixels.DragonECS } public EcsSpan WhereFor(EcsSpan span) where TAspect : EcsAspect { - if (_isEnableReleaseDelEntBuffer) + if (_isEnableAutoReleaseDelEntBuffer) { ReleaseDelEntityBufferAll(); } @@ -197,7 +235,7 @@ namespace DCFApixels.DragonECS } public EcsSpan Where(out TAspect aspect) where TAspect : EcsAspect { - if (_isEnableReleaseDelEntBuffer) + if (_isEnableAutoReleaseDelEntBuffer) { ReleaseDelEntityBufferAll(); } @@ -207,7 +245,7 @@ namespace DCFApixels.DragonECS } public EcsSpan Where() where TAspect : EcsAspect { - if (_isEnableReleaseDelEntBuffer) + if (_isEnableAutoReleaseDelEntBuffer) { ReleaseDelEntityBufferAll(); } @@ -339,12 +377,12 @@ namespace DCFApixels.DragonECS #region DelEntBuffer public AutoReleaseDelEntBufferLonkUnloker DisableAutoReleaseDelEntBuffer() { - _isEnableReleaseDelEntBuffer = false; + _isEnableAutoReleaseDelEntBuffer = false; return new AutoReleaseDelEntBufferLonkUnloker(this); } public void EnableAutoReleaseDelEntBuffer() { - _isEnableReleaseDelEntBuffer = true; + _isEnableAutoReleaseDelEntBuffer = true; } public readonly struct AutoReleaseDelEntBufferLonkUnloker : IDisposable { From a248f4fc347f866780cc78fa1cbc7fbd17da2e64 Mon Sep 17 00:00:00 2001 From: Mikhail <99481254+DCFApixels@users.noreply.github.com> Date: Sat, 3 Feb 2024 01:12:53 +0800 Subject: [PATCH 12/16] add EcsWorldConfig --- src/Builtin/Worlds.cs | 12 +++- src/DataInterfaces.cs | 2 +- src/Debug/EcsDebug.cs | 5 ++ src/EcsWorld.cs | 87 ++++++++++++++++++-------- src/EcsWorld.pools.cs | 2 +- src/EcsWorld.static.cs | 12 ++-- src/EcsWorldConfig.cs | 124 ++++++++++++++++++++++++++++++++++++++ src/Pools/EcsPool.cs | 6 +- src/Utils/Exceptions.cs | 5 ++ src/Utils/IntDispenser.cs | 7 +-- 10 files changed, 218 insertions(+), 44 deletions(-) create mode 100644 src/EcsWorldConfig.cs diff --git a/src/Builtin/Worlds.cs b/src/Builtin/Worlds.cs index 8662512..d98a1db 100644 --- a/src/Builtin/Worlds.cs +++ b/src/Builtin/Worlds.cs @@ -1,5 +1,13 @@ namespace DCFApixels.DragonECS { - public sealed class EcsDefaultWorld : EcsWorld { } - public sealed class EcsEventWorld : EcsWorld { } + public sealed class EcsDefaultWorld : EcsWorld + { + public EcsDefaultWorld() : base(null) { } + public EcsDefaultWorld(IEcsWorldConfig config) : base(config) { } + } + public sealed class EcsEventWorld : EcsWorld + { + public EcsEventWorld() : base(null) { } + public EcsEventWorld(IEcsWorldConfig config) : base(config) { } + } } diff --git a/src/DataInterfaces.cs b/src/DataInterfaces.cs index 4fed4d3..d200d3a 100644 --- a/src/DataInterfaces.cs +++ b/src/DataInterfaces.cs @@ -74,7 +74,7 @@ namespace DCFApixels.DragonECS static EcsComponentCopyHandler() { T def = default; - if(def is IEcsComponentCopy intrf) + if (def is IEcsComponentCopy intrf) { instance = intrf; } diff --git a/src/Debug/EcsDebug.cs b/src/Debug/EcsDebug.cs index bb7bbef..279404f 100644 --- a/src/Debug/EcsDebug.cs +++ b/src/Debug/EcsDebug.cs @@ -41,6 +41,11 @@ namespace DCFApixels.DragonECS [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void PrintWarning(object v) => Print(EcsConsts.DEBUG_WARNING_TAG, v); public static void PrintError(object v) => Print(EcsConsts.DEBUG_ERROR_TAG, v); + public static void PrintErrorAndBreak(object v) + { + Print(EcsConsts.DEBUG_ERROR_TAG, v); + Break(); + } public static void PrintPass(object v) => Print(EcsConsts.DEBUG_PASS_TAG, v); public static void Print() { diff --git a/src/EcsWorld.cs b/src/EcsWorld.cs index 4bc4059..572c208 100644 --- a/src/EcsWorld.cs +++ b/src/EcsWorld.cs @@ -3,12 +3,14 @@ using DCFApixels.DragonECS.Utils; using System; using System.Collections.Generic; using System.Runtime.CompilerServices; +using static Leopotam.EcsLite.EcsWorld; namespace DCFApixels.DragonECS { public abstract partial class EcsWorld { public readonly short id; + private IEcsWorldConfig _config; private bool _isDestroyed; @@ -36,6 +38,11 @@ namespace DCFApixels.DragonECS private readonly PoolsMediator _poolsMediator; #region Properties + public IEcsWorldConfig Config + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return _config; } + } public bool IsDestroyed { [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -63,7 +70,7 @@ namespace DCFApixels.DragonECS get { return _isEnableAutoReleaseDelEntBuffer; } } - public EcsReadonlyGroup Entities + public EcsReadonlyGroup Entities { [MethodImpl(MethodImplOptions.AggressiveInlining)] get @@ -84,13 +91,15 @@ namespace DCFApixels.DragonECS #endregion #region Constructors/Destroy - public EcsWorld() : this(true) { } - internal EcsWorld(bool isIndexable) + public EcsWorld(IEcsWorldConfig config) : this(config, true) { } + private EcsWorld(IEcsWorldConfig config, bool isIndexable) { - const int POOLS_CAPACITY = 512; - _poolsMediator = new PoolsMediator(this); - - _entitesCapacity = 512; + if (config == null) + { + config = EmptyConfig.Instance; + } + config.Lock(); + _config = config; if (isIndexable) { @@ -102,13 +111,15 @@ namespace DCFApixels.DragonECS Worlds[id] = this; } + _poolsMediator = new PoolsMediator(this); _entityDispenser = new IntDispenser(0); - _pools = new IEcsPoolImplementation[POOLS_CAPACITY]; - _poolComponentCounts = new int[POOLS_CAPACITY]; - //_sortedPoolIds = new int[POOLS_CAPACITY]; - //_sortedPoolIdsMapping = new int[POOLS_CAPACITY]; + + int poolsCapacity = config.Get_PoolsCapacity(); + _pools = new IEcsPoolImplementation[poolsCapacity]; + _poolComponentCounts = new int[poolsCapacity]; ArrayUtility.Fill(_pools, _nullPool); + _entitesCapacity = config.Get_EntitiesCapacity(); _gens = new short[_entitesCapacity]; _componentCounts = new short[_entitesCapacity]; @@ -116,9 +127,11 @@ namespace DCFApixels.DragonECS _delEntBufferCount = 0; _delEntBuffer = new int[_entitesCapacity]; _entitiesComponentMasks = new int[_entitesCapacity][]; + + int maskLength = _pools.Length / 32 + 1; for (int i = 0; i < _entitesCapacity; i++) { - _entitiesComponentMasks[i] = new int[_pools.Length / 32 + 1]; + _entitiesComponentMasks[i] = new int[maskLength]; } _delEntBufferMinCount = Math.Max(_delEntBuffer.Length >> DEL_ENT_BUFFER_SIZE_OFFSET, DEL_ENT_BUFFER_MIN_SIZE); @@ -264,7 +277,9 @@ namespace DCFApixels.DragonECS _entitiesCount++; if (_gens.Length <= entityID) - Upsize(); + { + Upsize(_gens.Length << 1); + } _gens[entityID] &= GEN_BITS; _allEntites.Add(entityID); @@ -432,24 +447,31 @@ namespace DCFApixels.DragonECS #region Upsize [MethodImpl(MethodImplOptions.NoInlining)] - private void Upsize() + public void Upsize(int minSize) { - Array.Resize(ref _gens, _gens.Length << 1); - Array.Resize(ref _componentCounts, _gens.Length); - Array.Resize(ref _delEntBuffer, _gens.Length); - Array.Resize(ref _entitiesComponentMasks, _gens.Length); - for (int i = _entitesCapacity; i < _gens.Length; i++) + if (minSize < Capacity) + { + return; + } + + int newSize = 1 << (BitsUtility.GetHighBitNumber(minSize - 1) + 1); + + Array.Resize(ref _gens, newSize); + Array.Resize(ref _componentCounts, newSize); + Array.Resize(ref _delEntBuffer, newSize); + Array.Resize(ref _entitiesComponentMasks, newSize); + for (int i = _entitesCapacity; i < newSize; i++) _entitiesComponentMasks[i] = new int[_pools.Length / 32 + 1]; _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; + _entitesCapacity = newSize; for (int i = 0; i < _groups.Count; i++) { if (_groups[i].TryGetTarget(out EcsGroup group)) { - group.OnWorldResize(_gens.Length); + group.OnWorldResize(newSize); } else { @@ -459,9 +481,11 @@ namespace DCFApixels.DragonECS } } foreach (var item in _pools) - item.OnWorldResize(_gens.Length); + { + item.OnWorldResize(newSize); + } - _listeners.InvokeOnWorldResize(_gens.Length); + _listeners.InvokeOnWorldResize(newSize); } #endregion @@ -538,6 +562,21 @@ namespace DCFApixels.DragonECS } } #endregion + + #region EmptyConfig + private class EmptyConfig : IEcsWorldConfig + { + public static readonly EmptyConfig Instance = new EmptyConfig(); + private EmptyConfig() { } + public bool IsLocked => true; + public T Get(string valueName) { return default; } + public bool Has(string valueName) { return false; } + public void Lock() { } + public void Remove(string valueName) { } + public void Set(string valueName, T value) { } + public bool TryGet(string valueName, out T value) { value = default; return false; } + } + #endregion } #region Callbacks Interface @@ -589,4 +628,4 @@ namespace DCFApixels.DragonECS public static entlong ToEntityLong(this int self, EcsWorld world) => world.GetEntityLong(self); } #endregion -} +} \ No newline at end of file diff --git a/src/EcsWorld.pools.cs b/src/EcsWorld.pools.cs index a9c371d..c20881f 100644 --- a/src/EcsWorld.pools.cs +++ b/src/EcsWorld.pools.cs @@ -25,7 +25,7 @@ namespace DCFApixels.DragonECS public bool IsComponentTypeDeclared(Type type) => _componentIds.Contains(EcsTypeCode.Get(type)); public bool IsComponentTypeDeclared(int componentTypeID) { - if(componentTypeID >= 0 && componentTypeID < _pools.Length) + if (componentTypeID >= 0 && componentTypeID < _pools.Length) { return _pools[componentTypeID] != _nullPool; } diff --git a/src/EcsWorld.static.cs b/src/EcsWorld.static.cs index af03e07..8803f44 100644 --- a/src/EcsWorld.static.cs +++ b/src/EcsWorld.static.cs @@ -22,14 +22,14 @@ namespace DCFApixels.DragonECS private const int DEL_ENT_BUFFER_MIN_SIZE = 64; private static EcsWorld[] Worlds = new EcsWorld[4]; - private static IdDispenser _worldIdDispenser = new IdDispenser(0); + private static IdDispenser _worldIdDispenser = new IdDispenser(4); private static List _dataReleaseres = new List(); //public static int Copacity => Worlds.Length; static EcsWorld() { - Worlds[0] = new EcsNullWorld(); + Worlds[0] = new NullWorld(); } private static void ReleaseData(int worldID) { @@ -121,9 +121,9 @@ namespace DCFApixels.DragonECS } } } - } - internal sealed class EcsNullWorld : EcsWorld - { - internal EcsNullWorld() : base(false) { } + private sealed class NullWorld : EcsWorld + { + internal NullWorld() : base(EmptyConfig.Instance, false) { } + } } } diff --git a/src/EcsWorldConfig.cs b/src/EcsWorldConfig.cs new file mode 100644 index 0000000..98522b9 --- /dev/null +++ b/src/EcsWorldConfig.cs @@ -0,0 +1,124 @@ +using System; +using System.Collections.Generic; + +namespace DCFApixels.DragonECS +{ + public interface IEcsWorldConfig + { + bool IsLocked { get; } + void Lock(); + void Set(string valueName, T value); + bool Has(string valueName); + T Get(string valueName); + bool TryGet(string valueName, out T value); + void Remove(string valueName); + } + public class EcsWorldConfig : IEcsWorldConfig + { + private Dictionary _storage = new Dictionary(); + private bool _isLocked = false; + public bool IsLocked { get { return _isLocked; } } + public void Lock() + { + _isLocked = true; + } + public T Get(string valueName) + { + return (T)_storage[valueName]; + } + public bool Has(string valueName) + { + return _storage.ContainsKey(valueName); + } + public void Remove(string valueName) + { + _storage.Remove(valueName); + } + public void Set(string valueName, T value) + { + if (_isLocked) + { + throw new InvalidOperationException(); + } + _storage[valueName] = value; + } + public bool TryGet(string valueName, out T value) + { + bool result = _storage.TryGetValue(valueName, out object rawValue); + value = rawValue == null ? default : (T)rawValue; + return result; + } + } + public static class EcsWorldConfigExtensions + { + public static T GetOrDefault(this IEcsWorldConfig self, string valueName, T defaultValue) + { + if (self.TryGet(valueName, out T value)) + { + return value; + } + return defaultValue; + } + + private const string ENTITIES_CAPACITY = nameof(ENTITIES_CAPACITY); + private const int ENTITIES_CAPACITY_DEFAULT = 512; + public static TConfig Set_EntitiesCapacity(this TConfig self, int value) + where TConfig : IEcsWorldConfig + { + self.Set(ENTITIES_CAPACITY, value); + return self; + } + public static int Get_EntitiesCapacity(this IEcsWorldConfig self) + { + return self.GetOrDefault(ENTITIES_CAPACITY, ENTITIES_CAPACITY_DEFAULT); + } + + //private const string RECYCLED_ENTITIES_CAPACITY = nameof(RECYCLED_ENTITIES_CAPACITY); + //public static void Set_RecycledEntitiesCapacity(this IEcsWorldConfig self, int value) + //{ + // self.Set(RECYCLED_ENTITIES_CAPACITY, value); + //} + //public static int Get_RecycledEntitiesCapacity(this IEcsWorldConfig self) + //{ + // return self.GetOrDefault(RECYCLED_ENTITIES_CAPACITY, self.Get_EntitiesCapacity() / 2); + //} + + private const string POOLS_CAPACITY = nameof(POOLS_CAPACITY); + private const int POOLS_CAPACITY_DEFAULT = 512; + public static TConfig Set_PoolsCapacity(this TConfig self, int value) + where TConfig : IEcsWorldConfig + { + self.Set(POOLS_CAPACITY, value); + return self; + } + public static int Get_PoolsCapacity(this IEcsWorldConfig self) + { + return self.GetOrDefault(POOLS_CAPACITY, POOLS_CAPACITY_DEFAULT); + } + + private const string COMPONENT_POOL_CAPACITY = nameof(COMPONENT_POOL_CAPACITY); + private const int COMPONENT_POOL_CAPACITY_DEFAULT = 512; + public static TConfig Set_PoolComponentsCapacity(this TConfig self, int value) + where TConfig : IEcsWorldConfig + { + self.Set(COMPONENT_POOL_CAPACITY, value); + return self; + } + public static int Get_PoolComponentsCapacity(this IEcsWorldConfig self) + { + return self.GetOrDefault(COMPONENT_POOL_CAPACITY, COMPONENT_POOL_CAPACITY_DEFAULT); + } + + private const string POOL_RECYCLED_COMPONENTS_CAPACITY = nameof(POOL_RECYCLED_COMPONENTS_CAPACITY); + public static TConfig Set_PoolRecycledComponentsCapacity(this TConfig self, int value) + where TConfig : IEcsWorldConfig + { + self.Set(POOL_RECYCLED_COMPONENTS_CAPACITY, value); + return self; + } + public static int Get_PoolRecycledComponentsCapacity(this IEcsWorldConfig self) + { + return self.GetOrDefault(POOL_RECYCLED_COMPONENTS_CAPACITY, self.Get_PoolComponentsCapacity() / 2); + } + } +} diff --git a/src/Pools/EcsPool.cs b/src/Pools/EcsPool.cs index 2f0755a..07a5a26 100644 --- a/src/Pools/EcsPool.cs +++ b/src/Pools/EcsPool.cs @@ -143,12 +143,10 @@ namespace DCFApixels.DragonECS _componentTypeID = componentTypeID; _maskBit = EcsMaskChunck.FromID(componentTypeID); - const int capacity = 512; - _mapping = new int[world.Capacity]; - _recycledItems = new int[128]; + _recycledItems = new int[world.Config.Get_PoolRecycledComponentsCapacity()]; _recycledItemsCount = 0; - _items = new T[capacity]; + _items = new T[world.Config.Get_PoolComponentsCapacity()]; _itemsCount = 0; } void IEcsPoolImplementation.OnWorldResize(int newSize) diff --git a/src/Utils/Exceptions.cs b/src/Utils/Exceptions.cs index b883552..243646f 100644 --- a/src/Utils/Exceptions.cs +++ b/src/Utils/Exceptions.cs @@ -81,6 +81,11 @@ namespace DCFApixels.DragonECS.Internal else throw new EcsFrameworkException($"The {entity} is not alive."); } + [MethodImpl(MethodImplOptions.NoInlining)] + internal static void UndefinedException() + { + throw new Exception(); + } } } diff --git a/src/Utils/IntDispenser.cs b/src/Utils/IntDispenser.cs index 96fb120..df975e4 100644 --- a/src/Utils/IntDispenser.cs +++ b/src/Utils/IntDispenser.cs @@ -14,12 +14,7 @@ namespace DCFApixels.DragonECS.Utils #endregion #region Constructor - public IntDispenser() - { - _freeInts = new ConcurrentQueue(); - _increment = 0; - } - public IntDispenser(int startIncrement) + public IntDispenser(int startIncrement = 0) { _freeInts = new ConcurrentQueue(); _increment = startIncrement; From ddceb74a2064a34521aa9f51b4768c9cb88c437f Mon Sep 17 00:00:00 2001 From: Mikhail <99481254+DCFApixels@users.noreply.github.com> Date: Tue, 6 Feb 2024 18:48:44 +0800 Subject: [PATCH 13/16] fix config --- src/EcsWorldConfig.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/EcsWorldConfig.cs b/src/EcsWorldConfig.cs index 98522b9..1a1e269 100644 --- a/src/EcsWorldConfig.cs +++ b/src/EcsWorldConfig.cs @@ -32,6 +32,10 @@ namespace DCFApixels.DragonECS } public void Remove(string valueName) { + if (_isLocked) + { + throw new InvalidOperationException(); + } _storage.Remove(valueName); } public void Set(string valueName, T value) From 7b2c64274a86783e8f67d12d0eaf4927258c5a2f Mon Sep 17 00:00:00 2001 From: Mikhail <99481254+DCFApixels@users.noreply.github.com> Date: Wed, 7 Feb 2024 22:16:41 +0800 Subject: [PATCH 14/16] update --- src/Collections/EcsSpan.cs | 2 +- src/EcsWorld.cs | 41 ++++++++++++++++++++------------- src/Pools/EcsPool.cs | 7 +++++- src/Utils/ArrayUtility.cs | 47 +++++++++++++++++++++++++++++++++++++- 4 files changed, 78 insertions(+), 19 deletions(-) diff --git a/src/Collections/EcsSpan.cs b/src/Collections/EcsSpan.cs index f45d97c..a2f5b75 100644 --- a/src/Collections/EcsSpan.cs +++ b/src/Collections/EcsSpan.cs @@ -1,4 +1,4 @@ -using DCFApixels.DragonECS.Utils; +using DCFApixels.DragonECS.Internal; using System; using System.Collections.Generic; using System.ComponentModel; diff --git a/src/EcsWorld.cs b/src/EcsWorld.cs index 572c208..895c876 100644 --- a/src/EcsWorld.cs +++ b/src/EcsWorld.cs @@ -3,7 +3,6 @@ using DCFApixels.DragonECS.Utils; using System; using System.Collections.Generic; using System.Runtime.CompilerServices; -using static Leopotam.EcsLite.EcsWorld; namespace DCFApixels.DragonECS { @@ -114,12 +113,12 @@ namespace DCFApixels.DragonECS _poolsMediator = new PoolsMediator(this); _entityDispenser = new IntDispenser(0); - int poolsCapacity = config.Get_PoolsCapacity(); + int poolsCapacity = ArrayUtility.NormalizeSizeToPowerOfTwo(config.Get_PoolsCapacity()); _pools = new IEcsPoolImplementation[poolsCapacity]; _poolComponentCounts = new int[poolsCapacity]; ArrayUtility.Fill(_pools, _nullPool); - _entitesCapacity = config.Get_EntitiesCapacity(); + _entitesCapacity = ArrayUtility.NormalizeSizeToPowerOfTwo(config.Get_EntitiesCapacity()); _gens = new short[_entitesCapacity]; _componentCounts = new short[_entitesCapacity]; @@ -267,22 +266,20 @@ namespace DCFApixels.DragonECS #endregion #region Entity + [MethodImpl(MethodImplOptions.AggressiveInlining)] public int NewEntity() { - //if (_isEnableReleaseDelEntBuffer && _freeSpace <= 1 && _delEntBufferCount > _delEntBufferMinCount) - // ReleaseDelEntityBufferAll(); - int entityID = _entityDispenser.GetFree(); _freeSpace--; _entitiesCount++; if (_gens.Length <= entityID) { - Upsize(_gens.Length << 1); + Upsize_Internal(_gens.Length << 1); } _gens[entityID] &= GEN_BITS; - _allEntites.Add(entityID); + _allEntites.AddUnchecked(entityID); _entityListeners.InvokeOnNewEntity(entityID); return entityID; } @@ -291,8 +288,23 @@ namespace DCFApixels.DragonECS int e = NewEntity(); return GetEntityLong(e); } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void TryDelEntity(int entityID) + { + if (IsUsed(entityID)) + { + DelEntity(entityID); + } + } public void DelEntity(int entityID) { +#if DEBUG + if(IsUsed(entityID) == false) + { + Throw.UndefinedException(); + } +#endif _allEntites.Remove(entityID); _delEntBuffer[_delEntBufferCount++] = entityID; _gens[entityID] |= DEATH_GEN_BIT; @@ -446,16 +458,13 @@ namespace DCFApixels.DragonECS #endregion #region Upsize - [MethodImpl(MethodImplOptions.NoInlining)] public void Upsize(int minSize) { - if (minSize < Capacity) - { - return; - } - - int newSize = 1 << (BitsUtility.GetHighBitNumber(minSize - 1) + 1); - + Upsize_Internal(ArrayUtility.NormalizeSizeToPowerOfTwo(minSize)); + } + [MethodImpl(MethodImplOptions.NoInlining)] + private void Upsize_Internal(int newSize) + { Array.Resize(ref _gens, newSize); Array.Resize(ref _componentCounts, newSize); Array.Resize(ref _delEntBuffer, newSize); diff --git a/src/Pools/EcsPool.cs b/src/Pools/EcsPool.cs index 07a5a26..0110348 100644 --- a/src/Pools/EcsPool.cs +++ b/src/Pools/EcsPool.cs @@ -1,3 +1,4 @@ +using DCFApixels.DragonECS.Internal; using System; using System.Collections; using System.Collections.Generic; @@ -54,6 +55,7 @@ namespace DCFApixels.DragonECS } _mediator.RegisterComponent(entityID, _componentTypeID, _maskBit); _listeners.InvokeOnAddAndGet(entityID); + _componentResetHandler.Reset(ref _items[itemIndex]); return ref _items[itemIndex]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -93,6 +95,7 @@ namespace DCFApixels.DragonECS _listeners.InvokeOnAdd(entityID); } _listeners.InvokeOnGet(entityID); + _componentResetHandler.Reset(ref _items[itemIndex]); return ref _items[itemIndex]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -146,7 +149,7 @@ namespace DCFApixels.DragonECS _mapping = new int[world.Capacity]; _recycledItems = new int[world.Config.Get_PoolRecycledComponentsCapacity()]; _recycledItemsCount = 0; - _items = new T[world.Config.Get_PoolComponentsCapacity()]; + _items = new T[ArrayUtility.NormalizeSizeToPowerOfTwo(world.Config.Get_PoolComponentsCapacity())]; _itemsCount = 0; } void IEcsPoolImplementation.OnWorldResize(int newSize) @@ -157,7 +160,9 @@ namespace DCFApixels.DragonECS void IEcsPoolImplementation.OnReleaseDelEntityBuffer(ReadOnlySpan buffer) { foreach (var entityID in buffer) + { TryDel(entityID); + } } #endregion diff --git a/src/Utils/ArrayUtility.cs b/src/Utils/ArrayUtility.cs index 1a80faa..52c7a70 100644 --- a/src/Utils/ArrayUtility.cs +++ b/src/Utils/ArrayUtility.cs @@ -5,18 +5,61 @@ using System.Linq; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -namespace DCFApixels.DragonECS.Utils +namespace DCFApixels.DragonECS.Internal { internal static class ArrayUtility { + private static int GetHighBitNumber(uint bits) + { + if (bits == 0) + { + return -1; + } + int bit = 0; + if ((bits & 0xFFFF0000) != 0) + { + bits >>= 16; + bit |= 16; + } + if ((bits & 0xFF00) != 0) + { + bits >>= 8; + bit |= 8; + } + if ((bits & 0xF0) != 0) + { + bits >>= 4; + bit |= 4; + } + if ((bits & 0xC) != 0) + { + bits >>= 2; + bit |= 2; + } + if ((bits & 0x2) != 0) + { + bit |= 1; + } + return bit; + } + public static int NormalizeSizeToPowerOfTwo(int minSize) + { + return 1 << (GetHighBitNumber((uint)minSize - 1u) + 1); + } public static void Fill(T[] array, T value, int startIndex = 0, int length = -1) { if (length < 0) + { length = array.Length; + } else + { length = startIndex + length; + } for (int i = startIndex; i < length; i++) + { array[i] = value; + } } } internal readonly struct EnumerableInt : IEnumerable @@ -113,7 +156,9 @@ namespace DCFApixels.DragonECS.Utils { T* clone = New(length); for (int i = 0; i < length; i++) + { clone[i] = sourcePtr[i]; + } return clone; } From 79452349c2e97eb2844d28f9140591975b4da942 Mon Sep 17 00:00:00 2001 From: Mikhail <99481254+DCFApixels@users.noreply.github.com> Date: Fri, 9 Feb 2024 22:20:55 +0800 Subject: [PATCH 15/16] update data interfaces --- src/DataInterfaces.cs | 6 ++++++ src/Pools/EcsPool.cs | 41 ++++++++++++++++++++++++++++++++++++----- 2 files changed, 42 insertions(+), 5 deletions(-) diff --git a/src/DataInterfaces.cs b/src/DataInterfaces.cs index d200d3a..81a8a70 100644 --- a/src/DataInterfaces.cs +++ b/src/DataInterfaces.cs @@ -17,10 +17,12 @@ namespace DCFApixels.DragonECS T def = default; if (def is IEcsWorldComponent intrf) { + isHasHandler = true; instance = intrf; } else { + isHasHandler = false; instance = new DummyHandler(); } } @@ -47,10 +49,12 @@ namespace DCFApixels.DragonECS T def = default; if (def is IEcsComponentReset intrf) { + isHasHandler = true; instance = intrf; } else { + isHasHandler = false; instance = new DummyHandler(); } } @@ -76,10 +80,12 @@ namespace DCFApixels.DragonECS T def = default; if (def is IEcsComponentCopy intrf) { + isHasHandler = true; instance = intrf; } else { + isHasHandler = false; instance = new DummyHandler(); } } diff --git a/src/Pools/EcsPool.cs b/src/Pools/EcsPool.cs index 0110348..cc69c74 100644 --- a/src/Pools/EcsPool.cs +++ b/src/Pools/EcsPool.cs @@ -21,7 +21,9 @@ namespace DCFApixels.DragonECS private int _recycledItemsCount; private IEcsComponentReset _componentResetHandler = EcsComponentResetHandler.instance; + private bool _isHasComponentResetHandler = EcsComponentResetHandler.isHasHandler; private IEcsComponentCopy _componentCopyHandler = EcsComponentCopyHandler.instance; + private bool _isHasComponentCopyHandler = EcsComponentCopyHandler.isHasHandler; private List _listeners = new List(); @@ -55,7 +57,7 @@ namespace DCFApixels.DragonECS } _mediator.RegisterComponent(entityID, _componentTypeID, _maskBit); _listeners.InvokeOnAddAndGet(entityID); - _componentResetHandler.Reset(ref _items[itemIndex]); + ResetComponent(ref _items[itemIndex]); return ref _items[itemIndex]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -95,7 +97,7 @@ namespace DCFApixels.DragonECS _listeners.InvokeOnAdd(entityID); } _listeners.InvokeOnGet(entityID); - _componentResetHandler.Reset(ref _items[itemIndex]); + ResetComponent(ref _items[itemIndex]); return ref _items[itemIndex]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -109,9 +111,11 @@ namespace DCFApixels.DragonECS if (!Has(entityID)) EcsPoolThrowHalper.ThrowNotHaveComponent(entityID); #endif ref int itemIndex = ref _mapping[entityID]; - _componentResetHandler.Reset(ref _items[itemIndex]); + ResetComponent(ref _items[itemIndex]); if (_recycledItemsCount >= _recycledItems.Length) + { Array.Resize(ref _recycledItems, _recycledItems.Length << 1); + } _recycledItems[_recycledItemsCount++] = itemIndex; _mapping[entityID] = 0; _itemsCount--; @@ -127,14 +131,14 @@ namespace DCFApixels.DragonECS #if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS if (!Has(fromEntityID)) EcsPoolThrowHalper.ThrowNotHaveComponent(fromEntityID); #endif - _componentCopyHandler.Copy(ref Get(fromEntityID), ref TryAddOrGet(toEntityID)); + CopyComponent(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(fromEntityID); #endif - _componentCopyHandler.Copy(ref Get(fromEntityID), ref toWorld.GetPool().TryAddOrGet(toEntityID)); + CopyComponent(ref Get(fromEntityID), ref toWorld.GetPool().TryAddOrGet(toEntityID)); } #endregion @@ -187,6 +191,33 @@ namespace DCFApixels.DragonECS } #endregion + #region Reset/Copy + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void ResetComponent(ref T component) + { + if (_isHasComponentResetHandler) + { + _componentResetHandler.Reset(ref component); + } + else + { + component = default; + } + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void CopyComponent(ref T from, ref T to) + { + if (_isHasComponentCopyHandler) + { + _componentCopyHandler.Copy(ref from, ref to); + } + else + { + to = from; + } + } + #endregion + #region IEnumerator - IntelliSense hack IEnumerator IEnumerable.GetEnumerator() => throw new NotImplementedException(); IEnumerator IEnumerable.GetEnumerator() => throw new NotImplementedException(); From 181f0ecde93479f6de127b9ff330426da42c29a4 Mon Sep 17 00:00:00 2001 From: Mikhail <99481254+DCFApixels@users.noreply.github.com> Date: Fri, 9 Feb 2024 22:39:42 +0800 Subject: [PATCH 16/16] Create EcsWorldConfig.cs.meta --- src/EcsWorldConfig.cs.meta | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 src/EcsWorldConfig.cs.meta diff --git a/src/EcsWorldConfig.cs.meta b/src/EcsWorldConfig.cs.meta new file mode 100644 index 0000000..2c9a917 --- /dev/null +++ b/src/EcsWorldConfig.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0bd5947405343044b9e716c787ad4945 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: