Can you write a GDExtension with C#?

Godot Version

v4.3-stable

Question

I want to write a GDExtension that adds support for the Flecs ECS library. I have been doing a bit of playing around the Godot-cpp for GDExtensions, but I have ran into an issue.

Long story short I want to be add support for Flecs via GDExtensions. But due to the type limitations for Flecs and how Godot handles extending classes in GDScript I need a language that has support for runtime defined classes/structs. Hence my desire to write the extension with C#

Edit: I assume that if it is possible that it would only be compatible with the mono version of the engine

Any help would be appreciated

1 Like

Classes/Structs aren’t a real thing to compiled code, you won’t find runtime defined structs in compiled languages interfacing with C as required in GDExtension. What’s the feature you are trying to implement that cannot be represented without language-level dynamic typing and would be better suited to a GDExtension over scripting?

Flecs uses concrete types for adding components to it’s entities. e.g. flecs::entity e1 = world.entity().set(Position{10, 20}). Once you have one Position you can’t add more, only replace the current one.

To my knowledge when programming in GDScript if I exposed a type called Component then when someone inherits that object it doesn’t suddenly create a new type in C++ that cna be used to add new components.

In C# however you can use the System.Runtime.Emit namespace to actually make new types at runtime. So my intention was that when someone creates a new Component in GDScript, it’s more of a descriptor than the object itself and in the background it would take said component and use runtime reflection to create a real type that can then be used to add new components. In theory anyway

Your scenario sounds vague. What’s your first step?

In general you would need to define components in c++ and build an abstraction layer that allows you to interact with godot (that uses godots classes).

But the far bigger question imo is how do you query your entities?

1 Like

Most of this is theory while reading through the Flecs documentation and my (intermediate) understanding of GDScript

  • So the first step is a World node that would be a warpper around a flecs::world and also exposes the functionality of the library. var my_world = World.new()
    • This would provide all the exposed APIs for handling things like the creation and descruction of new entities as well as adding and removing systems.
  • Then you would have an Entity wrapper. It would be made by getting an Entity from the World Node, e.g. var my_entity = my_world.new_entity()
    • I don’t think this needs to be a node because it wouldn’t be “ticking” each frame on it’s own. So something like inhereting Object or RefCounted should be enough. This wrapper would be where you add and remove components.
    • It’s also where I ran into the first issue. How do you pass a GDScript defined object to C++ and have it recognised as different objects to be able to add them all to an Entity.
  • Then you would have another wrapper for Systems, similar to Entity I think it could be an extension of RefCounted and would contain a query and a function that matches the query handle.
    • GDScript wouldn’t actually directly call the System. There would be a wrapper system in C++ that understands how to call a GDScript function with my_system->call("name_of_system", system_query)
    • Unlike Entities which are created and returned by the World node, with Systems you would define your new system then do something like my_world.add_system(my_system). And the World node would be responsible for setting up the new system on the C++ side of things

That’s the basic setup I had theorised. I am certain I am still missing things. But like I said, the first major blocking issue I came across is the fact that extending objects in GDScript doesn’t make them distinct types in the C++ side of things

Okay, as the first step I would start with a basic but concrete scenario.

The most important thing is from godot’s side is: how do you want to define an entity with it’s components there?
For example: you want to define an enemy entity with a simple position and health component. How do you define that in godot?
Maybe add an EntityNode to make it an entity with PositionComponentNode or something like that.

Since you can’t build “dynamic structs” you will need to define them in the c++ part and just use them internally with flecs. Your representation you use in godot has to be a different godot class (since you want to use it with gdscript).

In general this is the same approach Unity uses with it’s ECS. So you may have a look at that as a reference. It’s integrated in a similar way into the existing game object system.

Thanks, I’m gonna look into the workarounds. I found something that might potentially work, someone has made a godot-dotnet experimental project for writing GDExtensions in C#

Okay, so actually turns out Flecs doesn’t require hardcoded types like I thought it does. Behind the scenes it converts types to integers that are registered with worlds.
I think knowing this I don’t need runtime types, I should be able to do a work around that converts GDScript types to a unique ID that Flecs can use and map the data over

Can you show me how to do that?

Can’t imagine a way to specify components as an integer value. How do you query that component?

Sure, the C api is very verbose compared to the C++ one. There’s a hello world example on their github: here

The ECS_COMPONENT macro appears to be the main bulk of registering a component with an unique ID and it’s size. Once that’s done all queries are done based on that same ID

My new plan is to try and see if I can get a dynamic pointer/size situation working to register the components and pass the data as a pointer