split Id to EntityId and TypeId

rev2
cosmonaut 2023-10-31 15:00:42 -07:00
parent d4c84868d8
commit 5ba5c2f5cd
13 changed files with 152 additions and 147 deletions

View File

@ -8,11 +8,11 @@ internal class Archetype
public World World; public World World;
public ArchetypeSignature Signature; public ArchetypeSignature Signature;
public NativeArray[] ComponentColumns; public NativeArray[] ComponentColumns;
public NativeArray<Id> RowToEntity = new NativeArray<Id>(); public NativeArray<EntityId> RowToEntity = new NativeArray<EntityId>();
public Dictionary<Id, int> ComponentToColumnIndex = public Dictionary<TypeId, int> ComponentToColumnIndex =
new Dictionary<Id, int>(); new Dictionary<TypeId, int>();
public SortedDictionary<Id, ArchetypeEdge> Edges = new SortedDictionary<Id, ArchetypeEdge>(); public SortedDictionary<TypeId, ArchetypeEdge> Edges = new SortedDictionary<TypeId, ArchetypeEdge>();
public int Count => RowToEntity.Count; public int Count => RowToEntity.Count;

View File

@ -11,7 +11,7 @@ internal class ArchetypeSignature : IEquatable<ArchetypeSignature>
public int Count => Ids.Count; public int Count => Ids.Count;
public Id this[int i] => new Id(Ids[i]); public TypeId this[int i] => new TypeId(Ids[i]);
public ArchetypeSignature() public ArchetypeSignature()
{ {
@ -24,7 +24,7 @@ internal class ArchetypeSignature : IEquatable<ArchetypeSignature>
} }
// Maintains sorted order // Maintains sorted order
public void Insert(Id componentId) public void Insert(TypeId componentId)
{ {
var index = Ids.BinarySearch(componentId.Value); var index = Ids.BinarySearch(componentId.Value);
@ -34,7 +34,7 @@ internal class ArchetypeSignature : IEquatable<ArchetypeSignature>
} }
} }
public void Remove(Id componentId) public void Remove(TypeId componentId)
{ {
var index = Ids.BinarySearch(componentId.Value); var index = Ids.BinarySearch(componentId.Value);

View File

@ -9,21 +9,21 @@ public abstract class EntityComponentReader
World = world; World = world;
} }
protected bool Has<T>(in Id entityId) where T : unmanaged => World.Has<T>(entityId); protected bool Has<T>(in EntityId entityId) where T : unmanaged => World.Has<T>(entityId);
protected bool Some<T>() where T : unmanaged => World.Some<T>(); protected bool Some<T>() where T : unmanaged => World.Some<T>();
protected ref T Get<T>(in Id entityId) where T : unmanaged => ref World.Get<T>(entityId); protected ref T Get<T>(in EntityId entityId) where T : unmanaged => ref World.Get<T>(entityId);
protected ref T GetSingleton<T>() where T : unmanaged => ref World.GetSingleton<T>(); protected ref T GetSingleton<T>() where T : unmanaged => ref World.GetSingleton<T>();
protected Id GetSingletonEntity<T>() where T : unmanaged => World.GetSingletonEntity<T>(); protected EntityId GetSingletonEntity<T>() where T : unmanaged => World.GetSingletonEntity<T>();
protected ReverseSpanEnumerator<(Id, Id)> Relations<T>() where T : unmanaged => World.Relations<T>(); protected ReverseSpanEnumerator<(EntityId, EntityId)> Relations<T>() where T : unmanaged => World.Relations<T>();
protected bool Related<T>(in Id entityA, in Id entityB) where T : unmanaged => World.Related<T>(entityA, entityB); protected bool Related<T>(in EntityId entityA, in EntityId entityB) where T : unmanaged => World.Related<T>(entityA, entityB);
protected T GetRelationData<T>(in Id entityA, in Id entityB) where T : unmanaged => World.GetRelationData<T>(entityA, entityB); protected T GetRelationData<T>(in EntityId entityA, in EntityId entityB) where T : unmanaged => World.GetRelationData<T>(entityA, entityB);
protected ReverseSpanEnumerator<Id> OutRelations<T>(in Id entity) where T : unmanaged => World.OutRelations<T>(entity); protected ReverseSpanEnumerator<EntityId> OutRelations<T>(in EntityId entity) where T : unmanaged => World.OutRelations<T>(entity);
protected Id OutRelationSingleton<T>(in Id entity) where T : unmanaged => World.OutRelationSingleton<T>(entity); protected EntityId OutRelationSingleton<T>(in EntityId entity) where T : unmanaged => World.OutRelationSingleton<T>(entity);
protected bool HasOutRelation<T>(in Id entity) where T : unmanaged => World.HasOutRelation<T>(entity); protected bool HasOutRelation<T>(in EntityId entity) where T : unmanaged => World.HasOutRelation<T>(entity);
protected ReverseSpanEnumerator<Id> InRelations<T>(in Id entity) where T : unmanaged => World.InRelations<T>(entity); protected ReverseSpanEnumerator<EntityId> InRelations<T>(in EntityId entity) where T : unmanaged => World.InRelations<T>(entity);
protected Id InRelationSingleton<T>(in Id entity) where T : unmanaged => World.InRelationSingleton<T>(entity); protected EntityId InRelationSingleton<T>(in EntityId entity) where T : unmanaged => World.InRelationSingleton<T>(entity);
protected bool HasInRelation<T>(in Id entity) where T : unmanaged => World.HasInRelation<T>(entity); protected bool HasInRelation<T>(in EntityId entity) where T : unmanaged => World.HasInRelation<T>(entity);
} }

