GithubHelp home page GithubHelp logo

beancheeseburrito / flecs.net Goto Github PK

View Code? Open in Web Editor NEW
83.0 3.0 8.0 2.01 MB

A C# wrapper for flecs

License: MIT License

C# 99.91% Zig 0.09%
bindgen c csharp data-oriented data-oriented-design ecs entity-component-system flecs flecs-csharp game-development game-engine gamedev interop net netcore netstandard21 wrapper

flecs.net's Introduction

Flecs.NET

Flecs.NET is a high-level wrapper for flecs. Low-level bindings to the C api are included and generated with Bindgen.NET. Native libraries are cross-compiled with Vezel-Dev's Zig Toolsets.

Show me the code!

// Copy, paste, and run in a .NET project!

using Flecs.NET.Core;

using World ecs = World.Create();

Entity entity = ecs.Entity()
    .Set<Position>(new(10, 20))
    .Set<Velocity>(new(1, 2));

ecs.Each((ref Position p, ref Velocity v) =>
{
    p.X += v.X;
    p.Y += v.Y;
});

public record struct Position(float X, float Y);
public record struct Velocity(float X, float Y);

Overview

Flecs.NET - High-level C# port of the C++ wrapper

  • Compatible with .NET Standard 2.1 and NativeAOT
  • Near feature parity with the C++ API
  • Struct-based API with minimal GC interaction
  • Supports both unmanaged and managed types as components
  • Implicitly registers components on-the-fly

Flecs.NET.Bindings - Low-level bindings of the C API

  • Build your own wrapper to suite your personal needs
  • Auto-generated bindings for the entire flecs API
  • Fully blittable interface with no runtime marshalling

Flecs.NET.Native - Precompiled native libraries

  • Provides both shared and static libraries for Windows, MacOS, and Linux
  • Packaged with Zig for dependency free cross-compilation everywhere

NuGet

You can download the nuget package and use Flecs.NET right away!

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

dotnet add PROJECT package Flecs.NET.Release --version *-*

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

dotnet add PROJECT package Flecs.NET.Bindings.Release --version *-*

Flecs.NET.Native (Native Libraries): Release | Debug

dotnet add PROJECT package Flecs.NET.Native.Release --version *-*

Flecs.NET provides both release and debug packages for nuget. To include both of them in your project based on your build configuration, use the package references below. The latest stable or prerelease versions will be added to your project.

<Project Sdk="Microsoft.NET.Sdk">

    <PropertyGroup>
        <OutputType>Exe</OutputType>
        <TargetFramework>net7.0</TargetFramework>
    </PropertyGroup>

    <ItemGroup>
        <PackageReference Include="Flecs.NET.Debug" Version="*-*" Condition="'$(Configuration)' == 'Debug'" />
        <PackageReference Include="Flecs.NET.Release" Version="*-*" Condition="'$(Configuration)' == 'Release'" />
    </ItemGroup>

</Project>

GitLab Package Registry

For more up-to-date packages, development builds are available on the GitLab package registry. To add the development feed to your project, add the GitLab link below as a restore source. You can now reference any package version listed here!

<Project Sdk="Microsoft.NET.Sdk">

    <PropertyGroup>
        <OutputType>Exe</OutputType>
        <TargetFramework>net7.0</TargetFramework>
        <RestoreAdditionalProjectSources>https://gitlab.com/api/v4/projects/51698729/packages/nuget/index.json</RestoreAdditionalProjectSources>
    </PropertyGroup>

    <ItemGroup>
        <PackageReference Include="Flecs.NET.Debug" Version="3.2.8-dev-2023-10-30-11-06-14"/>
    </ItemGroup>

</Project>

Warning

Development feed packages may be deleted without warning to free up space.

Unity Package Manager

The Flecs.NET Unity Package is hosted on github and can be downloaded using the URL below.

  • Open the package manager window Window > Package Manager
  • Click the + icon
  • Click Add package from git URL...
  • Enter the Flecs.NET.Unity git URL
https://github.com/BeanCheeseBurrito/Flecs.NET.Unity.git

Note

Only Windows, MacOS, and Linux builds on x64 Mono are supported. IL2CPP, web, and mobile support are planned for the future.

Caution

The Unity package is incomplete and extremely unstable. Flecs.NET is not recommended to be used with the Unity game engine.

Running examples

To run any of the example programs, use dotnet runand set the "Example" property to the example's path relative to the Flecs.NET.Examples project. Each level of the path must be separated by an underscore.

Example:

dotnet run --project src/Flecs.NET.Examples --property:Example=Cpp_Entities_Basics

