diff --git a/plugins/TinyEcs.Plugins/BevySystems.cs b/plugins/TinyEcs.Plugins/BevySystems.cs new file mode 100644 index 0000000..0250990 --- /dev/null +++ b/plugins/TinyEcs.Plugins/BevySystems.cs @@ -0,0 +1,78 @@ +// using System; +// using System.Collections.Generic; +// using System.Runtime.CompilerServices; +// using TinyEcs; + +// namespace BevySystems; + +// // https://promethia-27.github.io/dependency_injection_like_bevy_from_scratch/introductions.html + +// // public interface ISystemParam +// // { +// // //object Retrieve(Dictionary resources); +// // } + +// public sealed class Res : ISystemParam +// { +// public T Value { get; set; } +// } + +// public interface ISystem +// { +// void Run(Dictionary resources); +// } + +// public sealed class ErasedFunctionSystem : ISystem +// { +// private readonly Action> f; + +// public ErasedFunctionSystem(Action> f) +// { +// this.f = f; +// } + +// public void Run(Dictionary resources) => f(resources); +// } + +// public sealed partial class Scheduler +// { +// private readonly List _systems = new (); +// private readonly Dictionary _resources = new (); + +// public void Run() +// { +// foreach (var system in _systems) +// { +// system.Run(_resources); +// } +// } + +// public void AddSystem(Action system) where T0 : ISystemParam +// { +// var fn = (Dictionary res) => system((T0)res[typeof(T0)]); +// _systems.Add(new ErasedFunctionSystem(fn)); +// } + +// public void AddSystem(Action system) where T0 : ISystemParam where T1 : ISystemParam +// { +// var fn = (Dictionary res) => system((T0)res[typeof(T0)], (T1)res[typeof(T1)]); +// _systems.Add(new ErasedFunctionSystem(fn)); +// } + +// public void AddSystem(Action system) where T0 : ISystemParam where T1 : ISystemParam where T2 : ISystemParam +// { +// var fn = (Dictionary res) => system((T0)res[typeof(T0)], (T1)res[typeof(T1)], (T2)res[typeof(T2)]); +// _systems.Add(new ErasedFunctionSystem(fn)); +// } + + +// public void AddResource(T resource) +// { +// _resources[typeof(Res)] = new Res() { Value = resource }; +// } + +// public void AddSystemParam(T param) where T : ISystemParam +// { +// _resources[typeof(T)] = param; +// } +// } diff --git a/samples/MyBattleground/Program.cs b/samples/MyBattleground/Program.cs index 0edf874..d5bbd13 100644 --- a/samples/MyBattleground/Program.cs +++ b/samples/MyBattleground/Program.cs @@ -6,94 +6,59 @@ const int ENTITIES_COUNT = (524_288 * 2 * 1); -using var ecs = new World(); -var systems = new SystemManager(ecs); -var ff = systems.Add(); - -Console.WriteLine("system name : {0}", ff.Name); - -ecs.Entity(); -ecs.Entity(); - -var e = ecs.Entity("Main") - .Set(new Position() {X = 2}) - .Set(new Velocity()); - - - -var query = ecs.Query<(Position, Velocity), (Not, Not)>(); -query.Each((ref Position pos, ref Velocity vel) => { - -}); - +// Program2.Test(); +//BevySystems2.Program3.Test(); -systems.Update(); -var rabbit = ecs.Entity(); -var eats = ecs.Entity(); -var carrots = ecs.Entity(); -var grass = ecs.Entity(); +using var ecs = new World(); -e.Disable(); -var enabled = e.IsEnabled(); -e.Disable(); -enabled = e.IsEnabled(); -e.Enable(); -enabled = e.IsEnabled(); - -// 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(); +ecs.Entity(); +ecs.Entity(); +ecs.Entity(); +ecs.Entity(); -var child = ecs.Entity("child 0"); -var child2 = ecs.Entity("child 1"); -var child3 = ecs.Entity("child 2"); -e.AddChild(child); -e.AddChild(child2); -child2.AddChild(child3); +var scheduler = new Scheduler(); +// these should be added automatically somehow idk... +scheduler.AddSystemParam(ecs.Query<(Position, Velocity), (Not, Not)>()); +scheduler.AddSystemParam(ecs.Query()); -e.AddChild(child2); -e.AddChild(child3); +scheduler.AddSystem( + ( + Query<(Position, Velocity), (Not, Not)> query0, + Query query1, + Res myText + ) => + { + query0.Each((ref Position pos, ref Velocity vel) => { + pos.X *= vel.X; + pos.Y *= vel.Y; + }); -//child2.Delete(); + query1.Each((ref Position pos) => { }); + Console.WriteLine("What: {0}", myText.Value); + } +); -// e.ClearChildren(); -// ecs.Filter>().Query((EntityView entity, ref Relationship relation) => { -// Console.WriteLine("parent {0} has {1} children", entity.Name(), relation.Count); +// scheduler.AddSystem((Commands commands) => { +// commands.Entity(); // }); -for (var i = 0; i < 5; ++i) -{ - var c = ecs.Entity(); - Console.WriteLine("Add {0}", c.ID); - e.AddChild(c); -} +scheduler.AddResource("oh shit i made it"); +scheduler.Run(); -foreach (var childId in e.Children()) -{ - Console.WriteLine("child {0}", childId); -} +// var e = ecs.Entity("Main") +// .Set(new Position() {X = 2}) +// .Set(new Velocity()); -e.Delete(); -var exists = e.Exists(); -ecs.Entity() - .Set(new Position()) - .Set(new Velocity()); for (int i = 0; i < ENTITIES_COUNT / 1; i++) ecs.Entity() @@ -104,17 +69,16 @@ // .Set() ; -for (var i = 7000; i < 8000 * 2; ++i) - ecs.Entity((ulong)i).Delete(); +// for (var i = 7000; i < 8000 * 2; ++i) +// ecs.Entity((ulong)i).Delete(); + var sw = Stopwatch.StartNew(); var start = 0f; var last = 0f; - while (true) { - //var cur = (start - last) / 1000f; for (int i = 0; i < 3600; ++i) { // ecs.Query<(Position, Velocity)>() @@ -123,10 +87,14 @@ // pos.Y *= vel.Y; // }); - ecs.Each((ref Position pos, ref Velocity vel) => { - pos.X *= vel.X; - pos.Y *= vel.Y; - }); + // ecs.Each((ref Position pos, ref Velocity vel) => { + // pos.X *= vel.X; + // pos.Y *= vel.Y; + // }); + + //ecs.Exec(fn); + + scheduler.Run(); } last = start; @@ -167,25 +135,14 @@ struct Chunk; struct ChunkTile; -sealed class MoveSystem : EcsSystem +class Systemmsss { - private Query? _query; - - public override void OnCreate(World ecs) - { - _query = ecs.Query<(Position, Velocity)>(); - Console.WriteLine("system {0} created", Name); - } - - public override void OnStart(World ecs) + void systemMove(Query<(Position, Velocity), (Not, Not)> q) { - Console.WriteLine("system {0} started", Name); - } - - public override void OnUpdate(World ecs) - { - _query!.Each((ref Position pos, ref Velocity vel) => { - Console.WriteLine("aa"); + q.Each((ref Position pos, ref Velocity vel) => { + pos.X *= vel.X; + pos.Y *= vel.Y; }); } + } diff --git a/src/Commands.cs b/src/Commands.cs index cf6d115..1627f6b 100644 --- a/src/Commands.cs +++ b/src/Commands.cs @@ -2,7 +2,7 @@ namespace TinyEcs; -public sealed class Commands +public sealed class Commands : ISystemParam { private readonly World _main; private readonly EntitySparseSet _despawn; diff --git a/src/DotnetAddons.cs b/src/DotnetAddons.cs index 034cdaa..f0a6a3b 100644 --- a/src/DotnetAddons.cs +++ b/src/DotnetAddons.cs @@ -1,4 +1,100 @@ +#if !NET7_0_OR_GREATER +namespace TinyEcs +{ + public readonly ref struct Ref + { + // + // Summary: + // The 1-length System.Span`1 instance used to track the target T value. + internal readonly Span Span; + + // + // Summary: + // Gets the T reference represented by the current CommunityToolkit.HighPerformance.Ref`1 + // instance. + public ref T Value + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + return ref MemoryMarshal.GetReference(Span); + } + } + + // + // Summary: + // Initializes a new instance of the CommunityToolkit.HighPerformance.Ref`1 struct. + // + // + // Parameters: + // value: + // The reference to the target T value. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Ref(ref T value) + { + Span = MemoryMarshal.CreateSpan(ref value, 1); + } + + // + // Summary: + // Initializes a new instance of the CommunityToolkit.HighPerformance.Ref`1 struct. + // + // + // Parameters: + // pointer: + // The pointer to the target value. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public unsafe Ref(void* pointer) + : this(ref Unsafe.AsRef(pointer)) + { + } + + // + // Summary: + // Implicitly gets the T value from a given CommunityToolkit.HighPerformance.Ref`1 + // instance. + // + // Parameters: + // reference: + // The input CommunityToolkit.HighPerformance.Ref`1 instance. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator T(Ref reference) + { + return reference.Value; + } + } +} +#endif + + #if !NET5_0_OR_GREATER +namespace System.Diagnostics.CodeAnalysis +{ + /// + /// Used to indicate a byref escapes and is not scoped. + /// + /// + /// There are several cases where the C# compiler treats a as implicitly + /// - where the compiler does not allow the to escape the method. + ///
+ /// For example: + /// + /// for instance methods. + /// parameters that refer to types. + /// parameters. + /// + /// This attribute is used in those instances where the should be allowed to escape. + ///
+ [AttributeUsage(AttributeTargets.Method | AttributeTargets.Parameter | AttributeTargets.Property, AllowMultiple = false, Inherited = false)] + public sealed class UnscopedRefAttribute : Attribute + { + /// + /// Initializes a new instance of the class. + /// + public UnscopedRefAttribute() { } + } +} + namespace System.Runtime.CompilerServices { /// diff --git a/src/Query.cs b/src/Query.cs new file mode 100644 index 0000000..d82acdb --- /dev/null +++ b/src/Query.cs @@ -0,0 +1,169 @@ +using System.Collections.Immutable; + +namespace TinyEcs; + +public ref struct QueryInternal +{ + private readonly ReadOnlySpan _archetypes; + private readonly ReadOnlySpan _terms; + private int _index; + + internal QueryInternal(ReadOnlySpan archetypes, ReadOnlySpan terms) + { + _archetypes = archetypes; + _terms = terms; + _index = -1; + } + + public readonly Archetype Current => _archetypes[_index]; + + public bool MoveNext() + { + while (++_index < _archetypes.Length) + { + var arch = _archetypes[_index]; + if (arch.Count > 0) + return true; + } + + return false; + } + + public void Reset() => _index = -1; + + public readonly QueryInternal GetEnumerator() => this; +} + +public delegate void QueryFilterDelegateWithEntity(EntityView entity); + + + +public interface IQueryConstruct +{ + IQueryBuild With() where T : struct; + IQueryBuild With(EcsID id); + IQueryBuild Without() where T : struct; + IQueryBuild Without(EcsID id); +} + +public interface IQueryBuild +{ + Query Build(); +} + +public interface IQuery +{ + +} + + +public sealed class QueryBuilder : IQueryConstruct, IQueryBuild +{ + private readonly World _world; + private readonly HashSet _components = new(); + + internal QueryBuilder(World world) => _world = world; + + public IQueryBuild With() where T : struct + => With(_world.Component().ID); + + public IQueryBuild With(EcsID id) + { + _components.Add(Term.With(id)); + return this; + } + + public IQueryBuild Without() where T : struct + => Without(_world.Component().ID); + + public IQueryBuild Without(EcsID id) + { + _components.Add(Term.Without(id)); + return this; + } + + public Query Build() + { + var terms = _components.ToImmutableArray(); + return _world.GetQuery( + Hashing.Calculate(terms.AsSpan()), + terms, + static (world, terms) => new Query(world, terms) + ); + } +} + + +public sealed partial class Query : Query, ISystemParam + where TQuery : struct +{ + internal Query(World world) : base(world, Lookup.Query.Terms) + { + } +} + +public sealed partial class Query : Query, ISystemParam + where TQuery : struct where TFilter : struct +{ + internal Query(World world) : base(world, Lookup.Query.Terms) + { + } +} + +public partial class Query : IQuery +{ + private readonly World _world; + private readonly ImmutableArray _terms; + private readonly List _matchedArchetypes; + private ulong _lastArchetypeIdMatched = 0; + + internal Query(World world, ImmutableArray terms) + { + _world = world; + _terms = terms; + _matchedArchetypes = new List(); + } + + internal List MatchedArchetypes => _matchedArchetypes; + + internal void Match() + { + var allArchetypes = _world.Archetypes; + + if (allArchetypes.IsEmpty || _lastArchetypeIdMatched == allArchetypes[^1].Id) + return; + + var terms = _terms.AsSpan(); + var first = _world.FindArchetype(Hashing.Calculate(terms)); + if (first == null) + return; + + _lastArchetypeIdMatched = allArchetypes[^1].Id; + _matchedArchetypes.Clear(); + _world.MatchArchetypes(first, terms, _matchedArchetypes); + } + + public QueryInternal GetEnumerator() + { + Match(); + + return new (CollectionsMarshal.AsSpan(_matchedArchetypes), _terms.AsSpan()); + } + + public void Each(QueryFilterDelegateWithEntity fn) + { + foreach (var arch in this) + { + foreach (ref readonly var chunk in arch) + { + ref var entity = ref chunk.Entities[0]; + ref var last = ref Unsafe.Add(ref entity, chunk.Count); + while (Unsafe.IsAddressLessThan(ref entity, ref last)) + { + fn(entity); + entity = ref Unsafe.Add(ref entity, 1); + } + } + } + } +} diff --git a/src/System.cs b/src/System.cs new file mode 100644 index 0000000..5e7405e --- /dev/null +++ b/src/System.cs @@ -0,0 +1,78 @@ +namespace TinyEcs; + +// https://promethia-27.github.io/dependency_injection_like_bevy_from_scratch/introductions.html + +// public interface ISystemParam +// { +// //object Retrieve(Dictionary resources); +// } + +public sealed class Res : ISystemParam +{ + public T Value { get; set; } +} + +public interface ISystem +{ + void Run(Dictionary resources); +} + +public sealed class ErasedFunctionSystem : ISystem +{ + private readonly Action> f; + + public ErasedFunctionSystem(Action> f) + { + this.f = f; + } + + public void Run(Dictionary resources) => f(resources); +} + +public sealed partial class Scheduler +{ + private readonly List _systems = new (); + private readonly Dictionary _resources = new (); + + public Scheduler() + { + + } + + public void Run() + { + foreach (var system in _systems) + { + system.Run(_resources); + } + } + + public void AddSystem(Action system) where T0 : ISystemParam + { + var fn = (Dictionary res) => system((T0)res[typeof(T0)]); + _systems.Add(new ErasedFunctionSystem(fn)); + } + + public void AddSystem(Action system) where T0 : ISystemParam where T1 : ISystemParam + { + var fn = (Dictionary res) => system((T0)res[typeof(T0)], (T1)res[typeof(T1)]); + _systems.Add(new ErasedFunctionSystem(fn)); + } + + public void AddSystem(Action system) where T0 : ISystemParam where T1 : ISystemParam where T2 : ISystemParam + { + var fn = (Dictionary res) => system((T0)res[typeof(T0)], (T1)res[typeof(T1)], (T2)res[typeof(T2)]); + _systems.Add(new ErasedFunctionSystem(fn)); + } + + + public void AddResource(T resource) + { + _resources[typeof(Res)] = new Res() { Value = resource }; + } + + public void AddSystemParam(T param) where T : ISystemParam + { + _resources[typeof(T)] = param; + } +} diff --git a/src/Term.cs b/src/Term.cs index e3c549d..b2ee820 100644 --- a/src/Term.cs +++ b/src/Term.cs @@ -56,8 +56,6 @@ public enum TermOp : byte public static implicit operator Term(Not _) => Term.Without(Lookup.Component.Value.ID); } -public readonly struct Pair : IFilter where T : struct { } - public readonly struct Or : IFilter where T : struct { } public interface IFilter { } diff --git a/src/World.cs b/src/World.cs index 1646083..065496f 100644 --- a/src/World.cs +++ b/src/World.cs @@ -1,9 +1,11 @@ using System.Collections.Immutable; +using System.Formats.Tar; +using System.Reflection; using Microsoft.Collections.Extensions; namespace TinyEcs; -public sealed partial class World : IDisposable +public sealed partial class World : ISystemParam, IDisposable { private readonly Archetype _archRoot; private readonly EntitySparseSet _entities = new(); @@ -331,21 +333,29 @@ public void PrintGraph() _archRoot.Print(); } - public Query Query() where TQuery : struct + public Query Query() where TQuery : struct { - return GetQuery(Lookup.Query.Hash, Lookup.Query.Terms); + return (Query) GetQuery( + Lookup.Query.Hash, + Lookup.Query.Terms, + static (world, _) => new Query(world) + ); } - public Query Query() where TQuery : struct where TFilter : struct + public Query Query() where TQuery : struct where TFilter : struct { - return GetQuery(Lookup.Query.Hash, Lookup.Query.Terms); + return (Query) GetQuery( + Lookup.Query.Hash, + Lookup.Query.Terms, + static (world, _) => new Query(world) + ); } - internal Query GetQuery(ulong hash, ImmutableArray terms) + internal Query GetQuery(ulong hash, ImmutableArray terms, Func, Query> factory) { if (!_cachedQueries.TryGetValue(hash, out var query)) { - query = new Query(this, terms); + query = factory(this, terms); _cachedQueries.Add(hash, query); } @@ -394,156 +404,6 @@ internal void MatchArchetypes(Archetype root, ReadOnlySpan terms, List _archetypes; - private readonly ReadOnlySpan _terms; - private int _index; - - internal QueryInternal(ReadOnlySpan archetypes, ReadOnlySpan terms) - { - _archetypes = archetypes; - _terms = terms; - _index = -1; - } - - public readonly Archetype Current => _archetypes[_index]; - - public bool MoveNext() - { - while (++_index < _archetypes.Length) - { - var arch = _archetypes[_index]; - if (arch.Count > 0) - return true; - } - - return false; - } - - public void Reset() => _index = -1; - - public readonly QueryInternal GetEnumerator() => this; -} - -public delegate void QueryFilterDelegateWithEntity(EntityView entity); - -public partial interface IQuery -{ - void Query(); -} - -public interface IQueryFilter -{ - IQuery Filter() - where T : struct; - - IQuery Filter() - where TQuery : struct - where TFilter : struct; -} - -public interface IQueryConstruct -{ - IQueryBuild With() where T : struct; - IQueryBuild With(EcsID id); - IQueryBuild Without() where T : struct; - IQueryBuild Without(EcsID id); -} - -public interface IQueryBuild -{ - Query Build(); -} - -public sealed class QueryBuilder : IQueryConstruct, IQueryBuild -{ - private readonly World _world; - private readonly HashSet _components = new(); - - internal QueryBuilder(World world) => _world = world; - - public IQueryBuild With() where T : struct - => With(_world.Component().ID); - - public IQueryBuild With(EcsID id) - { - _components.Add(Term.With(id)); - return this; - } - - public IQueryBuild Without() where T : struct - => Without(_world.Component().ID); - - public IQueryBuild Without(EcsID id) - { - _components.Add(Term.Without(id)); - return this; - } - - public Query Build() - { - var terms = _components.ToImmutableArray(); - return _world.GetQuery(Hashing.Calculate(terms.AsSpan()), terms); - } -} - -public sealed partial class Query -{ - private readonly World _world; - private readonly ImmutableArray _terms; - private readonly List _matchedArchetypes; - private ulong _lastArchetypeIdMatched = 0; - - internal Query(World world, ImmutableArray terms) - { - _world = world; - _terms = terms; - _matchedArchetypes = new List(); - } - - internal void Match() - { - var allArchetypes = _world.Archetypes; - - if (allArchetypes.IsEmpty || _lastArchetypeIdMatched == allArchetypes[^1].Id) - return; - - var terms = _terms.AsSpan(); - var first = _world.FindArchetype(Hashing.Calculate(terms)); - if (first == null) - return; - - _lastArchetypeIdMatched = allArchetypes[^1].Id; - _matchedArchetypes.Clear(); - _world.MatchArchetypes(first, terms, _matchedArchetypes); - } - - public QueryInternal GetEnumerator() - { - Match(); - - return new (CollectionsMarshal.AsSpan(_matchedArchetypes), _terms.AsSpan()); - } - - public void Each(QueryFilterDelegateWithEntity fn) - { - foreach (var arch in this) - { - foreach (ref readonly var chunk in arch) - { - ref var entity = ref chunk.Entities[0]; - ref var last = ref Unsafe.Add(ref entity, chunk.Count); - while (Unsafe.IsAddressLessThan(ref entity, ref last)) - { - fn(entity); - entity = ref Unsafe.Add(ref entity, 1); - } - } - } - } -} - internal static class Hashing { public static ulong Calculate(ReadOnlySpan components) @@ -714,3 +574,15 @@ struct EcsRecord public readonly ref ArchetypeChunk GetChunk() => ref Archetype.GetChunk(Row); } + + +internal enum SystemParamType +{ + Query, + QueryWithFilter, +} + +public interface ISystemParam +{ +} + diff --git a/tests/Query.cs b/tests/Query.cs index e5ca2e8..2c24ed3 100644 --- a/tests/Query.cs +++ b/tests/Query.cs @@ -14,7 +14,7 @@ public void Query_AttachOneComponent_WithOneComponent(int amount) ctx.World.Set(ctx.World.Entity(), new FloatComponent()); var done = 0; - foreach (var arch in ctx.World.Filter()) + foreach (var arch in ctx.World.Query()) foreach (ref readonly var chunk in arch) done += chunk.Count; @@ -37,7 +37,7 @@ public void Query_AttachTwoComponents_WithTwoComponents(int amount) } var done = 0; - foreach (var arch in ctx.World.Filter<(FloatComponent, IntComponent)>()) + foreach (var arch in ctx.World.Query<(FloatComponent, IntComponent)>()) foreach (ref readonly var chunk in arch) done += chunk.Count; @@ -61,7 +61,7 @@ public void Query_AttachThreeComponents_WithThreeComponents(int amount) } var done = 0; - foreach (var arch in ctx.World.Filter<(FloatComponent, IntComponent, BoolComponent)>()) + foreach (var arch in ctx.World.Query<(FloatComponent, IntComponent, BoolComponent)>()) foreach (ref readonly var chunk in arch) done += chunk.Count; @@ -85,7 +85,7 @@ public void Query_AttachThreeComponents_WithTwoComponents_WithoutOneComponent(in } var done = 0; - foreach (var arch in ctx.World.Filter<(FloatComponent, IntComponent, Not)>()) + foreach (var arch in ctx.World.Query<(FloatComponent, IntComponent, Not)>()) foreach (ref readonly var chunk in arch) done += chunk.Count; @@ -108,7 +108,7 @@ public void Query_AttachTwoComponents_WithTwoComponents_WithoutOneComponent(int } var done = 0; - foreach (var arch in ctx.World.Filter<(FloatComponent, IntComponent, Not)>()) + foreach (var arch in ctx.World.Query<(FloatComponent, IntComponent, Not)>()) foreach (ref readonly var chunk in arch) done += chunk.Count; @@ -131,7 +131,7 @@ public void Query_AttachTwoComponents_WithOneComponents_WithoutTwoComponent(int } var done = 0; - foreach (var arch in ctx.World.Filter<(FloatComponent, Not, Not)>()) + foreach (var arch in ctx.World.Query<(FloatComponent, Not, Not)>()) foreach (ref readonly var chunk in arch) done += chunk.Count; @@ -167,7 +167,7 @@ public void Query_EdgeValidation() ctx.World.Set(e4); var done = 0; - foreach (var arch in ctx.World.Filter<(FloatComponent, IntComponent, Not, Not)>()) + foreach (var arch in ctx.World.Query<(FloatComponent, IntComponent, Not, Not)>()) foreach (ref readonly var chunk in arch) done += chunk.Count; diff --git a/tools/TinyEcs.Generator/Program.cs b/tools/TinyEcs.Generator/Program.cs index 826674a..db138f4 100644 --- a/tools/TinyEcs.Generator/Program.cs +++ b/tools/TinyEcs.Generator/Program.cs @@ -20,6 +20,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context) postContext.AddSource("TinyEcs.g.cs", CodeFormatter.Format(Generate())); }); + static string Generate() { return $@" @@ -58,27 +59,6 @@ static string GenerateQueryTemplateDelegates(bool withEntityView) return sb.ToString(); } - // static string GenerateQueryInterfaceMethods(string name) - // { - // var sb = new StringBuilder(); - // sb.AppendLine(@$" - // public partial interface {name} - // {{ - // "); - // - // for (var i = 0; i < MAX_GENERICS; ++i) - // { - // var typeParams = GenerateSequence(i + 1, ", ", j => $"T{j}"); - // var whereParams = GenerateSequence(i + 1, " ", j => $"where T{j} : struct"); - // - // sb.AppendLine($"void Each<{typeParams}>(QueryFilterDelegate<{typeParams}> fn) {whereParams};"); - // } - // - // sb.AppendLine("}"); - // - // return sb.ToString(); - // } - static string GenerateFilterQuery(bool withFilter, bool withEntityView) { var className = withFilter ? "class World" : "class Query"; @@ -148,176 +128,6 @@ public partial {className} return sb.ToString(); } - // static string GenerateFilterQuery(bool withFilter, bool withEntityView) - // { - // var className = withFilter ? "struct FilterQuery" : "class World"; - // var filter = withFilter ? "" : ""; - // var filterMethod = withFilter ? ", TFilter" : ""; - // var delegateName = withEntityView ? "QueryFilterDelegateWithEntity" : "QueryFilterDelegate"; - - // var sb = new StringBuilder(); - // sb.AppendLine($@" - // public partial {className}{filter} - // {{ - // "); - - // for (var i = 0; i < MAX_GENERICS; ++i) - // { - // var typeParams = GenerateSequence(i + 1, ", ", j => $"T{j}"); - // var whereParams = GenerateSequence(i + 1, " ",j => $"where T{j} : struct"); - // var columnIndices = GenerateSequence(i + 1, "\n" , j => $"var column{j} = arch.GetComponentIndex();"); - // var fieldList = (withEntityView ? "ref var entityA = ref chunk.Entities[0];\n" : "") + - // GenerateSequence(i + 1, "\n" , j => $"ref var t{j}A = ref chunk.GetReference(column{j});"); - // var signCallback = (withEntityView ? "entityA, " : "") + - // GenerateSequence(i + 1, ", " , j => $"ref t{j}A"); - // var advanceField = (withEntityView ? "entityA = ref Unsafe.Add(ref entityA, 1);\n" : "") + - // GenerateSequence(i + 1, "\n" , j => $"t{j}A = ref Unsafe.Add(ref t{j}A, 1);"); - - // sb.AppendLine($@" - // public void Query<{typeParams}>({delegateName}<{typeParams}> fn) {whereParams} - // {{ - // var terms = Lookup.Query<{(i > 0 ? "(" : "")}{typeParams}{(i > 0 ? ")" : "")}{filterMethod}>.Terms.AsSpan(); - // var query = new QueryInternal({(withFilter ? "_world." : "")}Archetypes, terms); - - // foreach (var arch in query) - // {{ - // {columnIndices} - - // foreach (ref readonly var chunk in arch) - // {{ - // {fieldList} - // ref var last = ref Unsafe.Add(ref t0A, chunk.Count - 4); - // ref var last2 = ref Unsafe.Add(ref t0A, chunk.Count); - - // while (Unsafe.IsAddressLessThan(ref t0A, ref last)) - // {{ - // fn({signCallback}); - // {advanceField} - - // fn({signCallback}); - // {advanceField} - - // fn({signCallback}); - // {advanceField} - - // fn({signCallback}); - // {advanceField} - // }} - - // while (Unsafe.IsAddressLessThan(ref t0A, ref last2)) - // {{ - // fn({signCallback}); - // {advanceField} - // }} - // }} - // }} - // }} - // "); - // } - - // sb.AppendLine("}"); - - // return sb.ToString(); - // } - - // static string GenerateFilterQuery(bool withFilter, bool withEntityView) - // { - // var className = withFilter ? "struct FilterQuery" : "class World"; - // var filter = withFilter ? "" : ""; - // var filterMethod = withFilter ? ", TFilter" : ""; - // var delegateName = withEntityView ? "QueryFilterDelegateWithEntity" : "QueryFilterDelegate"; - - // var sb = new StringBuilder(); - // sb.AppendLine($@" - // public partial {className}{filter} - // {{ - // "); - - // for (var i = 0; i < MAX_GENERICS; ++i) - // { - // var typeParams = GenerateSequence(i + 1, ", ", j => $"T{j}"); - // var whereParams = GenerateSequence(i + 1, " ",j => $"where T{j} : struct"); - // var columnIndices = GenerateSequence(i + 1, "\n" , j => $"var column{j} = arch.GetComponentIndex();"); - // var fieldList = (withEntityView ? "ref var entityA = ref chunk.Entities[0];\n" : "") + - // GenerateSequence(i + 1, "\n" , j => $"ref var t{j}A = ref chunk.GetReference(column{j});"); - // var signCallback = (withEntityView ? "entityA, " : "") + - // GenerateSequence(i + 1, ", " , j => $"ref t{j}A"); - // var advanceField = (withEntityView ? "entityA = ref Unsafe.Add(ref entityA, 1);\n" : "") + - // GenerateSequence(i + 1, "\n" , j => $"t{j}A = ref Unsafe.Add(ref t{j}A, 1);"); - - // 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 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 - // ) - // {{ - // if (arch.Count > 0) - // {{ - // {columnIndices} - - // foreach (ref readonly var chunk in arch) - // {{ - // {fieldList} - // ref var last = ref Unsafe.Add(ref t0A, chunk.Count - 4); - // ref var last2 = ref Unsafe.Add(ref t0A, chunk.Count); - - // while (Unsafe.IsAddressLessThan(ref t0A, ref last)) - // {{ - // fn({signCallback}); - // {advanceField} - - // fn({signCallback}); - // {advanceField} - - // fn({signCallback}); - // {advanceField} - - // fn({signCallback}); - // {advanceField} - // }} - - // while (Unsafe.IsAddressLessThan(ref t0A, ref last2)) - // {{ - // 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); - // }} - // }} - // }} - // "); - // } - - // sb.AppendLine("}"); - - // return sb.ToString(); - // } - static string GenerateSequence(int count, string separator, Func generator) { var sb = new StringBuilder();