Skip to content

Commit

Permalink
new archetype parser
Browse files Browse the repository at this point in the history
  • Loading branch information
Andrea Angelini committed Feb 26, 2024
1 parent 8da3a32 commit fdf5a91
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 163 deletions.
50 changes: 11 additions & 39 deletions samples/MyBattleground/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@
.Set<Position>(new Position())
.Set<Velocity>(new Velocity());

for (int i = 0; i < ENTITIES_COUNT / 1000; i++)
for (int i = 0; i < ENTITIES_COUNT / 1; i++)
ecs.Entity()
.Set<Position>(new Position())
.Set<Velocity>(new Velocity())
Expand All @@ -97,58 +97,30 @@
//var cur = (start - last) / 1000f;
for (int i = 0; i < 3600; ++i)
{
// ecs.Filter<With<PlayerTag>>()
// .Query((ref Position pos, ref Velocity vel) =>
// {
// pos.X *= vel.X;
// pos.Y *= vel.Y;
// });

ecs.System<Not<PlayerTag>, 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<Position>();
// var column1 = archetype.GetComponentIndex<Velocity>();

// foreach (ref readonly var chunk in archetype)
// {
// ref var pos = ref chunk.GetReference<Position>(column0);
// ref var vel = ref chunk.GetReference<Velocity>(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<With<PlayerTag>>()
.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<Position>();
// var column1 = archetype.GetComponentIndex<Velocity>();
//

// foreach (ref readonly var chunk in archetype)
// {
// ref var pos = ref chunk.GetReference<Position>(column0);
// ref var vel = ref chunk.GetReference<Velocity>(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);
// }
Expand Down
122 changes: 13 additions & 109 deletions src/World.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ public sealed partial class World : IDisposable
private readonly DictionarySlim<ulong, Archetype> _typeIndex = new();
private readonly Dictionary<string, EcsID> _entityNames = new();
private Archetype[] _archetypes = new Archetype[16];
private Dictionary<ulong, ArchetypeList> _cachedArchetypesMatch = new();
private int _archetypeCount;
private readonly ComponentComparer _comparer;
private readonly Commands _commands;
Expand Down Expand Up @@ -56,7 +55,6 @@ public void Dispose()
_typeIndex.Clear();
_commands.Clear();
_entityNames.Clear();
_cachedArchetypesMatch.Clear();

Array.Clear(_archetypes, 0, _archetypeCount);
_archetypeCount = 0;
Expand Down Expand Up @@ -339,7 +337,7 @@ public void PrintGraph()

public FilterQuery<TFilter> Filter<TFilter>() where TFilter : struct
{
return new FilterQuery<TFilter>(_archetypes.AsSpan(0, _archetypeCount));
return new FilterQuery<TFilter>(this);
}

public FilterQuery Filter(ReadOnlySpan<Term> terms)
Expand All @@ -348,20 +346,15 @@ public FilterQuery Filter(ReadOnlySpan<Term> terms)
}

public IQueryConstruct QueryBuilder() => new QueryBuilder(this);

public QueryIterator2 Query2<TFilter>() where TFilter : struct
internal Archetype? FindArchetype(ulong hash, ReadOnlySpan<Term> terms)
{
var hash = Lookup.Query<TFilter>.Hash;

if (!_cachedArchetypesMatch.TryGetValue(hash, out var list))
if (!_typeIndex.TryGetValue(hash, out var arch))
{
list = new ArchetypeList(_archRoot);
list.Renew(Lookup.Query<TFilter>.Terms.AsSpan());

_cachedArchetypesMatch.Add(hash, list);
arch = FindFirst(_archRoot, terms);
}

return new QueryIterator2(list);
return arch;
}

public void System<TFilter, T0, T1>(QueryFilterDelegate<T0, T1> fn)
Expand All @@ -371,11 +364,7 @@ public void System<TFilter, T0, T1>(QueryFilterDelegate<T0, T1> 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;

Expand All @@ -386,7 +375,7 @@ static void InternalQuery
Archetype root,
QueryFilterDelegate<T0, T1> fn,
ReadOnlySpan<Term> terms,
ImmutableDictionary<ulong, Term> withouts
IDictionary<ulong, Term> withouts
)
{
if (root.Count > 0)
Expand Down Expand Up @@ -490,106 +479,21 @@ public bool MoveNext()
public readonly QueryInternal GetEnumerator() => this;
}

public ref struct QueryIterator2
{
private LinkedListNode<Archetype> _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<Archetype>
{
private readonly Archetype _root;
internal ArchetypeList(Archetype root) => _root = root;


public void Renew<TFilter>() where TFilter : struct
{
Renew(Lookup.Query<TFilter>.Terms.AsSpan());
}

public void Renew<TQuery, TFilter>()
where TQuery : struct where TFilter : struct
{
Renew(Lookup.Query<TQuery, TFilter>.Terms.AsSpan());
}

public void Renew(ReadOnlySpan<Term> terms)
{
Clear();
Find(_root, terms, this);
}

static void Find(Archetype root, ReadOnlySpan<Term> 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<TFilter> where TFilter : struct
{
private readonly ReadOnlySpan<Archetype> _archetypes;
private readonly World _world;

internal FilterQuery(ReadOnlySpan<Archetype> archetypes)
internal FilterQuery(World world)
{
_archetypes = archetypes;
_world = world;
}

public void Query(QueryFilterDelegateWithEntity fn)
{
var terms = Lookup.Query<TFilter>.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)
Expand All @@ -607,7 +511,7 @@ public void Query(QueryFilterDelegateWithEntity fn)

public QueryInternal GetEnumerator()
{
return new QueryInternal(_archetypes, Lookup.Query<TFilter>.Terms.AsSpan());
return new QueryInternal(_world.Archetypes, Lookup.Query<TFilter>.Terms.AsSpan());
}
}

Expand Down
52 changes: 37 additions & 15 deletions tools/TinyEcs.Generator/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Term> terms,
IDictionary<ulong, Term> 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);
}}
}}
}}
");
Expand Down

0 comments on commit fdf5a91

Please sign in to comment.