-
-
Notifications
You must be signed in to change notification settings - Fork 98
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Godot C# GDExtension Roadmap Discussion #7895
Comments
Since I don't see it mentioned anywhere, I just want to paste below the minutes from last week's .NET contributors meetings regarding this specific topic. Note that I'm just quoting, I don't personally share the same opinion on all of the points.
|
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as resolved.
This comment was marked as resolved.
For my current/future use case (using C# to heavily modify Godot itself, basically creating a new editor), the extension class workflow would be hugely beneficial, if not outright necessary. |
Quick poll! If you favor script workflow (slightly better usability, but more limited in performance and extensibility), give this comment a 🚀 |
Some questions:
|
I just want to weight in that the current dev experience is pretty comfortable. I usually have my C# IDE on my second screen with the Godot Editor opened from the IDE. There is one odd behavior where the Godot Editor sometimes seems to reset a source file (which I can revert easily) but I'm not entirely sure if that's a problem connected with the general structure. One thing I'd like to know is how dependencies would be resolved in a user-scenario? Let's say I want to publish a tool written in C#, how would the user experience (of those who download said tool) be affected? |
Just going to weigh in that ideally whichever workflow is chosen should avoid Variant/Godot object overhead. I've seen the whole discourse over GC recently and think it was missing the forest for the woods that is having to interface with the engine using an indirect reflection-like system instead of direct function calls. I really think that forcing non-scripting languages to go through a dynamic API is a bad idea in general, strongly typed languages have strong typing for a reason and it should be utilized at every level of the API (including at the FFI point) Thus, I'd advocate for the use of extensions here. |
My opinion is that if you're using C# in the first place, you're only worrying about performance and maybe third party libraries. I'd wager most C# developers care more about the former. On that point, whatever allows greater performance (or enables code which can facilitate greater performance), should be the option chosen. Developer usability should be prioritised behind this. If we want nice usability, we can just use GDScript. |
Hard disagree here, GDScript is unsuitable for large scale/modular/moddable projects due to lackluster language design (lack of interfaces and composition tools, lack of reliable typing i.e. you can fall back into pure dynamic types pretty easily and no longer get error checking, lack of compile time type verification, etc), but that's another ballpark for another day. |
@Zylann Exposing a [Tool] interface is probably the same, a placeholder class is created and used during editor run. Classes from C++ extension should become available easy if the headers are generated for them, but there is not an easy way to do this yet. Its not technically complex, just that some UI/UX needs to be designed. |
While I don't agree GDScript is badly designed (I believe it seeks different design goals), I think it's true and important to highlight that modularity, scalability and refactorability are important aspects for choosing C#. |
This is really exciting! I just have a few clarifying questions:
Am I understanding correctly that the plan here would be to expose low level APIs directly to C# (in an automated way based on GDE) but that high level APIs would be built on top of this (semi automated) for good user experience? I would generally support that approach. Allowing each language to tailor the API design to its idioms rather than directly exposing GDE seems very important. Is it in scope to make modifications to how the core APIs and GDE work to better support this, for C# and for other languages? For example, is it reasonable to think about defining the core APIs (as registered in ClassDB) to work with very general purpose collection types (maybe even iterator like constructs for array inputs) and for languages to have the freedom to bind to those APIs using whatever wrapper is appropriate? More about the motivation for that is here in my comment on the other thread. To what extent would the plan be to try to retain backcompat with existing C# APIs, and to what extent can this be treated as a blank slate? Would it be reasonable to take a blank slate approach and ship both versions side by side for a while (perhaps billed as Stable and Experimental) so the user can choose one or the other on a per project basis, allowing the freedom to make breaking changes? (A cool feature of shipping a new version as Experimental is that breaking changes could continue in minor releases until it gets upgraded to Stable, giving more freedom to respond to feedback over a longer time period.) |
I mainly asked about the C# side having access to the C++ classes, I suspect C++ depending on C# is way less common in practice. |
This is something we should discuss in general, outside of the context of C#. Now that we have a solution for hot reload, the next thing down the list that people using GDExtension for gameplay code complain about is "everything runs like a tool script!?" :-) We need an answer to this for C++ and all the other languages as well |
This kind of comment is unnecessary. You're just giving assumption what others people cares about. Focus on the thread or speak for yourself. |
A poll given to a tiny subset of Godot's total C# userbase, framed with reasonably biased context from the engine lead? C'mon, this is not useful data. We can surely do better than this.
Let's not go making massive sweeping statements. There are many reasons people want to use C#. It indeed has better library support as you have mentioned. Tooling is more mature - be that the available editors, CI/CD environments, testing tools, build tools, 3rd party developer support etc. Many developers choose C# because they have an existing pool of knowledge they use - whether that's their own existing knowledge a solo dev, or for studios where employees are more likely to have existing C# experience. They might want it as the path of least resistance to convert from Unity, something we've seen a lot of the last few weeks. Outside of a few heavy algorithmic cases (proc gen etc), the engine should be doing all the heavy lifting and the performance of the scripting language is immaterial. The suggestion to make something less usable for everyone in order to benefit those cases seems off the mark. |
The performance of the scripting language is not immaterial. Such a statement does not even make sense. |
In C# this is not so terrible because you can sort of expose the property metadata (type, hints, etc) with a tag, which you can parse from C# itself before instantiating the class, then when instantiating in the editor a placeholder class is supplied that lets you update the properties. In GodotCPP this is kinda a bit harder, you have this information from _bind_methods, so /at least/ this has to be registered. The problem is that when we instantiate a tool class we have to also give a separate placeholder instance that edits those properties. IMO most of this can be solved from the Godot side without that much issue, but will require scratching our heads a bit. |
I would be okay with moving to a GDExtension implementation if (and ONLY if):
I would still prefer a C# entry-point where Godot is used as a library over either approach, but I doubt that would be a popular choice since it would probably take a lot of effort. I also recognize that C# can't be the entry point on all platforms (i.e., consoles), so there would have to be a second type of integration, anyways. |
I want to use GD script, can gdscript converted into c# code 😶🌫️ |
Does this idea or proposal make a difference in the output with Native AOT in dotnet 8? |
Don't crop off the half the context and complain it makes no sense. It was specifically framed with "Outside of a few heavy algorithmic cases...". The scripting language is not doing the heavy lifting in most cases - the engine is. Does it matter if your scripting language is x% quicker if the engine is doing an order of magnitude more work? For most people the answer should be no. It's the same reason there isn't a simple answer when people ask "will my Godot game be faster if I make it in C#?" - it depends. You're arguing to make the experience worse (for everyone) to benefit a small subset of use cases. It's not even all algorithmic cases that benefit either. Its algorithmic operations that do reasonably heavy engine-interop. I'm sure that will benefit some developers. I remain unconvinced however that it will benefit most developers, and I remain less convinced by the argument that it's OK to trade developer usability in exchange for this gain. |
@definitelyokay
Just to clarify, the current binder code and GDExtension are redundant and the same thing. The main advantage of this is that it costs much less to keep C# up to date for contributors.
This was discussed, but ultimately rejected because Godot is not a C# focused engine. There is some ongoing discussions on allowing Godot to be compiled like a library, so it may be usable like this, but using it this way (say you get Godot itself on NuGet) would not be endorsed officially. |
@andy-noisyduck I understand the point you are trying to make, but a large majority of users and contributors want a performance focused C# integration. Its a matter of preference that dictated the priority, from there we work on making the usability as good as possible. |
I agree that the poll may be biased. Most people seeing this proposal are probably the ones that followed last weeks drama and are interested in performance, after all. |
To me this is not script versus class extension, both are good, they are targeting different usage. Going only to the Script Workflow path would be such a waste IMHO. Both would be ideal, but only if the cost of developing/maintaining the script part were low. With the class extension scenario, you can "develop" and not only do small scripts and I think that's what people want and need. C#/.net is a good compromise (at least compared to C++) to develop big projects with good performances. Working with an IDE like Rider and having a hot reload in the Godot editor upon compilation/save in Rider is quite suffisant I think. And if it's not good enough, we should work to improve this, because replicating the user experience of a full-featured IDE like Rider in the Godot editor would be a huge (if not poinless) effort. |
In my opinion, the Extension class approach gives both a better workflow for the users and performance in runtime. Thus, that would be my preference. In fact, if C# classes get registered in ClassDB - unlike GDScript ones - I'd be inclined to do more C# code for Godot in the future (I've been doing GDScript only for over a year now). I'm guessing having both would be too much trouble. In particular regarding whether or not one can switch a project from one to the other. If possible, perhaps some people would find it accesible to prototype with scripts, and then switch for extra performance. I wonder if that would be attractive for people not familiar GDScript (personally I would prototype with GDScript, and C# with extension class workflow seems like a good complement for it, also I remember the advice of migrating CPU intensive parts from GDScript to C# or C++ which makes sense for this and also supports the idea that we would expect performance from C#). I'd rather not have C# using the script workflow only, in that case I would continue using GDScript, yet I understand that for some people GDScript is not an option (let us skip on why and if that makes sense), and I'm guessing this is more for them than for me. About the listed cons, they do not seem too much trouble:
The editor will try to map property values when you change the type of a node from the context menu of the scene dock. Thus, I believe this is already mitigated.
It seems like the main benefit of using the script approach is some safety on this regard. Yet, I'm confident crashes would be worked out in general. Furthermore, if I'm not mistaken, there is already a solution for reloading, which might be improved or supplemented upon if necessary. And any work on this area might also benefit third party language projects, thus, even this is a challenge I think there is an starting point and it would be worth doing. My main concerns would be on breaking compatibility, and how much of this work can actually be done in parallel. I was expecting this would be put off for a while. |
This would be absolutely vital in order to play nice with existing dotnet tooling and enable things like stripping native builds of unused parts. Having a dotnet executable should also make it much easier to stay up to date with the latest dotnet versions as they become available(potentially even being able to support new releases without any changes at all). |
Can we start muting/banning/whatever people that constantly derail discussion? This has been unfortunately common for this proposal in particular, and I'd prefer to not recieve notifications about ongoing flamewars |
I'm temporarily locking this discussion to give the participants time to cool down. @michieal Please keep your interactions constructive and avoid personal attacks. Your own bad experiences with users modding your game is not a valid argument to attack anyone that holds a different opinion than you. @BenMcLean this issue is not the ground of ideological battle pro or against DRM. Please respect other's point of view. |
I deleted all the offtopic comments posted today. If someone wants to discuss modding restrictions and obfuscation, do that in a separate proposal, it's completely offtopic here. And it was pointed out as such, so doubling down and starting to call people names is a breach of our Code of Conduct: https://godotengine.org/code-of-conduct/ So I'm issuing a one-week ban to the user who started this and doubled down. Please be respectful of our discussions and the people involved if you come back afterwards. I'm reopening the proposal for discussion on the topic. Please do not comment further on the offtopic discussion from today. Edit: Geez, locked again, when folks start making sockpuppets to critize moderation, there isn't much room for healthy debate. Additionally, since this proposal has a lot of engagement (80 participants according to GitHub), I ask everyone to keep interactions constructive and strictly on point. Moderation on this issue will be heavy handed. Please keep it civil and be mindful of the amount of people that will receive a notification for every new comment on the proposal. |
NOTE: This proposal aims to be a public technical discussion regarding the future of C# in Godot. The idea is to get help from the community to reach implementation direction consensus.
Describe the project you are working on
Godot C# Bindings
Describe the problem or limitation you are having in your project
The current implementatio of C# in Godot is done on top of the script layer directly and in C++ using the .NET hosting API.
This is due to how Godot worked in version 3. It currently has the following problems:
Describe the feature / enhancement and how it helps to overcome the problem or limitation
The proposed solution is to move C# support to the new extension system in Godot 4.0.
This will give C# in Godot effective first class support at the same level C++ has, bringing the following features:
Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams
NOTE This is a medium term goal for C#. Currently, our immediate priorities are fixing C# support on mobile
and web. What is described in this proposal is work that would happen in parallel.
Ideally, we want to move Godot to use the GDExtension API instead of the
current custom glue glue. Unlike GDExtension, though, we don't want to
depend on a glue API, it should be possible to open the .NET DLL
containing the Godot C# library and have it register itself via the
GDExtension API through a tiny boostrapper that detects if a .net runtime is installed.
This would make the entire C++ side far simpler, easier to maintain,
and easier to implement new features (such as many additions on the
GDExtension side currently are not supported in in the current module, such as GDVIRTUAL,
struct pointers, Godot collections, enhanced performance due to less glue, etc).
Additionally, it would make it easy to have a single Godot executable
and export templates, where C# can be plugged at run-time easily.
Here are the steps to evaluate that would be required to do this:
Creation of a Godot Library in C#
The main idea is that C# should act as if it was a C++ extension. A library
(in the shape of a .net DLL), probably GodotLibrary.dll, can be added to
a project and this automatically is recognized and opened by Godot as if
it was a native shared object, but done actually via the .NET runtime.
In other words, if the C# runtime is installed in the Godot project (or
supplied by the platform to Godot), it is used to open GodotLibrary.dll
and call an entry point that should be the same as a regular GDExtension,
Rewrite the extension interface in C#
Godot has a C extension
interface
defined in C. This extension interface should be available as part of
the GodotLibrary.dll C# source code. Probably something like
ExtensionInterface.cs.
This means making all the structs and C funtions available in unsafe
mode as their C# counterparts.
Binder generation
Once we have the extension interface defined in C#, we can start working
on the binder generator. Before going into this, I think it's important
to reach consensus on whether we want to generate the bindings as scripts or
extension.
Bindings as extension or script?
Godot has two possible workflows today and both are supported in GDExtension: Script Workflow and Class Extension Wokflow.
Normally, script workflow is very quick and intuitive for GDScripts, as the steps to create a new script are:
Blazingly fast. In contrast, for C# the script workflow is more cumbersome:
The alternative is to implement C# using the Class Extension workflow. This workflow is the one compiled languages like GodotCPP, Rust, Swift, etc. uses.
In C#, it would work like this:
As you can see, when using compiled languages, there are not significant differences.
The question is, should C# using script or extension class bindings?
Here are the pros and const:
Script
Pros:
Cons:
Extension class
Pros:
Cons:
Should we use Script or Class extension workflow? That is up to you community.
My personal recommendation would be to go with Class Extension workflow primarily due to performance reasons. With this workflow you will be able to always have optimal performance in all situations and the alternations to ease of use are very minimal.
EDIT: I added a small poll a few coments below.
I put together a quick FAQ:
New Bindings Generator
The new bindings generator would comprise of the following parts:
ExtensionInterface
As mentioned before, the
extension_interace
file from Godot rewritten in C# as ExtensionInterface.cs.
Everything else will use this and it replaces the glue/ code in the
existing modules/mono codebase.
Glue
The C# side of the glue that previously existed in mono/glue, which will
need to be used by both Godot Types and the bindings generator. This
talks to ExtensionInterface.cs to ensure that types such as
Callable, Signal and a few low level behaviors in the class bindings can
be implemented properly.
Godot Types
These are the basic Godot types (Vector3, Vector4, Transform2D, etc)
exposed to C#. They are currently located in this
directory.
As mentioned before, not all need to be written natively, some now can
be done 100% by using the binding generator.
The Godot collections (the way C# calls Godot PackedArrays, Array,
Dictionary) currently are not properly implemented in C#, C# always does
conversion from native C# types to Godot types on every call. Ideally
this should be kept because it makes the API easier to use, but all the
Godot array types and dictionary should be properly supported as
Godot.Collections. This will allow properly implementing proposal
#7842.
Additionally, as mentioned, some may need minor changes, such as
Callable or Signal, which now need to use ExtensionInterface.cs.
Bindings Generator
This is the largest part of the work. The new bindings generator can
be written in Python, C# or whathever decided best. It takes an
extension_api.json file and dumps the whole Godot API as C#.
All the classes, utility functions (currently hardcoded), and several
other binding information is used to create the Godot API in C# entirely
in procedural form. Again, no C++ glue code should be needed anymore. Everything accessed via ExtensionInterface.cs.
Additionally, this should use the compatibility hashes system in
GDExtension, so we can ensure that backward compatibility is also kept
in C# when Godot releases new versions.
Currently, Godot C# uses API hashes, again those need to be dropped entirely and API hash support removed from Godot.
Editor Tools
Finally, porting the existing editor tooling to the new system. Most
code probably will remain unmodified.
Boostrapper
A small piece of code to load the .net runtime (if installed by the user), that calls the C# entry point.
Assembling the GodotLibrary.dll
The GodotLibrary.dll will be built from the existing and generated C# files created by the bindings generator script.
On PC platforms, It will be shipped in Godot together with:
C# runtime (where applies)
Respective additions to export templates to enable deploying using C#
Respective tools to help users build C# in their project using the
GodotLibrary (in editor build).
Compiling the game
C# games in Godot would simply be a library compiled against
GodotLibrary.dll and other .net dependencies. This step is the same as now.
Deploying to platforms
An important question here is how will this be ported to different
platforms (iOS, C#, etc).
Essentially, nothing should really change. Platforms that run JIT will
ship with the runtime.
Platforms that use NativeAOT will need to just change how the entry
point is accessed, but all the work is now done inside C#, so all Godot
cares is reaching that entry point and that's it.
Closing words
Thanks for reading the C# roadmap so far. Feel free to discuss what you think in this proposal!
If this enhancement will not be used often, can it be worked around with a few lines of script?
N/A
Is there a reason why this should be core and not an add-on in the asset library?
The tiny boostrapper will be core, the rest obtainable separately.
The text was updated successfully, but these errors were encountered: