From 2b63265e6c85bfc1a2cc8123650bf973ce01dd0b Mon Sep 17 00:00:00 2001 From: andreakarasho Date: Thu, 7 Mar 2024 21:50:27 +0100 Subject: [PATCH] component as entitty --- samples/MyBattleground/Program.cs | 6 ++-- src/Archetype.cs | 12 +++---- src/Commands.cs | 6 ++-- src/ComponentComparer.cs | 4 +-- src/Default.cs | 6 ++-- src/EntityView.cs | 2 +- src/World.cs | 57 ++++++++++++++++++------------- tests/Commands.cs | 2 +- tests/SparseSet.cs | 2 +- tests/TinyEcs.Tests.csproj | 5 +-- 10 files changed, 54 insertions(+), 48 deletions(-) diff --git a/samples/MyBattleground/Program.cs b/samples/MyBattleground/Program.cs index a30d849..56cf9ff 100644 --- a/samples/MyBattleground/Program.cs +++ b/samples/MyBattleground/Program.cs @@ -19,12 +19,14 @@ e.Enable(); enabled = e.IsEnabled(); -ecs.Filter<(Position, Velocity)>() +ecs.Filter<(Position, Velocity, Not)>() .Query((EntityView entity) => { Console.WriteLine(entity.Name()); }); - +ecs.Query((EntityView entity, ref ComponentInfo cmp) => { + Console.WriteLine("cmp {0} size {1}", cmp.ID, cmp.Size); + }); // var e2 = ecs.Entity("Main"); // ref var pp = ref e2.Get(); diff --git a/src/Archetype.cs b/src/Archetype.cs index 78703f9..9112e2d 100644 --- a/src/Archetype.cs +++ b/src/Archetype.cs @@ -69,7 +69,7 @@ public sealed class Archetype internal Archetype( World world, - ReadOnlySpan components, + ReadOnlySpan components, ComponentComparer comparer ) { @@ -97,7 +97,7 @@ ComponentComparer comparer public World World => _world; public int Count => _count; - public readonly ImmutableArray Components; + public readonly ImmutableArray Components; internal Span Chunks => _chunks.AsSpan(0, (_count + CHUNK_THRESHOLD - 1) / CHUNK_THRESHOLD); internal int EmptyChunks => _chunks.Length - Chunks.Length; @@ -127,7 +127,7 @@ public ChunkEnumerator GetEnumerator() } [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal int GetComponentIndex(ref readonly EcsComponent cmp) + internal int GetComponentIndex(ref readonly ComponentInfo cmp) { return GetComponentIndex(cmp.ID); } @@ -180,8 +180,8 @@ internal EcsID Remove(ref EcsRecord record) internal Archetype InsertVertex( Archetype left, - ReadOnlySpan components, - ref readonly EcsComponent component + ReadOnlySpan components, + ref readonly ComponentInfo component ) { var vertex = new Archetype(left._world, components, _comparer); @@ -303,7 +303,7 @@ private void InsertVertex(Archetype newNode) MakeEdges(newNode, this, Components[i].ID); } - private bool IsSuperset(ReadOnlySpan other) + private bool IsSuperset(ReadOnlySpan other) { int i = 0, j = 0; while (i < Components.Length && j < other.Length) diff --git a/src/Commands.cs b/src/Commands.cs index 62d93f6..cf6d115 100644 --- a/src/Commands.cs +++ b/src/Commands.cs @@ -69,7 +69,7 @@ public ref T Set(EcsID id, T component) where T : struct return ref Unsafe.As(ref objRef); } - private ref object Set(EcsID id, ref readonly EcsComponent cmp) + private ref object Set(EcsID id, ref readonly ComponentInfo cmp) { EcsAssert.Assert(_main.Exists(id)); @@ -130,7 +130,7 @@ public void Merge() { EcsAssert.Assert(_main.Exists(set.Entity)); - var cmp = new EcsComponent(set.Component, set.DataLength); + var cmp = new ComponentInfo(set.Component, set.DataLength); ref var record = ref _main.GetRecord(set.Entity); var array = _main.Set(_main.Entity(set.Entity), ref record, in cmp); @@ -144,7 +144,7 @@ public void Merge() { EcsAssert.Assert(_main.Exists(unset.Entity)); - var cmp = new EcsComponent(unset.Component, unset.ComponentSize); + var cmp = new ComponentInfo(unset.Component, unset.ComponentSize); _main.DetachComponent(unset.Entity, ref cmp); } diff --git a/src/ComponentComparer.cs b/src/ComponentComparer.cs index e9afac2..0d1003f 100644 --- a/src/ComponentComparer.cs +++ b/src/ComponentComparer.cs @@ -1,6 +1,6 @@ namespace TinyEcs; -sealed class ComponentComparer : IComparer, IComparer, IComparer +sealed class ComponentComparer : IComparer, IComparer, IComparer { private readonly World _world; @@ -10,7 +10,7 @@ public ComponentComparer(World world) } - public int Compare(EcsComponent x, EcsComponent y) + public int Compare(ComponentInfo x, ComponentInfo y) { return CompareTerms(_world, x.ID, y.ID); } diff --git a/src/Default.cs b/src/Default.cs index 5d8d77f..6a9e1b3 100644 --- a/src/Default.cs +++ b/src/Default.cs @@ -1,16 +1,14 @@ namespace TinyEcs; [DebuggerDisplay("ID: {ID}, Size: {Size}")] -public readonly struct EcsComponent +public readonly struct ComponentInfo { public readonly ulong ID; public readonly int Size; - internal EcsComponent(ulong id, int size) + internal ComponentInfo(ulong id, int size) { ID = id; Size = size; } } - -public readonly struct EcsDisabled { } diff --git a/src/EntityView.cs b/src/EntityView.cs index 0cbf9a8..c07d9ff 100644 --- a/src/EntityView.cs +++ b/src/EntityView.cs @@ -77,7 +77,7 @@ public readonly EntityView Unset() where T : struct } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly ReadOnlySpan Type() => World.GetType(ID); + public readonly ReadOnlySpan Type() => World.GetType(ID); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly ref T Get() where T : struct => ref World.Get(ID); diff --git a/src/World.cs b/src/World.cs index ce46874..c5f1c97 100644 --- a/src/World.cs +++ b/src/World.cs @@ -5,9 +5,6 @@ namespace TinyEcs; public sealed partial class World : IDisposable { - const ulong ECS_MAX_COMPONENT_FAST_ID = 256; - const ulong ECS_START_USER_ENTITY_DEFINE = ECS_MAX_COMPONENT_FAST_ID; - private readonly Archetype _archRoot; private readonly EntitySparseSet _entities = new(); private readonly DictionarySlim _typeIndex = new(); @@ -15,27 +12,26 @@ public sealed partial class World : IDisposable private int _archetypeCount; private readonly ComponentComparer _comparer; private readonly Commands _commands; - private int _frame; - private EcsID _lastCompID = 1; + private readonly EcsID _maxCmpId; - public World() + public World(ulong maxComponentId = 256) { _comparer = new ComponentComparer(this); _archRoot = new Archetype( this, - ReadOnlySpan.Empty, + ReadOnlySpan.Empty, _comparer ); _commands = new(this); - //InitializeDefaults(); - //_entities.MaxID = ECS_START_USER_ENTITY_DEFINE; + _maxCmpId = maxComponentId; + _entities.MaxID = maxComponentId; OnPluginInitialization?.Invoke(this); } public event Action? OnEntityCreated, OnEntityDeleted; - public event Action? OnComponentSet, OnComponentUnset; + public event Action? OnComponentSet, OnComponentUnset; public static event Action? OnPluginInitialization; @@ -73,10 +69,18 @@ static void InternalOptimize(Archetype root) } } - public unsafe ref readonly EcsComponent Component() where T : struct + public ref readonly ComponentInfo Component() where T : struct { ref readonly var lookup = ref Lookup.Component.Value; + EcsAssert.Panic(lookup.ID < _maxCmpId); + + if (!Exists(lookup.ID)) + { + var e = Entity(lookup.ID) + .Set(lookup); + } + // if (lookup.ID == 0 || !Exists(lookup.ID)) // { // EcsID id = lookup.ID; @@ -129,6 +133,11 @@ public unsafe ref readonly EcsComponent Component() where T : struct // return entity; // } + public EntityView Entity() where T : struct + { + return Entity(Component().ID); + } + public EntityView Entity(EcsID id = default) { return id == 0 || !Exists(id) ? NewEmpty(id) : new(this, id); @@ -181,7 +190,7 @@ public bool Exists(EcsID entity) return _entities.Contains(entity); } - internal void DetachComponent(EcsID entity, ref readonly EcsComponent cmp) + internal void DetachComponent(EcsID entity, ref readonly ComponentInfo cmp) { OnComponentUnset?.Invoke(Entity(entity), cmp); ref var record = ref GetRecord(entity); @@ -190,7 +199,7 @@ internal void DetachComponent(EcsID entity, ref readonly EcsComponent cmp) private bool InternalAttachDetach( ref EcsRecord record, - ref readonly EcsComponent cmp, + ref readonly ComponentInfo cmp, bool add ) { @@ -207,7 +216,7 @@ bool add } [SkipLocalsInit] - private Archetype? AttachToArchetype(Archetype root, ref readonly EcsComponent cmp, bool add) + private Archetype? AttachToArchetype(Archetype root, ref readonly ComponentInfo cmp, bool add) { if (!add && root.GetComponentIndex(in cmp) < 0) return null; @@ -216,8 +225,8 @@ bool add var cmpCount = Math.Max(0, initType.Length + (add ? 1 : -1)); const int STACKALLOC_SIZE = 16; - EcsComponent[]? buffer = null; - scoped var span = cmpCount <= STACKALLOC_SIZE ? stackalloc EcsComponent[STACKALLOC_SIZE] : (buffer = ArrayPool.Shared.Rent(cmpCount)); + ComponentInfo[]? buffer = null; + scoped var span = cmpCount <= STACKALLOC_SIZE ? stackalloc ComponentInfo[STACKALLOC_SIZE] : (buffer = ArrayPool.Shared.Rent(cmpCount)); span = span[..cmpCount]; @@ -249,12 +258,12 @@ bool add } if (buffer != null) - ArrayPool.Shared.Return(buffer); + ArrayPool.Shared.Return(buffer); return arch; } - private ref Archetype? GetArchetype(Span components, bool create) + private ref Archetype? GetArchetype(Span components, bool create) { var hash = Hashing.Calculate(components); ref var arch = ref Unsafe.NullRef(); @@ -280,7 +289,7 @@ bool add return ref arch; } - internal Array? Set(EntityView entity, ref EcsRecord record, ref readonly EcsComponent cmp) + internal Array? Set(EntityView entity, ref EcsRecord record, ref readonly ComponentInfo cmp) { var emit = false; var column = record.Archetype.GetComponentIndex(in cmp); @@ -303,13 +312,13 @@ bool add return array; } - internal bool Has(EcsID entity, ref readonly EcsComponent cmp) + internal bool Has(EcsID entity, ref readonly ComponentInfo cmp) { ref var record = ref GetRecord(entity); return record.Archetype.GetComponentIndex(in cmp) >= 0; } - public ReadOnlySpan GetType(EcsID id) + public ReadOnlySpan GetType(EcsID id) { ref var record = ref GetRecord(id); return record.Archetype.Components.AsSpan(); @@ -509,7 +518,7 @@ public QueryInternal Build() internal static class Hashing { - public static ulong Calculate(ReadOnlySpan components) + public static ulong Calculate(ReadOnlySpan components) { var hc = (ulong)components.Length; foreach (ref readonly var val in components) @@ -552,9 +561,9 @@ internal static class Component where T : struct { public static readonly int Size = GetSize(); public static readonly string Name = typeof(T).ToString(); - public static readonly ulong HashCode = (ulong)System.Threading.Interlocked.Increment(ref Unsafe.As(ref _index)) - 1; + public static readonly ulong HashCode = (ulong)System.Threading.Interlocked.Increment(ref Unsafe.As(ref _index)) - 0; - public static readonly EcsComponent Value = new EcsComponent(HashCode, Size); + public static readonly ComponentInfo Value = new ComponentInfo(HashCode, Size); static Component() { diff --git a/tests/Commands.cs b/tests/Commands.cs index eb54426..e3929ef 100644 --- a/tests/Commands.cs +++ b/tests/Commands.cs @@ -19,7 +19,7 @@ public void Merge_Create_Entity() cmd.Merge(); Assert.True(ctx.World.Exists(e.ID)); - Assert.False(ctx.World.Has(e.ID)); + Assert.False(ctx.World.Has(e.ID)); } [Fact] diff --git a/tests/SparseSet.cs b/tests/SparseSet.cs index c0ab345..0549d7a 100644 --- a/tests/SparseSet.cs +++ b/tests/SparseSet.cs @@ -23,7 +23,7 @@ public void SparseSet_Add(int amount) [Fact] public void SparseSet_Recycle() { - var set = new EntitySparseSet(); + var set = new EntitySparseSet(); int count = 1000; var genCount = 100; var ids = new List(); diff --git a/tests/TinyEcs.Tests.csproj b/tests/TinyEcs.Tests.csproj index f060762..17fd470 100644 --- a/tests/TinyEcs.Tests.csproj +++ b/tests/TinyEcs.Tests.csproj @@ -23,12 +23,9 @@ - - - - +