using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; namespace DCFApixels.DragonECS { using static EcsPoolThrowHalper; public sealed class EcsSinglePool : IEcsPoolImplementation, IEnumerable //IntelliSense hack where T : struct, IEcsSingleComponent { private EcsWorld _source; private int _id; private int[] _mapping; private int _count; private T _component; private PoolRunners _poolRunners; #region Properites public ref T Instance { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => ref _component; } public int Count => _count; int IEcsPool.Capacity => -1; public int ComponentID => _id; public Type ComponentType => typeof(T); public EcsWorld World => _source; #endregion #region Init void IEcsPoolImplementation.OnInit(EcsWorld world, int componentID) { _source = world; _id = componentID; _mapping = new int[world.Capacity]; _count = 0; _poolRunners = new PoolRunners(world.Pipeline); } #endregion #region Methods public ref T Add(int entityID) { #if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS if (Has(entityID)) ThrowAlreadyHasComponent(entityID); #endif _mapping[entityID] = ++_count; this.IncrementEntityComponentCount(entityID); _poolRunners.add.OnComponentAdd(entityID); return ref _component; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public ref T Write(int entityID) { #if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS if (!Has(entityID)) ThrowNotHaveComponent(entityID); #endif _poolRunners.write.OnComponentWrite(entityID); return ref _component; } public ref T TryAddOrWrite(int entityID) { if (!Has(entityID)) return ref Add(entityID); return ref Write(entityID); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public ref readonly T Read(int entityID) { #if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS if (!Has(entityID)) ThrowNotHaveComponent(entityID); #endif return ref _component; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Has(int entityID) { return _mapping[entityID] > 0; } public void Del(int entityID) { #if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS if (!Has(entityID)) ThrowNotHaveComponent(entityID); #endif _mapping[entityID] = 0; _count--; this.DecrementEntityComponentCount(entityID); _poolRunners.del.OnComponentDel(entityID); } public void TryDel(int entityID) { if (Has(entityID)) Del(entityID); } public void Copy(int fromEntityID, int toEntityID) { #if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS if (!Has(fromEntityID)) ThrowNotHaveComponent(fromEntityID); #endif TryAddOrWrite(toEntityID); } #endregion #region Callbacks 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 void IEcsPool.AddRaw(int entityID, object dataRaw) => Instance = (T)dataRaw; object IEcsPool.GetRaw(int entityID) => Instance; void IEcsPool.SetRaw(int entityID, object dataRaw) => Instance = (T)dataRaw; #endregion #region IEnumerator - IntelliSense hack IEnumerator IEnumerable.GetEnumerator() => throw new NotImplementedException(); IEnumerator IEnumerable.GetEnumerator() => throw new NotImplementedException(); #endregion } /// Singleton component public interface IEcsSingleComponent { } public static class EcsSinglePoolExt { public static EcsSinglePool GetPool(this EcsWorld self) where TSingleComponent : struct, IEcsSingleComponent { return self.GetPool>(); } public static EcsSinglePool Include(this EcsSubjectBuilderBase self) where TSingleComponent : struct, IEcsSingleComponent { return self.Include>(); } public static EcsSinglePool Exclude(this EcsSubjectBuilderBase self) where TSingleComponent : struct, IEcsSingleComponent { return self.Exclude>(); } public static EcsSinglePool Optional(this EcsSubjectBuilderBase self) where TSingleComponent : struct, IEcsSingleComponent { return self.Optional>(); } } }