diff --git a/src/Rev2/Compatibility/EntityComponentReader.cs b/src/Rev2/Compatibility/EntityComponentReader.cs new file mode 100644 index 0000000..715c247 --- /dev/null +++ b/src/Rev2/Compatibility/EntityComponentReader.cs @@ -0,0 +1,29 @@ +namespace MoonTools.ECS.Rev2.Compatibility; + +public abstract class EntityComponentReader +{ + protected World World; + + protected EntityComponentReader(World world) + { + World = world; + } + + protected bool Has(in Id entityId) where T : unmanaged => World.Has(entityId); + protected bool Some() where T : unmanaged => World.Some(); + protected ref T Get(in Id entityId) where T : unmanaged => ref World.Get(entityId); + protected ref T GetSingleton() where T : unmanaged => ref World.GetSingleton(); + protected Id GetSingletonEntity() where T : unmanaged => World.GetSingletonEntity(); + + protected ReverseSpanEnumerator<(Id, Id)> Relations() where T : unmanaged => World.Relations(); + protected bool Related(in Id entityA, in Id entityB) where T : unmanaged => World.Related(entityA, entityB); + protected T GetRelationData(in Id entityA, in Id entityB) where T : unmanaged => World.GetRelationData(entityA, entityB); + + protected ReverseSpanEnumerator OutRelations(in Id entity) where T : unmanaged => World.OutRelations(entity); + protected Id OutRelationSingleton(in Id entity) where T : unmanaged => World.OutRelationSingleton(entity); + protected bool HasOutRelation(in Id entity) where T : unmanaged => World.HasOutRelation(entity); + + protected ReverseSpanEnumerator InRelations(in Id entity) where T : unmanaged => World.InRelations(entity); + protected Id InRelationSingleton(in Id entity) where T : unmanaged => World.InRelationSingleton(entity); + protected bool HasInRelation(in Id entity) where T : unmanaged => World.HasInRelation(entity); +} diff --git a/src/Rev2/Compatibility/Manipulator.cs b/src/Rev2/Compatibility/Manipulator.cs new file mode 100644 index 0000000..61bce02 --- /dev/null +++ b/src/Rev2/Compatibility/Manipulator.cs @@ -0,0 +1,13 @@ +namespace MoonTools.ECS.Rev2.Compatibility; + +public class Manipulator : EntityComponentReader +{ + public Manipulator(World world) : base(world) { } + + protected void Set(in Id entity, in TComponent component) where TComponent : unmanaged => World.Set(entity, component); + protected void Remove(in Id entity) where TComponent : unmanaged => World.Remove(entity); + + protected void Unrelate(in Id entityA, in Id entityB) where TRelationKind : unmanaged => World.Unrelate(entityA, entityB); + protected void UnrelateAll(in Id entity) where TRelationKind : unmanaged => World.UnrelateAll(entity); + protected void Destroy(in Id entity) => World.Destroy(entity); +} diff --git a/src/Rev2/Compatibility/Renderer.cs b/src/Rev2/Compatibility/Renderer.cs new file mode 100644 index 0000000..6d06b31 --- /dev/null +++ b/src/Rev2/Compatibility/Renderer.cs @@ -0,0 +1,6 @@ +namespace MoonTools.ECS.Rev2.Compatibility; + +public class Renderer : EntityComponentReader +{ + public Renderer(World world) : base(world) { } +} diff --git a/src/Rev2/Compatibility/System.cs b/src/Rev2/Compatibility/System.cs new file mode 100644 index 0000000..7490f4d --- /dev/null +++ b/src/Rev2/Compatibility/System.cs @@ -0,0 +1,13 @@ +using System; + +namespace MoonTools.ECS.Rev2.Compatibility; + +public class System : Manipulator +{ + public System(World world) : base(world) { } + + protected ReadOnlySpan ReadMessages() where T : unmanaged => World.ReadMessages(); + protected T ReadMessage() where T : unmanaged => World.ReadMessage(); + protected bool SomeMessage() where T : unmanaged => World.SomeMessage(); + protected void Send(T message) where T : unmanaged => World.Send(message); +} diff --git a/src/Rev2/FilterBuilder.cs b/src/Rev2/FilterBuilder.cs index 1a986c7..a8c0595 100644 --- a/src/Rev2/FilterBuilder.cs +++ b/src/Rev2/FilterBuilder.cs @@ -24,15 +24,13 @@ public ref struct FilterBuilder public FilterBuilder Include() where T : unmanaged { - World.GetTypeId(); - Included.Add(World.TypeToId[typeof(T)]); + Included.Add(World.GetTypeId()); return new FilterBuilder(World, Included, Excluded); } public FilterBuilder Exclude() where T : unmanaged { - World.GetTypeId(); - Excluded.Add(World.TypeToId[typeof(T)]); + Excluded.Add(World.GetTypeId()); return new FilterBuilder(World, Included, Excluded); } diff --git a/src/Rev2/RelationStorage.cs b/src/Rev2/RelationStorage.cs index ec56601..b249b17 100644 --- a/src/Rev2/RelationStorage.cs +++ b/src/Rev2/RelationStorage.cs @@ -187,7 +187,7 @@ internal class RelationStorage return (aEmpty, bEmpty); } - public void RemoveEntity(Id entity) + public void RemoveEntity(in Id entity) { if (outRelations.TryGetValue(entity, out var entityOutRelations)) { diff --git a/src/Rev2/World.cs b/src/Rev2/World.cs index 0ff71f9..864aa39 100644 --- a/src/Rev2/World.cs +++ b/src/Rev2/World.cs @@ -18,9 +18,6 @@ public class World : IDisposable // Going from EntityId to Archetype and storage row internal Dictionary EntityIndex = new Dictionary(); - // Going from ComponentId to Archetype list - Dictionary> ComponentIndex = new Dictionary>(); - // Relation Storages internal Dictionary RelationIndex = new Dictionary(); @@ -33,6 +30,9 @@ public class World : IDisposable private Dictionary MessageIndex = new Dictionary(); + // Filters with a single Include type for Singleton/Some implementation + private Dictionary SingleTypeFilters = new Dictionary(); + // ID Management // FIXME: Entity and Type Ids should be separated internal IdAssigner IdAssigner = new IdAssigner(); @@ -60,7 +60,6 @@ public class World : IDisposable for (int i = 0; i < signature.Count; i += 1) { var componentId = signature[i]; - ComponentIndex[componentId].Add(archetype); archetype.ComponentToColumnIndex.Add(componentId, i); archetype.ComponentColumns[i] = new NativeArray(ElementSizes[componentId]); } @@ -68,7 +67,7 @@ public class World : IDisposable return archetype; } - public Id CreateEntity() + public Id CreateEntity(string tag = "") { var entityId = IdAssigner.Assign(); EntityIndex.Add(entityId, new Record(EmptyArchetype, EmptyArchetype.Count)); @@ -98,9 +97,9 @@ public class World : IDisposable private void TryRegisterComponentId() where T : unmanaged { var typeId = GetTypeId(); - if (!ComponentIndex.ContainsKey(typeId)) + if (!SingleTypeFilters.ContainsKey(typeId)) { - ComponentIndex.Add(typeId, new List()); + SingleTypeFilters.Add(typeId, FilterBuilder.Include().Build()); } } @@ -184,6 +183,12 @@ public class World : IDisposable return record.Archetype.ComponentToColumnIndex.ContainsKey(componentId); } + public bool Some() where T : unmanaged + { + var componentTypeId = GetComponentId(); + return SingleTypeFilters[componentTypeId].Count > 0; + } + // will throw if non-existent public unsafe ref T Get(Id entityId) where T : unmanaged { @@ -196,6 +201,37 @@ public class World : IDisposable return ref ((T*) column.Elements)[record.Row]; } + public ref T GetSingleton() where T : unmanaged + { + var componentId = GetComponentId(); + + foreach (var archetype in SingleTypeFilters[componentId].Archetypes) + { + if (archetype.Count > 0) + { + var columnIndex = archetype.ComponentToColumnIndex[componentId]; + return ref archetype.ComponentColumns[columnIndex].Get(0); + } + } + + throw new InvalidOperationException("No component of this type exists!"); + } + + public Id GetSingletonEntity() where T : unmanaged + { + var componentId = GetComponentId(); + + foreach (var archetype in SingleTypeFilters[componentId].Archetypes) + { + if (archetype.Count > 0) + { + return archetype.RowToEntity[0]; + } + } + + throw new InvalidOperationException("No entity with this component type exists!"); + } + public unsafe void Set(in Id entityId, in T component) where T : unmanaged { TryRegisterComponentId(); @@ -301,6 +337,12 @@ public class World : IDisposable relationStorage.Remove(entityA, entityB); } + public void UnrelateAll(in Id entity) where T : unmanaged + { + var relationStorage = GetRelationStorage(); + relationStorage.RemoveEntity(entity); + } + public bool Related(in Id entityA, in Id entityB) where T : unmanaged { var relationStorage = GetRelationStorage(); @@ -325,12 +367,36 @@ public class World : IDisposable return relationStorage.OutRelations(entity); } + public Id OutRelationSingleton(in Id entity) where T : unmanaged + { + var relationStorage = GetRelationStorage(); + return relationStorage.OutFirst(entity); + } + + public bool HasOutRelation(in Id entity) where T : unmanaged + { + var relationStorage = GetRelationStorage(); + return relationStorage.HasOutRelation(entity); + } + public ReverseSpanEnumerator InRelations(Id entity) where T : unmanaged { var relationStorage = GetRelationStorage(); return relationStorage.InRelations(entity); } + public Id InRelationSingleton(in Id entity) where T : unmanaged + { + var relationStorage = GetRelationStorage(); + return relationStorage.InFirst(entity); + } + + public bool HasInRelation(in Id entity) where T : unmanaged + { + var relationStorage = GetRelationStorage(); + return relationStorage.HasInRelation(entity); + } + private bool Has(Id entityId, Id typeId) { var record = EntityIndex[entityId];