Added generic World Enumerators

also moved WorldEnumerators out of EcsWorld
This commit is contained in:
Simon Lübeß
2021-09-02 12:20:33 +02:00
parent c9e9a11e4e
commit 5ce7ebe674
2 changed files with 164 additions and 50 deletions
+27 -50
View File
@@ -10,15 +10,15 @@ namespace GlitchyEngine.World
{ {
const int MaxEntities = 1024; const int MaxEntities = 1024;
typealias BitmaskEntry = (Entity ID, BitArray ComponentMask); internal typealias BitmaskEntry = (Entity ID, BitArray ComponentMask);
List<BitmaskEntry> _entities = new .(); internal List<BitmaskEntry> _entities = new .();
List<uint32> _freeIndices = new List<uint32>() ~ delete _; List<uint32> _freeIndices = new List<uint32>() ~ delete _;
typealias DisposeFunction = function void(void* component); typealias DisposeFunction = function void(void* component);
typealias ComponentPoolEntry = (uint32 Id, ComponentPool Pool, DisposeFunction DisposeFunction); internal typealias ComponentPoolEntry = (uint32 Id, ComponentPool Pool, DisposeFunction DisposeFunction);
Dictionary<Type, ComponentPoolEntry> _componentPools = new .(); internal Dictionary<Type, ComponentPoolEntry> _componentPools = new .();
/// A list containing all pools whose components need to be disposed before removal. /// A list containing all pools whose components need to be disposed before removal.
List<ComponentPoolEntry*> _disposingPools = new .() ~ delete _; List<ComponentPoolEntry*> _disposingPools = new .() ~ delete _;
@@ -68,6 +68,16 @@ namespace GlitchyEngine.World
_disposingPools.Add(&poolInDictionary); _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<TComponent>()
{
return ref _componentPools[typeof(TComponent)];
}
/** /**
* Creates a new Entity and returns its ID. * Creates a new Entity and returns its ID.
*/ */
@@ -230,54 +240,21 @@ namespace GlitchyEngine.World
return WorldEnumerator(this, componentTypes); return WorldEnumerator(this, componentTypes);
} }
public struct WorldEnumerator : IEnumerator<Entity>, IDisposable public WorldEnumerator<TComponent> Enumerate<TComponent>() where TComponent : struct
{ {
private EcsWorld _world; return WorldEnumerator<TComponent>(this);
private BitArray _bitMask; }
private BitmaskEntry* _currentEntry;
private BitmaskEntry* _endEntry;
public this(EcsWorld world, Type[] componentTypes) public WorldEnumerator<TComponent0, TComponent1> Enumerate<TComponent0, TComponent1>() where TComponent0 : struct
{ where TComponent1 : struct
_world = world; {
_currentEntry = _world._entities.Ptr; return WorldEnumerator<TComponent0, TComponent1>(this);
_endEntry = _world._entities.Ptr + _world._entities.Count; }
_bitMask = new BitArray(_world._componentPools.Count); public WorldEnumerator<TComponent0, TComponent1, TComponent2> Enumerate<TComponent0, TComponent1, TComponent2>()
for(var type in componentTypes) where TComponent0 : struct where TComponent1 : struct where TComponent2 : struct
{ {
Log.EngineLogger.AssertDebug(type.IsStruct, "Components can only be structs."); return WorldEnumerator<TComponent0, TComponent1, TComponent2>(this);
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<Entity> 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 static void Test() public static void Test()
+137
View File
@@ -0,0 +1,137 @@
using System.Collections;
using System;
using GlitchyEngine.Math;
using internal GlitchyEngine.World;
namespace GlitchyEngine.World
{
public struct WorldEnumerator : IEnumerator<Entity>, 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<Entity> 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<TComponent> : 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<TComponent>();
}
public new Result<(Entity Entity, TComponent* Component)> GetNext() mut
{
Result<Entity> 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<TComponent0, TComponent1> : 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<TComponent0>();
_componentPool1 = &world.GetComponentPool<TComponent1>();
}
public new Result<(Entity Entity, TComponent0* Component0, TComponent1* Component1)> GetNext() mut
{
Result<Entity> 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<TComponent0, TComponent1, TComponent2> : 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<TComponent0>();
_componentPool1 = &world.GetComponentPool<TComponent1>();
_componentPool2 = &world.GetComponentPool<TComponent2>();
}
public new Result<(Entity Entity, TComponent0* Component0, TComponent1* Component1, TComponent2* Component2)> GetNext() mut
{
Result<Entity> 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));
}
}
}