From fdf5a9176347342f6a6a0b7f50f4730a0a91ff78 Mon Sep 17 00:00:00 2001 From: Andrea Angelini Date: Mon, 26 Feb 2024 11:57:28 +0100 Subject: [PATCH] new archetype parser --- samples/MyBattleground/Program.cs | 50 +++--------- src/World.cs | 122 +++-------------------------- tools/TinyEcs.Generator/Program.cs | 52 ++++++++---- 3 files changed, 61 insertions(+), 163 deletions(-) diff --git a/samples/MyBattleground/Program.cs b/samples/MyBattleground/Program.cs index f8cbafa..76a7f83 100644 --- a/samples/MyBattleground/Program.cs +++ b/samples/MyBattleground/Program.cs @@ -79,7 +79,7 @@ .Set(new Position()) .Set(new Velocity()); -for (int i = 0; i < ENTITIES_COUNT / 1000; i++) +for (int i = 0; i < ENTITIES_COUNT / 1; i++) ecs.Entity() .Set(new Position()) .Set(new Velocity()) @@ -97,58 +97,30 @@ //var cur = (start - last) / 1000f; for (int i = 0; i < 3600; ++i) { - // ecs.Filter>() - // .Query((ref Position pos, ref Velocity vel) => - // { - // pos.X *= vel.X; - // pos.Y *= vel.Y; - // }); - - ecs.System, Position, Velocity>((ref Position pos , ref Velocity vel) => { - pos.X *= vel.X; - pos.Y *= vel.Y; - }); - - // foreach (var archetype in ecs.Query2<(Position, Velocity)>()) - // { - // var column0 = archetype.GetComponentIndex(); - // var column1 = archetype.GetComponentIndex(); - - // foreach (ref readonly var chunk in archetype) - // { - // ref var pos = ref chunk.GetReference(column0); - // ref var vel = ref chunk.GetReference(column1); - - // ref var last2 = ref Unsafe.Add(ref pos, chunk.Count); - - // while (Unsafe.IsAddressLessThan(ref pos, ref last2)) - // { - // pos.X *= vel.X; - // pos.Y *= vel.Y; - - // pos = ref Unsafe.Add(ref pos, 1); - // vel = ref Unsafe.Add(ref vel, 1); - // } - // } - // } + ecs.Filter>() + .Query((ref Position pos, ref Velocity vel) => + { + pos.X *= vel.X; + pos.Y *= vel.Y; + }); // foreach (var archetype in ecs.Filter<(Position, Velocity)>()) // { // var column0 = archetype.GetComponentIndex(); // var column1 = archetype.GetComponentIndex(); - // + // foreach (ref readonly var chunk in archetype) // { // ref var pos = ref chunk.GetReference(column0); // ref var vel = ref chunk.GetReference(column1); - // + // ref var last2 = ref Unsafe.Add(ref pos, chunk.Count); - // + // while (Unsafe.IsAddressLessThan(ref pos, ref last2)) // { // pos.X *= vel.X; // pos.Y *= vel.Y; - // + // pos = ref Unsafe.Add(ref pos, 1); // vel = ref Unsafe.Add(ref vel, 1); // } diff --git a/src/World.cs b/src/World.cs index b5d4d6a..387fa59 100644 --- a/src/World.cs +++ b/src/World.cs @@ -13,7 +13,6 @@ public sealed partial class World : IDisposable private readonly DictionarySlim _typeIndex = new(); private readonly Dictionary _entityNames = new(); private Archetype[] _archetypes = new Archetype[16]; - private Dictionary _cachedArchetypesMatch = new(); private int _archetypeCount; private readonly ComponentComparer _comparer; private readonly Commands _commands; @@ -56,7 +55,6 @@ public void Dispose() _typeIndex.Clear(); _commands.Clear(); _entityNames.Clear(); - _cachedArchetypesMatch.Clear(); Array.Clear(_archetypes, 0, _archetypeCount); _archetypeCount = 0; @@ -339,7 +337,7 @@ public void PrintGraph() public FilterQuery Filter() where TFilter : struct { - return new FilterQuery(_archetypes.AsSpan(0, _archetypeCount)); + return new FilterQuery(this); } public FilterQuery Filter(ReadOnlySpan terms) @@ -348,20 +346,15 @@ public FilterQuery Filter(ReadOnlySpan terms) } public IQueryConstruct QueryBuilder() => new QueryBuilder(this); - - public QueryIterator2 Query2() where TFilter : struct + + internal Archetype? FindArchetype(ulong hash, ReadOnlySpan terms) { - var hash = Lookup.Query.Hash; - - if (!_cachedArchetypesMatch.TryGetValue(hash, out var list)) + if (!_typeIndex.TryGetValue(hash, out var arch)) { - list = new ArchetypeList(_archRoot); - list.Renew(Lookup.Query.Terms.AsSpan()); - - _cachedArchetypesMatch.Add(hash, list); + arch = FindFirst(_archRoot, terms); } - return new QueryIterator2(list); + return arch; } public void System(QueryFilterDelegate fn) @@ -371,11 +364,7 @@ public void System(QueryFilterDelegate fn) var terms = Lookup.Query<(T0, T1), TFilter>.Terms.AsSpan(); var withouts = Lookup.Query<(T0, T1), TFilter>.Withouts; - if (!_typeIndex.TryGetValue(hash, out var arch)) - { - arch = FindFirst(_archRoot, terms); - } - + var arch = FindArchetype(hash, terms); if (arch == null) return; @@ -386,7 +375,7 @@ static void InternalQuery Archetype root, QueryFilterDelegate fn, ReadOnlySpan terms, - ImmutableDictionary withouts + IDictionary withouts ) { if (root.Count > 0) @@ -490,106 +479,21 @@ public bool MoveNext() public readonly QueryInternal GetEnumerator() => this; } -public ref struct QueryIterator2 -{ - private LinkedListNode _current, _next; - - internal QueryIterator2(ArchetypeList list) - { - _next = list.First!; - _current = list.First!; - } - - public readonly Archetype Current => _current.Value; - - public bool MoveNext() - { - _current = _next; - - while (_next != null) - { - _next = _next.Next!; - - if (_next != null && _next.Value.Count == 0) - continue; - - break; - } - - return _current != null; - } - - public readonly QueryIterator2 GetEnumerator() => this; -} - - -internal sealed class ArchetypeList : LinkedList -{ - private readonly Archetype _root; - internal ArchetypeList(Archetype root) => _root = root; - - - public void Renew() where TFilter : struct - { - Renew(Lookup.Query.Terms.AsSpan()); - } - - public void Renew() - where TQuery : struct where TFilter : struct - { - Renew(Lookup.Query.Terms.AsSpan()); - } - - public void Renew(ReadOnlySpan terms) - { - Clear(); - Find(_root, terms, this); - } - - static void Find(Archetype root, ReadOnlySpan terms, ArchetypeList list) - { - var result = root.FindMatch(terms); - if (result < 0) - { - return; - } - - if (result == 0 && root.Count > 0) - { - list.AddLast(root); - } - - var span = CollectionsMarshal.AsSpan(root._edgesRight); - if (span.IsEmpty) - return; - - ref var start = ref MemoryMarshal.GetReference(span); - ref var end = ref Unsafe.Add(ref start, span.Length); - - while (Unsafe.IsAddressLessThan(ref start, ref end)) - { - Find(start.Archetype, terms, list); - - start = ref Unsafe.Add(ref start, 1); - } - } -} - public delegate void QueryFilterDelegateWithEntity(EntityView entity); public readonly ref partial struct FilterQuery where TFilter : struct { - private readonly ReadOnlySpan _archetypes; + private readonly World _world; - internal FilterQuery(ReadOnlySpan archetypes) + internal FilterQuery(World world) { - _archetypes = archetypes; + _world = world; } public void Query(QueryFilterDelegateWithEntity fn) { var terms = Lookup.Query.Terms; - var query = new QueryInternal(_archetypes, terms.AsSpan()); + var query = new QueryInternal(_world.Archetypes, terms.AsSpan()); foreach (var arch in query) { foreach (ref readonly var chunk in arch) @@ -607,7 +511,7 @@ public void Query(QueryFilterDelegateWithEntity fn) public QueryInternal GetEnumerator() { - return new QueryInternal(_archetypes, Lookup.Query.Terms.AsSpan()); + return new QueryInternal(_world.Archetypes, Lookup.Query.Terms.AsSpan()); } } diff --git a/tools/TinyEcs.Generator/Program.cs b/tools/TinyEcs.Generator/Program.cs index 0eb3608..546c253 100644 --- a/tools/TinyEcs.Generator/Program.cs +++ b/tools/TinyEcs.Generator/Program.cs @@ -107,28 +107,50 @@ public partial {className}{filter} sb.AppendLine($@" public void Query<{typeParams}>({delegateName}<{typeParams}> fn) {whereParams} {{ + var hash = Lookup.Query<{(i > 0 ? "(" : "")}{typeParams}{(i > 0 ? ")" : "")}{filterMethod}>.Hash; var terms = Lookup.Query<{(i > 0 ? "(" : "")}{typeParams}{(i > 0 ? ")" : "")}{filterMethod}>.Terms.AsSpan(); - var query = new QueryInternal({(withFilter ? "_archetypes" : "Archetypes")}, terms); - foreach (var arch in query) + var withouts = Lookup.Query<{(i > 0 ? "(" : "")}{typeParams}{(i > 0 ? ")" : "")}{filterMethod}>.Withouts; + var arch = {(withFilter ? "_world." : "")}FindArchetype(hash, terms); + if (arch == null) return; + InternalQuery(arch, fn, terms, withouts); + + static void InternalQuery + ( + Archetype arch, + {delegateName}<{typeParams}> fn, + ReadOnlySpan terms, + IDictionary withouts + ) {{ - // columns - {columnIndices} - - foreach (ref readonly var chunk in arch) + if (arch.Count > 0) {{ - // field list - {fieldList} + {columnIndices} - ref var last = ref Unsafe.Add(ref t0A, chunk.Count); - while (Unsafe.IsAddressLessThan(ref t0A, ref last)) + foreach (ref readonly var chunk in arch) {{ - // sign list - fn({signCallback}); - - // unsafe add list - {advanceField} + {fieldList} + ref var last = ref Unsafe.Add(ref t0A, chunk.Count); + + while (Unsafe.IsAddressLessThan(ref t0A, ref last)) + {{ + fn({signCallback}); + {advanceField} + }} }} }} + + var span = CollectionsMarshal.AsSpan(arch._edgesRight); + + ref var start = ref MemoryMarshal.GetReference(span); + ref var end = ref Unsafe.Add(ref start, span.Length); + + while (Unsafe.IsAddressLessThan(ref start, ref end)) + {{ + if (!withouts.ContainsKey(start.ComponentID)) + InternalQuery(start.Archetype, fn, terms, withouts); + + start = ref Unsafe.Add(ref start, 1); + }} }} }} ");