View File

@ -4,10 +4,10 @@ public class Manipulator : EntityComponentReader
{ {
public Manipulator(World world) : base(world) { } public Manipulator(World world) : base(world) { }
protected void Set<TComponent>(in Id entity, in TComponent component) where TComponent : unmanaged => World.Set<TComponent>(entity, component); protected void Set<TComponent>(in EntityId entity, in TComponent component) where TComponent : unmanaged => World.Set<TComponent>(entity, component);
protected void Remove<TComponent>(in Id entity) where TComponent : unmanaged => World.Remove<TComponent>(entity); protected void Remove<TComponent>(in EntityId entity) where TComponent : unmanaged => World.Remove<TComponent>(entity);
protected void Unrelate<TRelationKind>(in Id entityA, in Id entityB) where TRelationKind : unmanaged => World.Unrelate<TRelationKind>(entityA, entityB); protected void Unrelate<TRelationKind>(in EntityId entityA, in EntityId entityB) where TRelationKind : unmanaged => World.Unrelate<TRelationKind>(entityA, entityB);
protected void UnrelateAll<TRelationKind>(in Id entity) where TRelationKind : unmanaged => World.UnrelateAll<TRelationKind>(entity); protected void UnrelateAll<TRelationKind>(in EntityId entity) where TRelationKind : unmanaged => World.UnrelateAll<TRelationKind>(entity);
protected void Destroy(in Id entity) => World.Destroy(entity); protected void Destroy(in EntityId entity) => World.Destroy(entity);
} }

11
src/Rev2/EntityId.cs Normal file
View File

@ -0,0 +1,11 @@
using System;
namespace MoonTools.ECS.Rev2;
public readonly record struct EntityId(uint Value) : IComparable<EntityId>
{
public int CompareTo(EntityId other)
{
return Value.CompareTo(other.Value);
}
}

View File

@ -7,8 +7,8 @@ namespace MoonTools.ECS.Rev2;
public class Filter public class Filter
{ {
private Archetype EmptyArchetype; private Archetype EmptyArchetype;
private HashSet<Id> Included; private HashSet<TypeId> Included;
private HashSet<Id> Excluded; private HashSet<TypeId> Excluded;
public EntityEnumerator Entities => new EntityEnumerator(this); public EntityEnumerator Entities => new EntityEnumerator(this);
internal ArchetypeEnumerator Archetypes => new ArchetypeEnumerator(this); internal ArchetypeEnumerator Archetypes => new ArchetypeEnumerator(this);
@ -47,7 +47,7 @@ public class Filter
} }
} }
public Id RandomEntity public EntityId RandomEntity
{ {
get get
{ {
@ -57,7 +57,7 @@ public class Filter
} }
// WARNING: this WILL crash if the index is out of range! // WARNING: this WILL crash if the index is out of range!
public Id NthEntity(int index) public EntityId NthEntity(int index)
{ {
var count = 0; var count = 0;
@ -83,7 +83,7 @@ public class Filter
} }
} }
internal Filter(Archetype emptyArchetype, HashSet<Id> included, HashSet<Id> excluded) internal Filter(Archetype emptyArchetype, HashSet<TypeId> included, HashSet<TypeId> excluded)
{ {
EmptyArchetype = emptyArchetype; EmptyArchetype = emptyArchetype;
Included = included; Included = included;
@ -155,12 +155,12 @@ public class Filter
public ref struct EntityEnumerator public ref struct EntityEnumerator
{ {
private Id CurrentEntity; private EntityId CurrentEntity;
public EntityEnumerator GetEnumerator() => this; public EntityEnumerator GetEnumerator() => this;
// TODO: pool this // TODO: pool this
Queue<Id> EntityQueue = new Queue<Id>(); Queue<EntityId> EntityQueue = new Queue<EntityId>();
internal EntityEnumerator(Filter filter) internal EntityEnumerator(Filter filter)
{ {
@ -180,7 +180,7 @@ public class Filter
return EntityQueue.TryDequeue(out CurrentEntity); return EntityQueue.TryDequeue(out CurrentEntity);
} }
public Id Current => CurrentEntity; public EntityId Current => CurrentEntity;
} }
public ref struct RandomEntityEnumerator public ref struct RandomEntityEnumerator
@ -198,6 +198,6 @@ public class Filter
} }
public bool MoveNext() => LinearCongruentialEnumerator.MoveNext(); public bool MoveNext() => LinearCongruentialEnumerator.MoveNext();
public Id Current => Filter.NthEntity(LinearCongruentialEnumerator.Current); public EntityId Current => Filter.NthEntity(LinearCongruentialEnumerator.Current);
} }
} }

