Skip to content

Releases: BeanCheeseBurrito/Flecs.NET

v4.0.3

23 Nov 15:16
Compare
Choose a tag to compare

Nuget Packages

Flecs.NET (Wrapper + Bindings + Native Libraries): Release | Debug
Flecs.NET.Bindings (Bindings + Native Libraries): Release | Debug
Flecs.NET.Native (Native Libraries): Release | Debug

New GitHub Package registry

For immediate access to the latest changes, NuGet packages are now pushed to the GitHub Package registry on every commit to the main branch. See the following link for more information. https://github.com/BeanCheeseBurrito/Flecs.NET?tab=readme-ov-file#github-package-registry

Static linking

Flecs can now be statically linked with Native AOT apps using the $(FlecsStaticLink) property when consuming the Flecs.NET NuGet package.

To enable static linking, add <FlecsStaticLink>true</FlecsStaticLink> to a property group. To prevent shared libraries from being copied to the output directory, add ExcludeAssets="native" to your package reference.

<Project Sdk="Microsoft.NET.Sdk">
    <PropertyGroup>
        <PublishAot>true</PublishAot>
        <FlecsStaticLink>true</FlecsStaticLink>
    </PropertyGroup>

    <ItemGroup>
        <PackageReference Include="Flecs.NET.Debug" Version="*-*" ExcludeAssets="native"/>
    </ItemGroup>
</Project>

Entity and Id extensions

All entity and id methods can now be called directly on Alert , Component , Observer , Pipeline , System, TimerEntity , and UntypedComponent . Previously, accessing entity and id methods had to be done through the .Entity and .Id properties.

Old:

world.Component<Phases.Render>().Entity
    .Add(Ecs.Phase)
    .DependsOn(Ecs.OnUpdate);

New:

world.Component<Phases.Render>()
    .Add(Ecs.Phase)
    .DependsOn(Ecs.OnUpdate);

Managed type support for user contexts

The .Ctx() APIs have been changed to support storing managed types as user context for queries, systems, and observers.

Old:

int value = 10;

world.System()
    .Ctx(&value) // Pointer has to be passed.
    .Each(static (Iter it, int _) =>
    {
        ref int ctx = ref it.Ctx<int>();
        Console.WriteLine(ctx); // Prints 10
    });

New:

world.System()
    .Ctx("Context") // Context is passed by value
    .Each(static (Iter it, int _) =>
    {
        ref string ctx = ref it.Ctx<string>();
        Console.WriteLine(ctx); // Prints "String"
    });

A callback can be provided to run clean-up logic before the context object is freed.

world.System()
    .Ctx("Context", static (ref string ctx) =>
    {
        Console.WriteLine("Context is being freed");
    }) 
    .Each(...);

Managed types can now also be used for user data associated with groups.

using Query<Position> q = world.QueryBuilder<Position>()
    .GroupBy<Group>()
    // Callback invoked when a new group is created. Including the third "out T" parameter
    // allows you to provide a user context.
    .OnGroupCreate((World world, ulong id, out GroupCtx ctx) =>
    {
        Console.WriteLine($"Group {world.Entity(id)} created");

        // Set data that will be associated with the group
        ctx = new GroupCtx(groupCounter++);
    })
    // Callback invoked when a group is deleted. Including the third "ref T" parameter
    // provides access to the user context object.
    .OnGroupDelete((World world, ulong id, ref GroupCtx ctx) =>
    {
        Console.WriteLine($"Group {world.Entity(id)} deleted");
    })
    .Build();

Type-checked QueryBuilder.TermAt()

New type-checked versions of QueryBuilder.TermAt() have been added to help ensure the intended field matches the correct type.

world.QueryBuilder<Position, Velocity, Mass>()
    .TermAt<Position>(0).Singleton()
    .TermAt<Velocity>(1).Singleton()
    .TermAt<Velocity>(2).Singleton() // Assertion fails due to mismatched type
    .Each(...);

For simple queries, the field index can be omitted, in which case the first field that matches the type argument is retrieved.

world.QueryBuilder<Position, Velocity, Mass>()
    .TermAt<Velocity>().Singleton() // Matches field index 1
    .Each();

World.AtFini/World.RunPostFrame/AppBuilder.Init

World.AtFini() and World.RunPostFrame() have been updated to only take a World argument. You can no longer pass a user context alongside the callbacks. User data can instead be stored in a static field if needed.
Old:

world.RunPostFrame(static (ecs_world_t*, void*) =>
{
    Console.WriteLine("Frame finished.")
}, null);

world.AtFini(static (ecs_world_t*, void*) =>
{
    Console.WriteLine("World finish.")
}, null);

New:

world.RunPostFrame(static (World world) =>
{
    Console.WriteLine("Frame finished.")
});

world.AtFini(static (World world) =>
{
    Console.WriteLine("World finish.")
});

