diff --git a/GlitchyEngine/src/World/EcsWorld.bf b/GlitchyEngine/src/World/EcsWorld.bf index f2d5ffd..915b390 100644 --- a/GlitchyEngine/src/World/EcsWorld.bf +++ b/GlitchyEngine/src/World/EcsWorld.bf @@ -10,15 +10,15 @@ namespace GlitchyEngine.World { const int MaxEntities = 1024; - typealias BitmaskEntry = (Entity ID, BitArray ComponentMask); - List _entities = new .(); + internal typealias BitmaskEntry = (Entity ID, BitArray ComponentMask); + internal List _entities = new .(); List _freeIndices = new List() ~ delete _; typealias DisposeFunction = function void(void* component); - typealias ComponentPoolEntry = (uint32 Id, ComponentPool Pool, DisposeFunction DisposeFunction); - Dictionary _componentPools = new .(); + internal typealias ComponentPoolEntry = (uint32 Id, ComponentPool Pool, DisposeFunction DisposeFunction); + internal Dictionary _componentPools = new .(); /// A list containing all pools whose components need to be disposed before removal. List _disposingPools = new .() ~ delete _; @@ -68,6 +68,16 @@ namespace GlitchyEngine.World _disposingPools.Add(&poolInDictionary); } + /** @brief Returns the component pool for the given component type. + * @param TComponent The type of the component whose component pool will be returned. + * @returns A reference to the component pool. + */ + [Inline] + internal ref ComponentPoolEntry GetComponentPool() + { + return ref _componentPools[typeof(TComponent)]; + } + /** * Creates a new Entity and returns its ID. */ @@ -230,54 +240,21 @@ namespace GlitchyEngine.World return WorldEnumerator(this, componentTypes); } - public struct WorldEnumerator : IEnumerator, IDisposable + public WorldEnumerator Enumerate() where TComponent : struct { - private EcsWorld _world; - private BitArray _bitMask; - private BitmaskEntry* _currentEntry; - private BitmaskEntry* _endEntry; + return WorldEnumerator(this); + } - public this(EcsWorld world, Type[] componentTypes) - { - _world = world; - _currentEntry = _world._entities.Ptr; - _endEntry = _world._entities.Ptr + _world._entities.Count; - - _bitMask = new BitArray(_world._componentPools.Count); - for(var type in componentTypes) - { - Log.EngineLogger.AssertDebug(type.IsStruct, "Components can only be structs."); - - var result = _world._componentPools.GetValue(type); - - if(result case .Ok(let entry)) - { - _bitMask[entry.Id] = true; - } - else - { - Log.EngineLogger.AssertDebug(false, "Queried component is not registered for this world. This is invalid because the query would never return any results."); - } - } - } - - public Result GetNext() mut - { - while(_currentEntry < _endEntry) - { - BitmaskEntry* entry = _currentEntry++; - // Check whether or not mask matches - if(entry.ComponentMask.MaskMatch(_bitMask)) - return entry.ID; - } - - return .Err; - } - - public void Dispose() - { - delete _bitMask; - } + public WorldEnumerator Enumerate() where TComponent0 : struct + where TComponent1 : struct + { + return WorldEnumerator(this); + } + + public WorldEnumerator Enumerate() + where TComponent0 : struct where TComponent1 : struct where TComponent2 : struct + { + return WorldEnumerator(this); } public static void Test() diff --git a/GlitchyEngine/src/World/WorldEnumerator.bf b/GlitchyEngine/src/World/WorldEnumerator.bf new file mode 100644 index 0000000..60611bb --- /dev/null +++ b/GlitchyEngine/src/World/WorldEnumerator.bf @@ -0,0 +1,137 @@ +using System.Collections; +using System; +using GlitchyEngine.Math; + +using internal GlitchyEngine.World; + +namespace GlitchyEngine.World +{ + public struct WorldEnumerator : IEnumerator, IDisposable + { + internal EcsWorld _world; + internal BitArray _bitMask; + internal EcsWorld.BitmaskEntry* _currentEntry; + internal EcsWorld.BitmaskEntry* _endEntry; + + public this(EcsWorld world, Type[] componentTypes) + { + _world = world; + _currentEntry = _world._entities.Ptr; + _endEntry = _world._entities.Ptr + _world._entities.Count; + + _bitMask = new BitArray(_world._componentPools.Count); + for(var type in componentTypes) + { + Log.EngineLogger.AssertDebug(type.IsStruct, "Components can only be structs."); + + var result = _world._componentPools.GetValue(type); + + if(result case .Ok(let entry)) + { + _bitMask[entry.Id] = true; + } + else + { + Log.EngineLogger.AssertDebug(false, "Queried component is not registered for this world. This is invalid because the query would never return any results."); + } + } + } + + public Result GetNext() mut + { + while(_currentEntry < _endEntry) + { + EcsWorld.BitmaskEntry* entry = _currentEntry++; + // Check whether or not mask matches + if(entry.ComponentMask.MaskMatch(_bitMask)) + return entry.ID; + } + + return .Err; + } + + public void Dispose() + { + delete _bitMask; + } + } + + public struct WorldEnumerator : WorldEnumerator, IEnumerator<(Entity Entity, TComponent* Component)> where TComponent : struct + { + internal EcsWorld.ComponentPoolEntry* _componentPool; + + public this(EcsWorld world) : base(world, scope Type[](typeof(TComponent))) + { + _componentPool = &world.GetComponentPool(); + } + + public new Result<(Entity Entity, TComponent* Component)> GetNext() mut + { + Result entity = base.GetNext(); + + if(entity case .Err) + return .Err; + + TComponent* component = (.)_componentPool.Pool.Get(entity.Value.Index); + + return .Ok((entity.Value, component)); + } + } + + public struct WorldEnumerator : WorldEnumerator, + IEnumerator<(Entity Entity, TComponent0* Component0, TComponent1* Component1)> + where TComponent0 : struct where TComponent1 : struct + { + internal EcsWorld.ComponentPoolEntry* _componentPool0; + internal EcsWorld.ComponentPoolEntry* _componentPool1; + + public this(EcsWorld world) : base(world, scope Type[](typeof(TComponent0), typeof(TComponent1))) + { + _componentPool0 = &world.GetComponentPool(); + _componentPool1 = &world.GetComponentPool(); + } + + public new Result<(Entity Entity, TComponent0* Component0, TComponent1* Component1)> GetNext() mut + { + Result entity = base.GetNext(); + + if(entity case .Err) + return .Err; + + TComponent0* component0 = (.)_componentPool0.Pool.Get(entity.Value.Index); + TComponent1* component1 = (.)_componentPool1.Pool.Get(entity.Value.Index); + + return .Ok((entity.Value, component0, component1)); + } + } + + public struct WorldEnumerator : WorldEnumerator, + IEnumerator<(Entity Entity, TComponent0* Component0, TComponent1* Component1, TComponent2* Component2)> + where TComponent0 : struct where TComponent1 : struct where TComponent2 : struct + { + internal EcsWorld.ComponentPoolEntry* _componentPool0; + internal EcsWorld.ComponentPoolEntry* _componentPool1; + internal EcsWorld.ComponentPoolEntry* _componentPool2; + + public this(EcsWorld world) : base(world, scope Type[](typeof(TComponent0), typeof(TComponent1), typeof(TComponent2))) + { + _componentPool0 = &world.GetComponentPool(); + _componentPool1 = &world.GetComponentPool(); + _componentPool2 = &world.GetComponentPool(); + } + + public new Result<(Entity Entity, TComponent0* Component0, TComponent1* Component1, TComponent2* Component2)> GetNext() mut + { + Result entity = base.GetNext(); + + if(entity case .Err) + return .Err; + + TComponent0* component0 = (.)_componentPool0.Pool.Get(entity.Value.Index); + TComponent1* component1 = (.)_componentPool1.Pool.Get(entity.Value.Index); + TComponent2* component2 = (.)_componentPool2.Pool.Get(entity.Value.Index); + + return .Ok((entity.Value, component0, component1, component2)); + } + } +}