View File

@ -5,17 +5,17 @@ namespace MoonTools.ECS.Rev2;
public ref struct FilterBuilder public ref struct FilterBuilder
{ {
World World; World World;
HashSet<Id> Included; HashSet<TypeId> Included;
HashSet<Id> Excluded; HashSet<TypeId> Excluded;
internal FilterBuilder(World world) internal FilterBuilder(World world)
{ {
World = world; World = world;
Included = new HashSet<Id>(); Included = new HashSet<TypeId>();
Excluded = new HashSet<Id>(); Excluded = new HashSet<TypeId>();
} }
private FilterBuilder(World world, HashSet<Id> included, HashSet<Id> excluded) private FilterBuilder(World world, HashSet<TypeId> included, HashSet<TypeId> excluded)
{ {
World = world; World = world;
Included = included; Included = included;

View File

@ -1,11 +0,0 @@
using System;
namespace MoonTools.ECS.Rev2;
public readonly record struct Id(uint Value) : IComparable<Id>
{
public int CompareTo(Id other)
{
return Value.CompareTo(other.Value);
}
}

View File

@ -7,7 +7,7 @@ internal class IdAssigner
uint Next; uint Next;
NativeArray<uint> AvailableIds = new NativeArray<uint>(); NativeArray<uint> AvailableIds = new NativeArray<uint>();
public Id Assign() public uint Assign()
{ {
if (!AvailableIds.TryPop(out var id)) if (!AvailableIds.TryPop(out var id))
{ {
@ -15,12 +15,12 @@ internal class IdAssigner
Next += 1; Next += 1;
} }
return new Id(id); return id;
} }
public void Unassign(Id id) public void Unassign(uint id)
{ {
AvailableIds.Add(id.Value); AvailableIds.Add(id);
} }
public void CopyTo(IdAssigner other) public void CopyTo(IdAssigner other)

View File

@ -10,25 +10,25 @@ internal class RelationStorage
{ {
internal NativeArray relations; internal NativeArray relations;
internal NativeArray relationDatas; internal NativeArray relationDatas;
internal Dictionary<(Id, Id), int> indices = new Dictionary<(Id, Id), int>(16); internal Dictionary<(EntityId, EntityId), int> indices = new Dictionary<(EntityId, EntityId), int>(16);
internal Dictionary<Id, IndexableSet<Id>> outRelations = new Dictionary<Id, IndexableSet<Id>>(16); internal Dictionary<EntityId, IndexableSet<EntityId>> outRelations = new Dictionary<EntityId, IndexableSet<EntityId>>(16);
internal Dictionary<Id, IndexableSet<Id>> inRelations = new Dictionary<Id, IndexableSet<Id>>(16); internal Dictionary<EntityId, IndexableSet<EntityId>> inRelations = new Dictionary<EntityId, IndexableSet<EntityId>>(16);
private Stack<IndexableSet<Id>> listPool = new Stack<IndexableSet<Id>>(); private Stack<IndexableSet<EntityId>> listPool = new Stack<IndexableSet<EntityId>>();
private bool disposed; private bool disposed;
public RelationStorage(int relationDataSize) public RelationStorage(int relationDataSize)
{ {
relations = new NativeArray(Unsafe.SizeOf<(Id, Id)>()); relations = new NativeArray(Unsafe.SizeOf<(EntityId, EntityId)>());
relationDatas = new NativeArray(relationDataSize); relationDatas = new NativeArray(relationDataSize);
} }
public ReverseSpanEnumerator<(Id, Id)> All() public ReverseSpanEnumerator<(EntityId, EntityId)> All()
{ {
return new ReverseSpanEnumerator<(Id, Id)>(relations.ToSpan<(Id, Id)>()); return new ReverseSpanEnumerator<(EntityId, EntityId)>(relations.ToSpan<(EntityId, EntityId)>());
} }
public unsafe void Set<T>(in Id entityA, in Id entityB, in T relationData) where T : unmanaged public unsafe void Set<T>(in EntityId entityA, in EntityId entityB, in T relationData) where T : unmanaged
{ {
var relation = (entityA, entityB); var relation = (entityA, entityB);
@ -55,18 +55,18 @@ internal class RelationStorage
indices.Add(relation, relations.Count - 1); indices.Add(relation, relations.Count - 1);
} }
public ref T Get<T>(in Id entityA, in Id entityB) where T : unmanaged public ref T Get<T>(in EntityId entityA, in EntityId entityB) where T : unmanaged
{ {
var relationIndex = indices[(entityA, entityB)]; var relationIndex = indices[(entityA, entityB)];
return ref relationDatas.Get<T>(relationIndex); return ref relationDatas.Get<T>(relationIndex);
} }
public bool Has(Id entityA, Id entityB) public bool Has(EntityId entityA, EntityId entityB)
{ {
return indices.ContainsKey((entityA, entityB)); return indices.ContainsKey((entityA, entityB));
} }
public ReverseSpanEnumerator<Id> OutRelations(Id entityID) public ReverseSpanEnumerator<EntityId> OutRelations(EntityId entityID)
{ {
if (outRelations.TryGetValue(entityID, out var entityOutRelations)) if (outRelations.TryGetValue(entityID, out var entityOutRelations))
{ {
@ -74,16 +74,16 @@ internal class RelationStorage
} }
else else
{ {
return ReverseSpanEnumerator<Id>.Empty; return ReverseSpanEnumerator<EntityId>.Empty;
} }
} }
public Id OutFirst(Id entityID) public EntityId OutFirst(EntityId entityID)
{ {
return OutNth(entityID, 0); return OutNth(entityID, 0);
} }
public Id OutNth(Id entityID, int n) public EntityId OutNth(EntityId entityID, int n)
{ {
#if DEBUG #if DEBUG
if (!outRelations.ContainsKey(entityID) || outRelations[entityID].Count == 0) if (!outRelations.ContainsKey(entityID) || outRelations[entityID].Count == 0)
@ -94,17 +94,17 @@ internal class RelationStorage
return outRelations[entityID][n]; return outRelations[entityID][n];
} }
public bool HasOutRelation(Id entityID) public bool HasOutRelation(EntityId entityID)
{ {
return outRelations.ContainsKey(entityID) && outRelations[entityID].Count > 0; return outRelations.ContainsKey(entityID) && outRelations[entityID].Count > 0;
} }
public int OutRelationCount(Id entityID) public int OutRelationCount(EntityId entityID)
{ {
return outRelations.TryGetValue(entityID, out var entityOutRelations) ? entityOutRelations.Count : 0; return outRelations.TryGetValue(entityID, out var entityOutRelations) ? entityOutRelations.Count : 0;
} }
public ReverseSpanEnumerator<Id> InRelations(Id entityID) public ReverseSpanEnumerator<EntityId> InRelations(EntityId entityID)
{ {
if (inRelations.TryGetValue(entityID, out var entityInRelations)) if (inRelations.TryGetValue(entityID, out var entityInRelations))
{ {
@ -112,16 +112,16 @@ internal class RelationStorage
} }
else else
{ {
return ReverseSpanEnumerator<Id>.Empty; return ReverseSpanEnumerator<EntityId>.Empty;
} }
} }
public Id InFirst(Id entityID) public EntityId InFirst(EntityId entityID)
{ {
return InNth(entityID, 0); return InNth(entityID, 0);
} }
public Id InNth(Id entityID, int n) public EntityId InNth(EntityId entityID, int n)
{ {
#if DEBUG #if DEBUG
if (!inRelations.ContainsKey(entityID) || inRelations[entityID].Count == 0) if (!inRelations.ContainsKey(entityID) || inRelations[entityID].Count == 0)
@ -133,17 +133,17 @@ internal class RelationStorage
return inRelations[entityID][n]; return inRelations[entityID][n];
} }
public bool HasInRelation(Id entityID) public bool HasInRelation(EntityId entityID)
{ {
return inRelations.ContainsKey(entityID) && inRelations[entityID].Count > 0; return inRelations.ContainsKey(entityID) && inRelations[entityID].Count > 0;
} }
public int InRelationCount(Id entityID) public int InRelationCount(EntityId entityID)
{ {
return inRelations.TryGetValue(entityID, out var entityInRelations) ? entityInRelations.Count : 0; return inRelations.TryGetValue(entityID, out var entityInRelations) ? entityInRelations.Count : 0;
} }
public (bool, bool) Remove(in Id entityA, in Id entityB) public (bool, bool) Remove(in EntityId entityA, in EntityId entityB)
{ {
var aEmpty = false; var aEmpty = false;
var bEmpty = false; var bEmpty = false;
@ -177,7 +177,7 @@ internal class RelationStorage
// move an element into the hole // move an element into the hole
if (index != lastElementIndex) if (index != lastElementIndex)
{ {
var lastRelation = relations.Get<(Id, Id)>(lastElementIndex); var lastRelation = relations.Get<(EntityId, EntityId)>(lastElementIndex);
indices[lastRelation] = index; indices[lastRelation] = index;
} }
@ -187,7 +187,7 @@ internal class RelationStorage
return (aEmpty, bEmpty); return (aEmpty, bEmpty);
} }
public void RemoveEntity(in Id entity) public void RemoveEntity(in EntityId entity)
{ {
if (outRelations.TryGetValue(entity, out var entityOutRelations)) if (outRelations.TryGetValue(entity, out var entityOutRelations))
{ {
@ -212,17 +212,17 @@ internal class RelationStorage
} }
} }
internal IndexableSet<Id> AcquireHashSetFromPool() internal IndexableSet<EntityId> AcquireHashSetFromPool()
{ {
if (listPool.Count == 0) if (listPool.Count == 0)
{ {
listPool.Push(new IndexableSet<Id>()); listPool.Push(new IndexableSet<EntityId>());
} }
return listPool.Pop(); return listPool.Pop();
} }
private void ReturnHashSetToPool(IndexableSet<Id> hashSet) private void ReturnHashSetToPool(IndexableSet<EntityId> hashSet)
{ {
hashSet.Clear(); hashSet.Clear();
listPool.Push(hashSet); listPool.Push(hashSet);

View File

@ -9,15 +9,15 @@ public class Snapshot
private Dictionary<ArchetypeSignature, ArchetypeSnapshot> ArchetypeSnapshots = private Dictionary<ArchetypeSignature, ArchetypeSnapshot> ArchetypeSnapshots =
new Dictionary<ArchetypeSignature, ArchetypeSnapshot>(); new Dictionary<ArchetypeSignature, ArchetypeSnapshot>();
private Dictionary<Id, RelationSnapshot> RelationSnapshots = private Dictionary<TypeId, RelationSnapshot> RelationSnapshots =
new Dictionary<Id, RelationSnapshot>(); new Dictionary<TypeId, RelationSnapshot>();
private Dictionary<Id, Record> EntityIndex = new Dictionary<Id, Record>(); private Dictionary<EntityId, Record> EntityIndex = new Dictionary<EntityId, Record>();
private Dictionary<Id, IndexableSet<Id>> EntityRelationIndex = private Dictionary<EntityId, IndexableSet<TypeId>> EntityRelationIndex =
new Dictionary<Id, IndexableSet<Id>>(); new Dictionary<EntityId, IndexableSet<TypeId>>();
private IdAssigner IdAssigner = new IdAssigner(); private IdAssigner EntityIdAssigner = new IdAssigner();
public int Count public int Count
{ {
@ -51,7 +51,7 @@ public class Snapshot
} }
// restore id assigner state // restore id assigner state
IdAssigner.CopyTo(world.IdAssigner); EntityIdAssigner.CopyTo(world.EntityIdAssigner);
// restore relation state // restore relation state
foreach (var (typeId, relationSnapshot) in RelationSnapshots) foreach (var (typeId, relationSnapshot) in RelationSnapshots)
@ -76,7 +76,7 @@ public class Snapshot
public void Take(World world) public void Take(World world)
{ {
// copy id assigner state // copy id assigner state
world.IdAssigner.CopyTo(IdAssigner); world.EntityIdAssigner.CopyTo(EntityIdAssigner);
// copy entity index // copy entity index
EntityIndex.Clear(); EntityIndex.Clear();
@ -103,7 +103,7 @@ public class Snapshot
{ {
if (!EntityRelationIndex.ContainsKey(id)) if (!EntityRelationIndex.ContainsKey(id))
{ {
EntityRelationIndex.Add(id, new IndexableSet<Id>()); EntityRelationIndex.Add(id, new IndexableSet<TypeId>());
} }
EntityRelationIndex[id].Clear(); EntityRelationIndex[id].Clear();
@ -126,7 +126,7 @@ public class Snapshot
archetypeSnapshot.Take(archetype); archetypeSnapshot.Take(archetype);
} }
private void TakeRelationSnapshot(Id typeId, RelationStorage relationStorage) private void TakeRelationSnapshot(TypeId typeId, RelationStorage relationStorage)
{ {
if (!RelationSnapshots.TryGetValue(typeId, out var snapshot)) if (!RelationSnapshots.TryGetValue(typeId, out var snapshot))
{ {
@ -140,14 +140,14 @@ public class Snapshot
private class ArchetypeSnapshot private class ArchetypeSnapshot
{ {
private readonly NativeArray[] ComponentColumns; private readonly NativeArray[] ComponentColumns;
private readonly NativeArray<Id> RowToEntity; private readonly NativeArray<EntityId> RowToEntity;
public int Count => RowToEntity.Count; public int Count => RowToEntity.Count;
public ArchetypeSnapshot(ArchetypeSignature signature) public ArchetypeSnapshot(ArchetypeSignature signature)
{ {
ComponentColumns = new NativeArray[signature.Count]; ComponentColumns = new NativeArray[signature.Count];
RowToEntity = new NativeArray<Id>(); RowToEntity = new NativeArray<EntityId>();
for (int i = 0; i < signature.Count; i += 1) for (int i = 0; i < signature.Count; i += 1)
{ {
@ -185,7 +185,7 @@ public class Snapshot
public RelationSnapshot(int elementSize) public RelationSnapshot(int elementSize)
{ {
Relations = new NativeArray(Unsafe.SizeOf<(Id, Id)>()); Relations = new NativeArray(Unsafe.SizeOf<(EntityId, EntityId)>());
RelationDatas = new NativeArray(elementSize); RelationDatas = new NativeArray(elementSize);
} }
@ -204,7 +204,7 @@ public class Snapshot
for (int index = 0; index < Relations.Count; index += 1) for (int index = 0; index < Relations.Count; index += 1)
{ {
var relation = Relations.Get<(Id, Id)>(index); var relation = Relations.Get<(EntityId, EntityId)>(index);
relationStorage.indices[relation] = index; relationStorage.indices[relation] = index;
relationStorage.indices[relation] = index; relationStorage.indices[relation] = index;

11
src/Rev2/TypeId.cs Normal file
View File

@ -0,0 +1,11 @@
using System;
namespace MoonTools.ECS.Rev2;
public readonly record struct TypeId(uint Value) : IComparable<TypeId>
{
public int CompareTo(TypeId other)
{
return Value.CompareTo(other.Value);
}
}

View File

@ -7,35 +7,35 @@ namespace MoonTools.ECS.Rev2;
public class World : IDisposable public class World : IDisposable
{ {
// Get ComponentId from a Type // Get TypeId from a Type
internal static Dictionary<Type, Id> TypeToId = new Dictionary<Type, Id>(); internal static Dictionary<Type, TypeId> TypeToId = new Dictionary<Type, TypeId>();
// Get element size from a ComponentId // Get element size from a TypeId
internal static Dictionary<Id, int> ElementSizes = new Dictionary<Id, int>(); internal static Dictionary<TypeId, int> ElementSizes = new Dictionary<TypeId, int>();
// Lookup from ArchetypeSignature to Archetype // Lookup from ArchetypeSignature to Archetype
internal Dictionary<ArchetypeSignature, Archetype> ArchetypeIndex = new Dictionary<ArchetypeSignature, Archetype>(); internal Dictionary<ArchetypeSignature, Archetype> ArchetypeIndex = new Dictionary<ArchetypeSignature, Archetype>();
// Going from EntityId to Archetype and storage row // Going from EntityId to Archetype and storage row
internal Dictionary<Id, Record> EntityIndex = new Dictionary<Id, Record>(); internal Dictionary<EntityId, Record> EntityIndex = new Dictionary<EntityId, Record>();
// Relation Storages // Relation Storages
internal Dictionary<Id, RelationStorage> RelationIndex = internal Dictionary<TypeId, RelationStorage> RelationIndex =
new Dictionary<Id, RelationStorage>(); new Dictionary<TypeId, RelationStorage>();
// Entity Relation Tracking // Entity Relation Tracking
internal Dictionary<Id, IndexableSet<Id>> EntityRelationIndex = internal Dictionary<EntityId, IndexableSet<TypeId>> EntityRelationIndex =
new Dictionary<Id, IndexableSet<Id>>(); new Dictionary<EntityId, IndexableSet<TypeId>>();
// Message Storages // Message Storages
private Dictionary<Id, MessageStorage> MessageIndex = private Dictionary<TypeId, MessageStorage> MessageIndex =
new Dictionary<Id, MessageStorage>(); new Dictionary<TypeId, MessageStorage>();
// Filters with a single Include type for Singleton/Some implementation // Filters with a single Include type for Singleton/Some implementation
private Dictionary<Id, Filter> SingleTypeFilters = new Dictionary<Id, Filter>(); private Dictionary<TypeId, Filter> SingleTypeFilters = new Dictionary<TypeId, Filter>();
// ID Management // ID Management
// FIXME: Entity and Type Ids should be separated internal IdAssigner EntityIdAssigner = new IdAssigner();
internal IdAssigner IdAssigner = new IdAssigner(); internal IdAssigner TypeIdAssigner = new IdAssigner();
internal readonly Archetype EmptyArchetype; internal readonly Archetype EmptyArchetype;
@ -67,28 +67,28 @@ public class World : IDisposable
return archetype; return archetype;
} }
public Id CreateEntity(string tag = "") public EntityId CreateEntity(string tag = "")
{ {
var entityId = IdAssigner.Assign(); var entityId = new EntityId(EntityIdAssigner.Assign());
EntityIndex.Add(entityId, new Record(EmptyArchetype, EmptyArchetype.Count)); EntityIndex.Add(entityId, new Record(EmptyArchetype, EmptyArchetype.Count));
EmptyArchetype.RowToEntity.Add(entityId); EmptyArchetype.RowToEntity.Add(entityId);
if (!EntityRelationIndex.ContainsKey(entityId)) if (!EntityRelationIndex.ContainsKey(entityId))
{ {
EntityRelationIndex.Add(entityId, new IndexableSet<Id>()); EntityRelationIndex.Add(entityId, new IndexableSet<TypeId>());
} }
return entityId; return entityId;
} }
internal Id GetTypeId<T>() where T : unmanaged internal TypeId GetTypeId<T>() where T : unmanaged
{ {
if (TypeToId.ContainsKey(typeof(T))) if (TypeToId.ContainsKey(typeof(T)))
{ {
return TypeToId[typeof(T)]; return TypeToId[typeof(T)];
} }
var typeId = IdAssigner.Assign(); var typeId = new TypeId(TypeIdAssigner.Assign());
TypeToId.Add(typeof(T), typeId); TypeToId.Add(typeof(T), typeId);
ElementSizes.Add(typeId, Unsafe.SizeOf<T>()); ElementSizes.Add(typeId, Unsafe.SizeOf<T>());
return typeId; return typeId;
@ -104,12 +104,12 @@ public class World : IDisposable
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private Id GetComponentId<T>() where T : unmanaged private TypeId GetComponentId<T>() where T : unmanaged
{ {
return TypeToId[typeof(T)]; return TypeToId[typeof(T)];
} }
private void RegisterRelationType(Id typeId) private void RegisterRelationType(TypeId typeId)
{ {
RelationIndex.Add(typeId, new RelationStorage(ElementSizes[typeId])); RelationIndex.Add(typeId, new RelationStorage(ElementSizes[typeId]));
} }
@ -131,7 +131,7 @@ public class World : IDisposable
// Messages // Messages
private Id GetMessageTypeId<T>() where T : unmanaged private TypeId GetMessageTypeId<T>() where T : unmanaged
{ {
var typeId = GetTypeId<T>(); var typeId = GetTypeId<T>();
@ -176,7 +176,7 @@ public class World : IDisposable
} }
// Components // Components
public bool Has<T>(Id entityId) where T : unmanaged public bool Has<T>(EntityId entityId) where T : unmanaged
{ {
var componentId = GetComponentId<T>(); var componentId = GetComponentId<T>();
var record = EntityIndex[entityId]; var record = EntityIndex[entityId];
@ -190,7 +190,7 @@ public class World : IDisposable
} }
// will throw if non-existent // will throw if non-existent
public unsafe ref T Get<T>(Id entityId) where T : unmanaged public unsafe ref T Get<T>(EntityId entityId) where T : unmanaged
{ {
var componentId = GetComponentId<T>(); var componentId = GetComponentId<T>();
@ -217,7 +217,7 @@ public class World : IDisposable
throw new InvalidOperationException("No component of this type exists!"); throw new InvalidOperationException("No component of this type exists!");
} }
public Id GetSingletonEntity<T>() where T : unmanaged public EntityId GetSingletonEntity<T>() where T : unmanaged
{ {
var componentId = GetComponentId<T>(); var componentId = GetComponentId<T>();
@ -232,7 +232,7 @@ public class World : IDisposable
throw new InvalidOperationException("No entity with this component type exists!"); throw new InvalidOperationException("No entity with this component type exists!");
} }
public unsafe void Set<T>(in Id entityId, in T component) where T : unmanaged public unsafe void Set<T>(in EntityId entityId, in T component) where T : unmanaged
{ {
TryRegisterComponentId<T>(); TryRegisterComponentId<T>();
var componentId = GetComponentId<T>(); var componentId = GetComponentId<T>();
@ -251,7 +251,7 @@ public class World : IDisposable
} }
} }
private void Add<T>(Id entityId, in T component) where T : unmanaged private void Add<T>(EntityId entityId, in T component) where T : unmanaged
{ {
Archetype? nextArchetype; Archetype? nextArchetype;
@ -290,7 +290,7 @@ public class World : IDisposable
column.Append(component); column.Append(component);
} }
public void Remove<T>(Id entityId) where T : unmanaged public void Remove<T>(EntityId entityId) where T : unmanaged
{ {
Archetype? nextArchetype; Archetype? nextArchetype;
@ -322,7 +322,7 @@ public class World : IDisposable
MoveEntityToLowerArchetype(entityId, row, archetype, nextArchetype, componentId); MoveEntityToLowerArchetype(entityId, row, archetype, nextArchetype, componentId);
} }
public void Relate<T>(in Id entityA, in Id entityB, in T relation) where T : unmanaged public void Relate<T>(in EntityId entityA, in EntityId entityB, in T relation) where T : unmanaged
{ {
TryRegisterRelationType<T>(); TryRegisterRelationType<T>();
var relationStorage = GetRelationStorage<T>(); var relationStorage = GetRelationStorage<T>();
@ -331,83 +331,77 @@ public class World : IDisposable
EntityRelationIndex[entityB].Add(TypeToId[typeof(T)]); EntityRelationIndex[entityB].Add(TypeToId[typeof(T)]);
} }
public void Unrelate<T>(in Id entityA, in Id entityB) where T : unmanaged public void Unrelate<T>(in EntityId entityA, in EntityId entityB) where T : unmanaged
{ {
var relationStorage = GetRelationStorage<T>(); var relationStorage = GetRelationStorage<T>();
relationStorage.Remove(entityA, entityB); relationStorage.Remove(entityA, entityB);
} }
public void UnrelateAll<T>(in Id entity) where T : unmanaged public void UnrelateAll<T>(in EntityId entity) where T : unmanaged
{ {
var relationStorage = GetRelationStorage<T>(); var relationStorage = GetRelationStorage<T>();
relationStorage.RemoveEntity(entity); relationStorage.RemoveEntity(entity);
} }
public bool Related<T>(in Id entityA, in Id entityB) where T : unmanaged public bool Related<T>(in EntityId entityA, in EntityId entityB) where T : unmanaged
{ {
var relationStorage = GetRelationStorage<T>(); var relationStorage = GetRelationStorage<T>();
return relationStorage.Has(entityA, entityB); return relationStorage.Has(entityA, entityB);
} }
public T GetRelationData<T>(in Id entityA, in Id entityB) where T : unmanaged public T GetRelationData<T>(in EntityId entityA, in EntityId entityB) where T : unmanaged
{ {
var relationStorage = GetRelationStorage<T>(); var relationStorage = GetRelationStorage<T>();
return relationStorage.Get<T>(entityA, entityB); return relationStorage.Get<T>(entityA, entityB);
} }
public ReverseSpanEnumerator<(Id, Id)> Relations<T>() where T : unmanaged public ReverseSpanEnumerator<(EntityId, EntityId)> Relations<T>() where T : unmanaged
{ {
var relationStorage = GetRelationStorage<T>(); var relationStorage = GetRelationStorage<T>();
return relationStorage.All(); return relationStorage.All();
} }
public ReverseSpanEnumerator<Id> OutRelations<T>(Id entity) where T : unmanaged public ReverseSpanEnumerator<EntityId> OutRelations<T>(EntityId entity) where T : unmanaged
{ {
var relationStorage = GetRelationStorage<T>(); var relationStorage = GetRelationStorage<T>();
return relationStorage.OutRelations(entity); return relationStorage.OutRelations(entity);
} }
public Id OutRelationSingleton<T>(in Id entity) where T : unmanaged public EntityId OutRelationSingleton<T>(in EntityId entity) where T : unmanaged
{ {
var relationStorage = GetRelationStorage<T>(); var relationStorage = GetRelationStorage<T>();
return relationStorage.OutFirst(entity); return relationStorage.OutFirst(entity);
} }
public bool HasOutRelation<T>(in Id entity) where T : unmanaged public bool HasOutRelation<T>(in EntityId entity) where T : unmanaged
{ {
var relationStorage = GetRelationStorage<T>(); var relationStorage = GetRelationStorage<T>();
return relationStorage.HasOutRelation(entity); return relationStorage.HasOutRelation(entity);
} }
public ReverseSpanEnumerator<Id> InRelations<T>(Id entity) where T : unmanaged public ReverseSpanEnumerator<EntityId> InRelations<T>(EntityId entity) where T : unmanaged
{ {
var relationStorage = GetRelationStorage<T>(); var relationStorage = GetRelationStorage<T>();
return relationStorage.InRelations(entity); return relationStorage.InRelations(entity);
} }
public Id InRelationSingleton<T>(in Id entity) where T : unmanaged public EntityId InRelationSingleton<T>(in EntityId entity) where T : unmanaged
{ {
var relationStorage = GetRelationStorage<T>(); var relationStorage = GetRelationStorage<T>();
return relationStorage.InFirst(entity); return relationStorage.InFirst(entity);
} }
public bool HasInRelation<T>(in Id entity) where T : unmanaged public bool HasInRelation<T>(in EntityId entity) where T : unmanaged
{ {
var relationStorage = GetRelationStorage<T>(); var relationStorage = GetRelationStorage<T>();
return relationStorage.HasInRelation(entity); return relationStorage.HasInRelation(entity);
} }
private bool Has(Id entityId, Id typeId)
{
var record = EntityIndex[entityId];
return record.Archetype.ComponentToColumnIndex.ContainsKey(typeId);
}
// used as a fast path by Archetype.ClearAll and snapshot restore // used as a fast path by Archetype.ClearAll and snapshot restore
internal void FreeEntity(Id entityId) internal void FreeEntity(EntityId entityId)
{ {
EntityIndex.Remove(entityId); EntityIndex.Remove(entityId);
IdAssigner.Unassign(entityId); EntityIdAssigner.Unassign(entityId.Value);
foreach (var relationTypeIndex in EntityRelationIndex[entityId]) foreach (var relationTypeIndex in EntityRelationIndex[entityId])
{ {
@ -418,7 +412,7 @@ public class World : IDisposable
EntityRelationIndex[entityId].Clear(); EntityRelationIndex[entityId].Clear();
} }
public void Destroy(Id entityId) public void Destroy(EntityId entityId)
{ {
var record = EntityIndex[entityId]; var record = EntityIndex[entityId];
var archetype = record.Archetype; var archetype = record.Archetype;
@ -439,7 +433,7 @@ public class World : IDisposable
archetype.RowToEntity.RemoveLastElement(); archetype.RowToEntity.RemoveLastElement();
EntityIndex.Remove(entityId); EntityIndex.Remove(entityId);
IdAssigner.Unassign(entityId); EntityIdAssigner.Unassign(entityId.Value);
foreach (var relationTypeIndex in EntityRelationIndex[entityId]) foreach (var relationTypeIndex in EntityRelationIndex[entityId])
{ {
@ -450,7 +444,7 @@ public class World : IDisposable
EntityRelationIndex[entityId].Clear(); EntityRelationIndex[entityId].Clear();
} }
private void MoveEntityToHigherArchetype(Id entityId, int row, Archetype from, Archetype to) private void MoveEntityToHigherArchetype(EntityId entityId, int row, Archetype from, Archetype to)
{ {
for (int i = 0; i < from.Signature.Count; i += 1) for (int i = 0; i < from.Signature.Count; i += 1)
{ {
@ -479,7 +473,7 @@ public class World : IDisposable
to.RowToEntity.Add(entityId); to.RowToEntity.Add(entityId);
} }
private void MoveEntityToLowerArchetype(Id entityId, int row, Archetype from, Archetype to, Id removed) private void MoveEntityToLowerArchetype(EntityId entityId, int row, Archetype from, Archetype to, TypeId removed)
{ {
for (int i = 0; i < from.Signature.Count; i += 1) for (int i = 0; i < from.Signature.Count; i += 1)
{ {