AppBuilder.Init() now takes a World instead of an ecs_world_t*

Old:

using World world = World.Create();

world.App()
    .Init(Setup)
    .Run();

static void Setup(ecs_world_t* worldPtr)
{
    World world = World.Create(worldPtr);
    world.Import<Module1>();
    world.Import<Module2>();
    world.Import<Module3>();
}

New:

using World world = World.Create();

world.App()
    .Init(Setup)
    .Run();

static void Setup(World world)
{
    world.Import<Module1>();
    world.Import<Module2>();
    world.Import<Module3>();
}

Other

  • Native build script can now output WASM static libraries
  • Longstanding issue with multi-threaded system crashes has been fixed
  • Using Flecs.NET in Native AOT applications works again

What's Changed

New Contributors

Full Changelog: v4.0.2...v4.0.3

v4.0.2

06 Oct 12:40
98a2483
Compare
Choose a tag to compare

Minimum target version bumped to .NET 8

All projects must now target .NET 8 or above. Support for .NET 7 and lower versions have been removed. This change is a prerequisite to implementing pinned array storage for managed types in the future #21. The Unity package will no longer be updated.

New generic query API

A new type-safe generic query API has been added to help reduce common errors relating to queries.

Old:

using Query query = world.Query<Position, Velocity>();
query.Each((ref Position p, ref Velocity v) => { });

New:

using Query<Position, Velocity> query = world.Query<Position, Velocity>();
query.Each((ref Position p, ref Velocity v) => { }); // Parameter types must match the query's type list.

When calling factory methods for query types using type parameters (ex. World.Query<T1, ...>), a generic query object will be returned instead of an untyped query.

  • World.Query<T1, ...>() returns Query<T1, ...>
  • World.QueryBuilder<T1, ...>() returns QueryBuilder<T1, ...>
  • World.Observer<T1, ...> returns Observer<T1, ...>
  • World.System<T1, ...> returns System<T1, ...>

Using tags in the above factory methods is no longer allowed and will trigger an assert in debug mode. Use .With<Tag>() to query for tag types.

public record struct Position(int X, int Y);
public struct Tag;

// Invalid and will trigger assert.
Query<Position, Tag> query = world.QueryBuilder<Position, Tag>()
    .Build()

// Correct
Query<Position> query = world.QueryBuilder<Position>()
    .With<Tag>()
    .Build()

IterIterable, PageIterable, and WorkerIterable types now have generic versions as well.

  • IIterable.Iter() returns IterIterable<T1, ...>
  • IIterable.Page() returns PageIterable<T1, ...>
  • IIterable.Worker() returns WorkerIterable<T1, ...>

Routine renamed to System

Routine and RoutineBuilder have been renamed to System and SystemBuilder to more closely match the C++ API.

System<Position, Velocity> system = world.System<Position, Velocity>()
    .Each((ref Position p, ref Velocity v) =>
    {
        p.X += v.X;
        p.Y += v.Y;
    });

// Systems that contain no type arguments have an underscore at the end to prevent clashing with the System namespace.
System_ system = world.System().Run((Iter it) => { });

System.Type lookup for types

A component's System.Type can now be retrieved through the component's entity by calling .Get<Type>()

// This is equivalent to typeof(string)
Type type = world.Component<string>().Entity.Get<Type>()

Other Breaking Changes

  • Ecs.Routine has been removed. Use Ecs.System instead.
  • RoutineBuilder.RoutineDesc renamed to RoutineBuilder.Desc
  • ObserverBuilder.ObserverDesc renamed to ObserverBuilder.Desc
  • PipelineBuilder.PipelineDesc renamed to PipelineBuilder.Desc
  • AlertBuilder.AlertDesc renamed to PipelineBuilder.Desc
  • AlertBuilder.Id renamed to AlertBuilder.AlertId
  • AlertBuilder.Var renamed to AlertBuilder.AlertVar
  • Entity.Read() callbacks now take ref readonly instead of in modifiers

What's Changed

New Contributors

Full Changelog: v4.0.0...v4.0.2

Nuget Packages

Flecs.NET (Wrapper + Bindings + Native Libraries): Release | Debug
Flecs.NET.Bindings (Bindings + Native Libraries): Release | Debug
Flecs.NET.Native (Native Libraries): Release | Debug

v4.0.0

14 Jul 05:06
Compare
Choose a tag to compare

Nuget Packages

Flecs.NET (Wrapper + Bindings + Native Libraries): Release | Debug
Flecs.NET.Bindings (Bindings + Native Libraries): Release | Debug
Flecs.NET.Native (Native Libraries): Release | Debug

What's Changed

Major changes between v3.2.11 and v4.0.0 are listed here #31

New Contributors

Full Changelog: https://github.com/BeanCheeseBurrito/Flecs.NET/commits/v4.0.0