Building from source

Clone the repo

Clone the repo and it's submodules.

git clone --recursive https://github.com/BeanCheeseBurrito/Flecs.NET.git
cd Flecs.NET

Restore dependencies

Run the following command on the solution to restore all project dependencies.

dotnet restore

Generate bindings

Generate the binding code. Bindings are generated with Bindgen.NET.

Note

The binding generator needs access to system headers on MacOS. Ensure that XCode is installed.

dotnet run --project src/Flecs.NET.Bindgen

Build Flecs.NET

Compile the wrapper and native libraries. The zig compiler will automatically be downloaded and cached in your local nuget package folder. Native libraries will be cross-compiled for linux, macos, and windows.

dotnet build

Reference the project

Reference the project and import the native libraries.

<Project Sdk="Microsoft.NET.Sdk">

    <PropertyGroup>
        <OutputType>Exe</OutputType>
        <TargetFramework>net7.0</TargetFramework>
    </PropertyGroup>

    <Import Project="PATH/Flecs.NET/src/Flecs.NET.Native/Flecs.NET.Native.targets" />

    <ItemGroup>
        <ProjectReference Include="PATH/Flecs.NET/src/Flecs.NET/Flecs.NET.csproj" />
    </ItemGroup>

</Project>

Contributing

Feel free to open an issue or pull request. All contributions are welcome!

Ways to contribute:

  • Bug Fixes/Reports
  • Feature Requests
  • Documentation
  • Examples/Snippets
  • Demos
  • Typo Corrections

flecs.net's People

Contributors

beancheeseburrito avatar seep avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

flecs.net's Issues

[v4] Implement component id lookup support for System.Type

It would be useful in reflection scenarios to allow the user to lookup component ids and execute ECS operations using System.Type. This functionality is required for automatic member registration/serialization/deserialization support. Needs to also support NativeAOT with trimming which might not be possible with the way component registration currently works.

// Example of registering all types in an assembly through reflection.
foreach (Type type in Assembly.GetExecutingAssembly().GetTypes())
    world.Component(type);

Modify examples to use new source-generated Iter/Each callbacks.

The examples were all written before the generic callback source generators were introduced. It would be a good idea to sweep through the examples and use the shorter Each callbacks wherever possible.

Before:

Routine routine = world.Routine(
    filter: world.FilterBuilder()
        .With<Position>()
        .With<Velocity>(),
    callback: (Iter it, int i) =>
    {
        Column<Position> p = it.Field<Position>(1);
        Column<Velocity> v = it.Field<Velocity>(2);

        p[i].X += v[i].X;
        p[i].Y += v[i].Y;
    }
);

After:

Routine routine = world.Routine(
    filter: world.FilterBuilder<Position, Velocity>(),
    callback: (ref Position p, ref Velocity v) =>
    {
        p.X += v.X;
        p.Y += v.Y;
    }
);

Avoid heap allocation with native strings whenever possible

In the current API, strings that need to be passed over to the native side are always allocated on the heap with Marshal.StringToHGlobalAnsi using the NativeString helper struct.

Example:

{
    string managedString = "Hello World";
    using NativeString nativeString = (NativeString)managedString; // Heap allocation
    random_function(nativeString); // NativeStrings are implicitly casted to byte*/sbyte*
    // String is freed at the end of the scope
}

Heap allocations are unnecessary in places where strings are freed immediately after use and should be rewritten to use stack allocated memory instead.

Example:

{
    string managedString = "Hello World";
    byte* nativeString = stackalloc byte[managedString.Length + 1];
    StackAllocString(nativeString, managedString);
    random_function(nativeString);
}

Unity Editor crashes when initializing world with Monitor and Metrics modules

Minimal repro is to add this MonoBehaviour to an empty scene:

using Flecs.NET.Core;
using UnityEngine;

public class FLECSBootstrap : MonoBehaviour
{
    private World world;

    private void Start()
    {
        world = World.Create();

        world.Import<Ecs.Monitor>();
        world.Import<Ecs.Metrics>();
    }

    private void Update()
    {
        world.Progress();
    }
}

Strangely, it only crashes on the second time running the scene. Windows 11 x64 and debug native libs.

Ambiguous definitions of Routine.

I was just trying to crate a pretty basic routine/system:

ecs.Set(new Window());
ecs.Routine<Window>().Each(UpdateWindows);

and got an error at the Routine line saying:

error CS0121: The call is ambiguous between the following methods or properties: 'World.Routine<T0>(FilterBuilder, QueryBuilder, RoutineBuilder, Ecs.IterCallback<T0>?, string)' and 'World.Routine<T0>(FilterBuilder, QueryBuilder, RoutineBuilder, Ecs.EachCallback<T0>?, string)

