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) {