using System; using System.Collections; using System.Collections.Generic; using System.Reflection; using System.Runtime.CompilerServices; namespace DCFApixels.DragonECS { public sealed class EcsTagPool : IEcsPoolImplementation, IEcsStructPool, IEnumerable //IEnumerable - IntelliSense hack where T : struct, IEcsTagComponent { private EcsWorld _source; private int _componentID; private bool[] _mapping;// index = entityID / value = itemIndex;/ value = 0 = no entityID private int _count; private List _listeners = new List(); private T _fakeComponent; private static bool _isInvalidType; static EcsTagPool() { _isInvalidType = typeof(T).GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).Length > 0; } public EcsTagPool() { if (_isInvalidType) throw new EcsFrameworkException($"{typeof(T).Name} type must not contain any data."); } #region Properites public int Count => _count; int IEcsPool.Capacity => -1; public int ComponentID => _componentID; public Type ComponentType => typeof(T); public EcsWorld World => _source; #endregion #region Method public void Add(int entityID) { #if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS if (Has(entityID)) EcsPoolThrowHalper.ThrowAlreadyHasComponent(entityID); #endif _count++; _mapping[entityID] = true; this.IncrementEntityComponentCount(entityID, _componentID); _listeners.InvokeOnAdd(entityID); } public void TryAdd(int entityID) { if (!_mapping[entityID]) { _count++; _mapping[entityID] = true; this.IncrementEntityComponentCount(entityID, _componentID); _listeners.InvokeOnAdd(entityID); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Has(int entityID) { return _mapping[entityID]; } public void Del(int entityID) { #if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS if (!Has(entityID)) EcsPoolThrowHalper.ThrowNotHaveComponent(entityID); #endif _mapping[entityID] = false; _count--; this.DecrementEntityComponentCount(entityID, _componentID); _listeners.InvokeOnDel(entityID); } public void TryDel(int entityID) { if (Has(entityID)) Del(entityID); } public void Copy(int fromEntityID, int toEntityID) { #if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS if (!Has(fromEntityID)) EcsPoolThrowHalper.ThrowNotHaveComponent(fromEntityID); #endif TryAdd(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 toWorld.GetPool().TryAdd(toEntityID); } public void Set(int entityID, bool isHas) { if (isHas) { if (!Has(entityID)) Add(entityID); } else { if (Has(entityID)) Del(entityID); } } public void Toggle(int entityID) { if (Has(entityID)) Del(entityID); else Add(entityID); } #endregion #region Callbacks void IEcsPoolImplementation.OnInit(EcsWorld world, int componentID) { _source = world; _componentID = componentID; _mapping = new bool[world.Capacity]; _count = 0; } void IEcsPoolImplementation.OnWorldResize(int newSize) { Array.Resize(ref _mapping, newSize); } void IEcsPoolImplementation.OnWorldDestroy() { } void IEcsPoolImplementation.OnReleaseDelEntityBuffer(ReadOnlySpan buffer) { foreach (var entityID in buffer) TryDel(entityID); } #endregion #region Other ref T IEcsStructPool.Add(int entityID) { Add(entityID); return ref _fakeComponent; } ref readonly T IEcsStructPool.Read(int entityID) { #if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS if (!Has(entityID)) EcsPoolThrowHalper.ThrowNotHaveComponent(entityID); #endif return ref _fakeComponent; } ref T IEcsStructPool.Get(int entityID) { #if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS if (!Has(entityID)) EcsPoolThrowHalper.ThrowNotHaveComponent(entityID); #endif return ref _fakeComponent; } void IEcsPool.AddRaw(int entityID, object dataRaw) => Add(entityID); object IEcsPool.GetRaw(int entityID) { #if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS if (!Has(entityID)) EcsPoolThrowHalper.ThrowNotHaveComponent(entityID); #endif return _fakeComponent; } void IEcsPool.SetRaw(int entityID, object dataRaw) { #if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS if (!Has(entityID)) EcsPoolThrowHalper.ThrowNotHaveComponent(entityID); #endif } #endregion #region Listeners public void AddListener(IEcsPoolEventListener listener) { if (listener == null) { throw new ArgumentNullException("listener is null"); } _listeners.Add(listener); } public void RemoveListener(IEcsPoolEventListener listener) { if (listener == null) { throw new ArgumentNullException("listener is null"); } _listeners.Remove(listener); } #endregion #region IEnumerator - IntelliSense hack IEnumerator IEnumerable.GetEnumerator() => throw new NotImplementedException(); IEnumerator IEnumerable.GetEnumerator() => throw new NotImplementedException(); #endregion } /// Component without data public interface IEcsTagComponent { } public static class EcsTagPoolExt { [MethodImpl(MethodImplOptions.AggressiveInlining)] public static EcsTagPool GetPool(this EcsWorld self) where TTagComponent : struct, IEcsTagComponent { return self.GetPool>(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static EcsTagPool GetPoolUnchecked(this EcsWorld self) where TTagComponent : struct, IEcsTagComponent { return self.GetPoolUnchecked>(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static EcsTagPool Include(this EcsAspectBuilderBase self) where TTagComponent : struct, IEcsTagComponent { return self.Include>(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static EcsTagPool Exclude(this EcsAspectBuilderBase self) where TTagComponent : struct, IEcsTagComponent { return self.Exclude>(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static EcsTagPool Optional(this EcsAspectBuilderBase self) where TTagComponent : struct, IEcsTagComponent { return self.Optional>(); } //--------------------------------------------------- [MethodImpl(MethodImplOptions.AggressiveInlining)] public static EcsTagPool GetTagPool(this EcsWorld self) where TTagComponent : struct, IEcsTagComponent { return self.GetPool>(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static EcsTagPool GetTagPoolUnchecked(this EcsWorld self) where TTagComponent : struct, IEcsTagComponent { return self.GetPoolUnchecked>(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static EcsTagPool IncludeTag(this EcsAspectBuilderBase self) where TTagComponent : struct, IEcsTagComponent { return self.Include>(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static EcsTagPool ExcludeTag(this EcsAspectBuilderBase self) where TTagComponent : struct, IEcsTagComponent { return self.Exclude>(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static EcsTagPool OptionalTag(this EcsAspectBuilderBase self) where TTagComponent : struct, IEcsTagComponent { return self.Optional>(); } } }