after looking into it, it seems there are multiple definitions of routine, 4 to be exact, that are the same.

FromJson and ToJson don't seem to work correctly

Hi, first and foremost love the work you're doing for the library!

It seems that FromJson / ToJson don't work so well, as the query from the loaded world never gets executed. The query from the world being saved is executed as it should. Feels like some issues with serialization, but not sure if it's the bindings.

Here's a quick copy-pastable console app with Flecs.NET.Debug

// Create world
using var world = World.Create();

// Create entities in world
for (var index = 0; index < 100; index++)
{
    var country = world.Entity();
    var province = world.Entity();
    country.Add<Country>();
    province.Add<Province>();
    country.Set(new Country()
    {
        Name = ("Hello world from saved and loaded world" + index).ToCharArray()
    });
    province.Set(new Province()
    {
        Name = index
    });
    province.ChildOf(country);
}

// Query entities on saved & loaded world
var query2 = world.QueryBuilder()
    .With<Province>()
    .Build();

query2.Each((Iter it,
             int i,
             ref Province c) =>
{
    var parent = it.Entity(i).Parent();
    Console.WriteLine(parent.Get<Country>().Name); // triggered
});

// Serialization

using var newWorld = World.Create();
var a = newWorld.FromJson(world.ToJson()); // a = true


// Query entities on saved & loaded world
var query = newWorld.QueryBuilder()
    .With<Province>()
    .Build();

query.Each((Iter it,
            int i,
            ref Province c) =>
{
    var parent = it.Entity(i).Parent();
    Console.WriteLine(parent.Get<Country>().Name); // never triggered
});

Support for tick sources?

Are tick sources supported yet?

Here is a C code example, which is useful to ensure that multiple systems are kept in-sync with regard to timing/ticks:

// Create a tick source to be shared across all systems
ecs_entity_t tick_source = ecs_set_interval(world, 0, tick_interval_secs);

// Set tick source for systems
ecs_set_tick_source(world, ecs_id(Move), tick_source);
ecs_set_tick_source(world, ecs_id(Transform), tick_source);

How to register a system that doesn't query for any components?

Let's say I want to create a system that prints delta_time on every tick. How can I do this with Flecs.NET?

Here's how to do it in C:

void S_PrintDeltaTime(ecs_iter_t *it) {
    printf("delta_time %f\n", (double)it->delta_time);
}

// This is the relevant line for this GH question.
ECS_SYSTEM(world, PrintDeltaTime, EcsOnUpdate, 0);

The system above doesn't query for any components which means it won't match any entities, but will still be run once for each call to ecs_progress().

The following attempts didn't work with Flecs.NET:

// Attempt 1: fails at runtime with "fatal: flecs.c: 44682: assert: table != NULL INTERNAL_ERROR"
_world.Routine(
    filter: _world.FilterBuilder(),
    /* ... */);

// Attempt 2: routine is never called
_world.Routine(
    filter: _world.FilterBuilder().With(0),
    /* ... */);

// Attempt 3: routine is never called
_world.Routine(
    filter: _world.FilterBuilder().Term(0),
    /* ... */);

Use C# arrays as pluggable storage for managed types

When pluggable storages are added to flecs, pinned C# arrays should be used as storage for managed types.

Performance - Special unboxing code is required per every iteration in the current design. Using plain C# arrays will remove this overhead and bring the performance of managed component iteration on par with native C# ECS frameworks/libraries.

Memory Allocations - This will greatly reduce memory consumption due to only needing a single GCHandle and Box<T> object to be allocated per column instead of per component.

Debugging - With the current setup, it is not possible to inspect the contents of a column for both managed and unmanaged types inside a debugger due to the GCHandle indirection and unboxing step required for managed objects. Switching to C# array storage will replace the Column<T> type with the Span<T> type and allow the contents of components to be displayed in the debugger.

Pointer APIs - Pointer-based APIs in Flecs.NET are currently restricted to unmanaged types only. This restriction can be removed entirely as using pinned C# arrays will allow us to retrieve pointers to managed component references. This is a prerequisite to being able to properly implement serialization and deserialization for managed types.

// Pointer-based iteration
Query.Iter((Iter it, Position* p, Velocity* v) => { });

// Span-based iteration
Query.Iter((Iter it, Span<Position> p, Span<Velocity> v) => { });

// Get raw pointers to managed objects.
Position* p = e.GetPtr<Position>();

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.