TinyEcs icon indicating copy to clipboard operation
TinyEcs copied to clipboard

Something like Arch's Source Generator?

Open Shadowblitz16 opened this issue 6 months ago • 3 comments

    [Query][With<Silk.Engine.Components.Silk>]
    public static void UpdateWindow([World] in WorldView world, [Entity]in EntityView entity, [Data]in float deltaTime, ref Silk.Engine.Components.Silk silk)
    {

        if ( silk.Window.IsClosing)
        {
            inWorld.Destroy(inEntity);
        }
        if (!silk.Window.IsClosing) silk.Window.DoEvents();
        if (!silk.Window.IsClosing) silk.Window.DoUpdate();
        if (!silk.Window.IsClosing) silk.Window.DoRender();
    }
}

Maybe this could work with Plugins and Events too.

Shadowblitz16 avatar Sep 06 '25 23:09 Shadowblitz16

If i understand correctly this approach is just for a single query and not for a full system where you can mix more than ISystemParam (query, resource, local, world, etc.). I tried this approach time ago, but I'm not fully satisfied : https://github.com/andreakarasho/TinyEcs/tree/source-gen

andreakarasho avatar Sep 07 '25 07:09 andreakarasho

So I've spent the last days to find something I like and I ended with this solution:

using var ecs = new World();
var scheduler = new Scheduler(ecs);
scheduler.AddPlugin(new TestPlugin() { Count = 10000 });
scheduler.RunOnce();

public sealed class TestPlugin : IPlugin
{
	public int Count { get; init; }

	public void Build(Scheduler scheduler)
	{
		scheduler
			.AddSystems2(Stages.Startup, new SetupAdapter(this))
			.AddSystems2(Stages.Update, new MoveEntitiesAdapter()
				.RunIf(new CanRunAdapter(this)))
			.AddSystem2<PrintSomethingAdapter>(Stages.Update);
	}


	[TinySystem]
	public void Setup(World world)
	{
		for (var i = 0; i < Count; i++)
			world.Entity()
				.Set(new Position())
				.Set(new Velocity());
	}

	[TinySystem]
	public static void MoveEntities(Query<Data<Position, Velocity>> query)
	{
		foreach ((var pos, var vel) in query)
		{
			pos.Ref.X *= vel.Ref.X;
			pos.Ref.Y *= vel.Ref.Y;
		}
	}

	[TinySystem]
	public static void PrintSomething()
		=> Console.WriteLine("Hello from plugin");

	[TinySystem]
	public bool CanRun()
		=> true;
}

What's happen here: A source generator grab all methods marked with TinySystemAttribute and create a class called MethodName + Adapter. The user registers these classes using the .AddSystems2 (and variations). Then the scheduler will call the method (which must be public). Some class needs the IPlugin instance to be passed to their .ctor because the method is not static. It's just a way to allow systems like Setup to access plugin instance customization properties (in this case the Count property).

Feedback appreciated.

andreakarasho avatar Sep 10 '25 16:09 andreakarasho

Ideally systems would loop over components..


public partial static class A
{
    [TinySystem][All<Position, Velocity>]
    private static void MoveEntities(ref Position pos, ref Velocity vel)
    {
    	pos.Ref.X *= vel.Ref.X;
    	pos.Ref.Y *= vel.Ref.Y;
    }
  	
    // plugin example...
    [TinyPlugin]
    private static Build(Scheduler scheduler)
    {
         // MoveEntitiesQuery is auto generated via source generators.
         scheduler.AddSystem(A.MoveEntitiesQuery, Stages.Update)
    }
}
var app = new App();
app.Add(A.BuildPlugin);
app.Run();

Shadowblitz16 avatar Sep 12 '25 23:09 Shadowblitz16