-
-
Notifications
You must be signed in to change notification settings - Fork 97
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
Auto generate C# bindings for gdextensions #8191
Comments
Working with GDExtensions and C# certainly has been a bit cumbersome! Great proposal! |
Some of our C# users have helped us document how to use Terrain3D in C# and are using it without issue. See the "Detecting" and "Calling" sections. So GDextensions in C# may be inconvenient, but are not inaccessible. |
Is this information available in var terrain = ClassDB.Instantiate("Terrain3D");
terrain.AsGodotObject().Set("storage", ClassDB.Instantiate("Terrain3DStorage"));
terrain.AsGodotObject().Set("texture_list", ClassDB.Instantiate("Terrain3DTextureList"));
terrain.AsGodotObject().Call("set_collision_enabled", true); However, it would probably still be nice if Godot provided an option to include more classes in the C# code generation, as it already has the entire codegen infrastructure in place. This would allow type-safe and idiomatic APIs rather than dynamic ones. Incidentally related: ongoing discussion of porting C# itself to GDExtension: #7895. |
GDExtension classes are registered in ClassDB and we can just retrieve the information needed from there. No need for the GDExtension source code. As mentioned by @Bromeon, any GDExtension class can be consumed using the reflection-like APIs available in We do want to improve support for GDExtensions in C#, which includes creating them as well as consuming them. If we were to use the codegen that exists in the editor (the bindings generator that generates the glue for GodotSharp), then there are a few things to keep in mind:
Also, the proposed workflow assumes GDExtensions are added from the Asset Library using the editor to trigger the C# bindings generation. How would this work if an user places a GDExtension in their projects from outside the editor? For example, if I have a project in GitHub that I download which includes GDExtensions already. I think the bindings generation should be part of the MSBuild compilation, either using Source Generators or MSBuild tasks. I mentioned this before in godot-rust/gdext#166 (comment). |
Would it make sense to have GDExtensions produce their own JSON API document similar to That way extensions could reference each other, rather than relying on the too-late ClassDB registration? Then its something build time for source generators to hook into and would be for more than just dotnet usage: extensions could reference each other. |
This needs some testing, but this may already work to some degree. If you run But even if it does work, this isn't an ideal workflow, since it requires building all your GDExtensions, generating the |
But in this instance of the C# bindings, the build is MSBuild right so assuming the Extensions are already built and registered we could use that as the source instead of ClassDB directly? Edit: that's work thats already happening somewhere right? I've never been able to find where |
suggestion: distribute C# binding as nugetThe following step could only be done by the nuget provider using a GDExtension C# binding addon Ideally
The user only consumes the nuget, no c# binding codes that require unsafe code compilation will be involved
|
Maybe we could modify these steps to work and do a script to automate them ? |
Update to this topic? When will this feature planned? Do you have a recommendation? |
Don't use Anyway, the bindings generator is already in the engine. It requires modifications, but this is most likely not a high priority. |
@mihe => it seems
|
As mentioned in the comment you linked, they're meant to be a workaround. They're pretty much the only alternative available from GDExtension right now, and as pointed out earlier in this thread the situation is similar to interop with GDScript, where you would also rely on |
@DmitriySalnikov => elaborate?
@raulsntos => care to share your latest view? This issue has an impact on Unity Users using c# moving to Godot. |
Just a little experiment that doesn't workC# project, which should be placed in the root of your Godot project: Before building it, you need to build an editor with the patch, run And don't forget to add Patch for 4.2.1: diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp
index 36fdda46255d6dcb256619eab1b7d3619c0e3776..9afd060bbac98652f8fbcee95f458bfc42fe04b8 100644
--- a/modules/mono/editor/bindings_generator.cpp
+++ b/modules/mono/editor/bindings_generator.cpp
@@ -1228,6 +1228,113 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_proj_dir) {
return OK;
}
+Error BindingsGenerator::generate_cs_extensions_project(const String &p_proj_dir) {
+ ERR_FAIL_COND_V(!initialized, ERR_UNCONFIGURED);
+
+ Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ ERR_FAIL_COND_V(da.is_null(), ERR_CANT_CREATE);
+
+ if (!DirAccess::exists(p_proj_dir)) {
+ Error err = da->make_dir_recursive(p_proj_dir);
+ ERR_FAIL_COND_V_MSG(err != OK, ERR_CANT_CREATE, "Cannot create directory '" + p_proj_dir + "'.");
+ }
+
+ da->change_dir(p_proj_dir);
+ da->make_dir("Generated");
+ da->make_dir("Generated/GodotObjects");
+
+ String base_gen_dir = path::join(p_proj_dir, "Generated");
+ String godot_objects_gen_dir = path::join(base_gen_dir, "GodotObjects");
+
+ Vector<String> compile_items;
+
+ for (const KeyValue<StringName, TypeInterface> &E : obj_types) {
+ const TypeInterface &itype = E.value;
+
+ if (itype.api_type != ClassDB::API_EXTENSION) {
+ continue;
+ }
+
+ String output_file = path::join(godot_objects_gen_dir, itype.proxy_name + ".cs");
+ Error err = _generate_cs_type(itype, output_file);
+
+ if (err == ERR_SKIP) {
+ continue;
+ }
+
+ if (err != OK) {
+ return err;
+ }
+
+ compile_items.push_back(output_file);
+ }
+
+ // Generate native calls
+
+ StringBuilder cs_icalls_content;
+
+ cs_icalls_content.append("namespace " BINDINGS_NAMESPACE ";\n\n");
+ cs_icalls_content.append("using System;\n"
+ "using System.Diagnostics.CodeAnalysis;\n"
+ "using System.Runtime.InteropServices;\n"
+ "using Godot.NativeInterop;\n"
+ "\n");
+ cs_icalls_content.append("[SuppressMessage(\"ReSharper\", \"InconsistentNaming\")]\n");
+ cs_icalls_content.append("[SuppressMessage(\"ReSharper\", \"RedundantUnsafeContext\")]\n");
+ cs_icalls_content.append("[SuppressMessage(\"ReSharper\", \"RedundantNameQualifier\")]\n");
+ cs_icalls_content.append("[System.Runtime.CompilerServices.SkipLocalsInit]\n");
+ cs_icalls_content.append("internal static class " BINDINGS_CLASS_NATIVECALLS_EXTENSION "\n{");
+
+ cs_icalls_content.append(MEMBER_BEGIN "internal static ulong godot_api_hash = ");
+ cs_icalls_content.append(String::num_uint64(ClassDB::get_api_hash(ClassDB::API_CORE)) + ";\n");
+
+ cs_icalls_content.append(MEMBER_BEGIN "private const int VarArgsSpanThreshold = 10;\n");
+
+ for (const InternalCall &icall : method_icalls) {
+ if (icall.api_type != ClassDB::API_EXTENSION) {
+ continue;
+ }
+ Error err = _generate_cs_native_calls(icall, cs_icalls_content);
+ if (err != OK) {
+ return err;
+ }
+ }
+
+ cs_icalls_content.append(CLOSE_BLOCK);
+
+ String internal_methods_file = path::join(base_gen_dir, BINDINGS_CLASS_NATIVECALLS_EXTENSION ".cs");
+
+ Error err = _save_file(internal_methods_file, cs_icalls_content);
+ if (err != OK) {
+ return err;
+ }
+
+ compile_items.push_back(internal_methods_file);
+
+ // Generate GeneratedIncludes.props
+
+ StringBuilder includes_props_content;
+ includes_props_content.append("<Project>\n"
+ " <ItemGroup>\n");
+
+ for (int i = 0; i < compile_items.size(); i++) {
+ String include = path::relative_to(compile_items[i], p_proj_dir).replace("/", "\\");
+ includes_props_content.append(" <Compile Include=\"" + include + "\" />\n");
+ }
+
+ includes_props_content.append(" </ItemGroup>\n"
+ "</Project>\n");
+
+ String includes_props_file = path::join(base_gen_dir, "GeneratedIncludes.props");
+
+ err = _save_file(includes_props_file, includes_props_content);
+ if (err != OK) {
+ return err;
+ }
+
+ return OK;
+}
+
Error BindingsGenerator::generate_cs_editor_project(const String &p_proj_dir) {
ERR_FAIL_COND_V(!initialized, ERR_UNCONFIGURED);
@@ -2166,7 +2273,11 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
cs_type = cs_type.substr(0, cs_type.length() - 2);
}
- String def_arg = sformat(iarg.default_argument, cs_type);
+ String def_arg_str = iarg.default_argument;
+ if (iarg.def_param_value.get_type() >= Variant::VECTOR2 && iarg.def_param_value.get_type() < Variant::PROJECTION)
+ def_arg_str = def_arg_str.replace("-inf", "real_t.NegativeInfinity").replace("inf", "real_t.PositiveInfinity");
+
+ String def_arg = sformat(def_arg_str, cs_type);
cs_in_statements << def_arg << ";\n";
@@ -2313,7 +2424,7 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
const InternalCall *im_icall = match->value;
- String im_call = im_icall->editor_only ? BINDINGS_CLASS_NATIVECALLS_EDITOR : BINDINGS_CLASS_NATIVECALLS;
+ String im_call = im_icall->api_type == ClassDB::API_EXTENSION ? BINDINGS_CLASS_NATIVECALLS_EXTENSION : (im_icall->editor_only ? BINDINGS_CLASS_NATIVECALLS_EDITOR : BINDINGS_CLASS_NATIVECALLS);
im_call += ".";
im_call += im_icall->name;
diff --git a/modules/mono/editor/bindings_generator.h b/modules/mono/editor/bindings_generator.h
index aa4e5ea093bc4f80ab7e8b8659807b8065d40deb..d0b0db0cb4f7d4fca2b5c9e3ea46a9d9d1c9ea15 100644
--- a/modules/mono/editor/bindings_generator.h
+++ b/modules/mono/editor/bindings_generator.h
@@ -599,6 +599,7 @@ class BindingsGenerator {
struct InternalCall {
String name;
String unique_sig; // Unique signature to avoid duplicates in containers
+ ClassDB::APIType api_type = ClassDB::API_NONE;
bool editor_only = false;
bool is_vararg = false;
@@ -610,10 +611,11 @@ class BindingsGenerator {
InternalCall() {}
- InternalCall(ClassDB::APIType api_type, const String &p_name, const String &p_unique_sig = String()) {
+ InternalCall(ClassDB::APIType p_api_type, const String &p_name, const String &p_unique_sig = String()) {
name = p_name;
unique_sig = p_unique_sig;
- editor_only = api_type == ClassDB::API_EDITOR;
+ editor_only = p_api_type == ClassDB::API_EDITOR;
+ api_type = p_api_type;
}
inline bool operator==(const InternalCall &p_a) const {
@@ -820,6 +822,7 @@ class BindingsGenerator {
public:
Error generate_cs_core_project(const String &p_proj_dir);
+ Error generate_cs_extensions_project(const String &p_proj_dir);
Error generate_cs_editor_project(const String &p_proj_dir);
Error generate_cs_api(const String &p_output_dir);
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Properties/AssemblyInfo.cs b/modules/mono/glue/GodotSharp/GodotSharp/Properties/AssemblyInfo.cs
index da6f293871089dbd16a5231d691dd124077da796..19beb385a3753f4648225197f99a8afc8942409e 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Properties/AssemblyInfo.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Properties/AssemblyInfo.cs
@@ -1,3 +1,4 @@
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("GodotSharpEditor")]
+[assembly: InternalsVisibleTo("GodotSharpExtensions")]
diff --git a/modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj b/modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj
index 3ceb3b64dc7ece60a774ae03803a7789b21c0d6f..c810c0fb150766314de83dcd657092d556f218b6 100644
--- a/modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj
+++ b/modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj
@@ -37,6 +37,7 @@
<!-- Compat Sources -->
<ItemGroup>
<Compile Include="Compat.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<!--
We import a props file with auto-generated includes. This works well with Rider.
diff --git a/modules/mono/glue/GodotSharp/GodotSharpEditor/Properties/AssemblyInfo.cs b/modules/mono/glue/GodotSharp/GodotSharpEditor/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000000000000000000000000000000000..3caf6f69df4f5a711b697e697ffd5a55bebe7786
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharpEditor/Properties/AssemblyInfo.cs
@@ -0,0 +1,3 @@
+using System.Runtime.CompilerServices;
+
+[assembly: InternalsVisibleTo("GodotSharpExtensions")]
diff --git a/modules/mono/godotsharp_defs.h b/modules/mono/godotsharp_defs.h
index 08eeffc3db1ac8b8fec48feab320742ec3e4e789..197d893998ca2aca44a4e85d6ef9395778c9a56c 100644
--- a/modules/mono/godotsharp_defs.h
+++ b/modules/mono/godotsharp_defs.h
@@ -39,6 +39,7 @@
#define TOOLS_ASM_NAME "GodotTools"
#define BINDINGS_CLASS_NATIVECALLS "NativeCalls"
+#define BINDINGS_CLASS_NATIVECALLS_EXTENSION "ExtensionsNativeCalls"
#define BINDINGS_CLASS_NATIVECALLS_EDITOR "EditorNativeCalls"
#endif // GODOTSHARP_DEFS_H
diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp
index 3eb746677d581aa595aaae9b37c3c7859238b4c7..b4d7b897096c06982df4c8b42d2077cde6351bb0 100644
--- a/modules/mono/mono_gd/gd_mono.cpp
+++ b/modules/mono/mono_gd/gd_mono.cpp
@@ -39,6 +39,7 @@
#include "gd_mono_cache.h"
#ifdef TOOLS_ENABLED
+#include "../editor/bindings_generator.h"
#include "../editor/hostfxr_resolver.h"
#endif
@@ -574,6 +575,11 @@ bool GodotSharp::_is_runtime_initialized() {
return GDMono::get_singleton() != nullptr && GDMono::get_singleton()->is_runtime_initialized();
}
+bool GodotSharp::_generate_extensions_bindings() {
+ BindingsGenerator generator;
+ return generator.generate_cs_extensions_project(".godot/mono/extension_bindings") == OK;
+}
+
void GodotSharp::_reload_assemblies(bool p_soft_reload) {
#ifdef GD_MONO_HOT_RELOAD
CRASH_COND(CSharpLanguage::get_singleton() == nullptr);
@@ -586,6 +592,7 @@ void GodotSharp::_reload_assemblies(bool p_soft_reload) {
}
void GodotSharp::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("generate_extensions_bindings"), &GodotSharp::_generate_extensions_bindings);
ClassDB::bind_method(D_METHOD("is_runtime_initialized"), &GodotSharp::_is_runtime_initialized);
ClassDB::bind_method(D_METHOD("_reload_assemblies"), &GodotSharp::_reload_assemblies);
}
diff --git a/modules/mono/mono_gd/gd_mono.h b/modules/mono/mono_gd/gd_mono.h
index 1b46a619ca37019aa8d2918de26a209b7aea09df..609f9728526ae0acc2ec4bd4163b91d17a2cab2f 100644
--- a/modules/mono/mono_gd/gd_mono.h
+++ b/modules/mono/mono_gd/gd_mono.h
@@ -169,6 +169,7 @@ class GodotSharp : public Object {
void _reload_assemblies(bool p_soft_reload);
bool _is_runtime_initialized();
+ bool _generate_extensions_bindings();
protected:
static GodotSharp *singleton;
This patch allows you to generate a DLL that contains only bindings for all extensions. But my extensions could not run with this library, because in one case |
Thnx so much. Now at least we can start where you left off to figure out more TOGETHER. |
Can you provide? Generated\ExtensionsNativeCalls.cs <= curious to see how this look like. this is not included in the provided Zip |
Cppbindings_generator.cppError BindingsGenerator::generate_cs_extensions_project(const String &p_proj_dir) {
//Generate_cs_extensions files
for (const KeyValue<StringName, TypeInterface> &E : obj_types) {
const TypeInterface &itype = E.value;
if (itype.api_type != ClassDB::API_EXTENSION) {
continue;
}
String output_file = path::join(godot_objects_gen_dir, itype.proxy_name + ".cs");
Error err = _generate_cs_type(itype, output_file);
if (err == ERR_SKIP) {
continue;
}
if (err != OK) {
return err;
}
compile_items.push_back(output_file);
}
// Generate native calls
StringBuilder cs_icalls_content;
cs_icalls_content.append("namespace " BINDINGS_NAMESPACE ";\n\n");
cs_icalls_content.append("using System;\n"
"using System.Diagnostics.CodeAnalysis;\n"
"using System.Runtime.InteropServices;\n"
"using Godot.NativeInterop;\n"
"\n");
cs_icalls_content.append("[SuppressMessage(\"ReSharper\", \"InconsistentNaming\")]\n");
cs_icalls_content.append("[SuppressMessage(\"ReSharper\", \"RedundantUnsafeContext\")]\n");
cs_icalls_content.append("[SuppressMessage(\"ReSharper\", \"RedundantNameQualifier\")]\n");
cs_icalls_content.append("[System.Runtime.CompilerServices.SkipLocalsInit]\n");
cs_icalls_content.append("internal static class " BINDINGS_CLASS_NATIVECALLS_EXTENSION "\n{");
cs_icalls_content.append(MEMBER_BEGIN "internal static ulong godot_api_hash = ");
cs_icalls_content.append(String::num_uint64(ClassDB::get_api_hash(ClassDB::API_CORE)) + ";\n");
cs_icalls_content.append(MEMBER_BEGIN "private const int VarArgsSpanThreshold = 10;\n");
for (const InternalCall &icall : method_icalls) {
if (icall.api_type != ClassDB::API_EXTENSION) {
continue;
}
Error err = _generate_cs_native_calls(icall, cs_icalls_content);
if (err != OK) {
return err;
}
}
cs_icalls_content.append(CLOSE_BLOCK);
String internal_methods_file = path::join(base_gen_dir, BINDINGS_CLASS_NATIVECALLS_EXTENSION ".cs");
Error err = _save_file(internal_methods_file, cs_icalls_content);
if (err != OK) {
return err;
}
compile_items.push_back(internal_methods_file);
// Generate GeneratedIncludes.props
StringBuilder includes_props_content;
includes_props_content.append("<Project>\n"
" <ItemGroup>\n");
for (int i = 0; i < compile_items.size(); i++) {
String include = path::relative_to(compile_items[i], p_proj_dir).replace("/", "\\");
includes_props_content.append(" <Compile Include=\"" + include + "\" />\n");
}
includes_props_content.append(" </ItemGroup>\n"
"</Project>\n");
String includes_props_file = path::join(base_gen_dir, "GeneratedIncludes.props");
err = _save_file(includes_props_file, includes_props_content);
if (err != OK) {
return err;
}
return OK;
} Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterface &p_itype, const BindingsGenerator::MethodInterface &p_imethod, int &p_method_bind_count, StringBuilder &p_output) {
String def_arg_str = iarg.default_argument;
if (iarg.def_param_value.get_type() >= Variant::VECTOR2 && iarg.def_param_value.get_type() < Variant::PROJECTION)
def_arg_str = def_arg_str.replace("-inf", "real_t.NegativeInfinity").replace("inf", "real_t.PositiveInfinity");
String def_arg = sformat(def_arg_str, cs_type);
} - String im_call = im_icall->editor_only ? BINDINGS_CLASS_NATIVECALLS_EDITOR : BINDINGS_CLASS_NATIVECALLS;
+ String im_call = im_icall->api_type == ClassDB::API_EXTENSION ? BINDINGS_CLASS_NATIVECALLS_EXTENSION : (im_icall->editor_only ? BINDINGS_CLASS_NATIVECALLS_EDITOR : BINDINGS_CLASS_NATIVECALLS); bindings_generator.h struct InternalCall {
String name;
String unique_sig; // Unique signature to avoid duplicates in containers
+ ClassDB::APIType api_type = ClassDB::API_NONE;
bool editor_only = false; - InternalCall(ClassDB::APIType api_type, const String &p_name, const String &p_unique_sig = String()) {
+ InternalCall(ClassDB::APIType p_api_type, const String &p_name, const String &p_unique_sig = String()) {
name = p_name;
unique_sig = p_unique_sig;
- editor_only = api_type == ClassDB::API_EDITOR;
+ editor_only = p_api_type == ClassDB::API_EDITOR;
+ api_type = p_api_type;
}
public:
Error generate_cs_core_project(const String &p_proj_dir);
+ Error generate_cs_extensions_project(const String &p_proj_dir);
Error generate_cs_editor_project(const String &p_proj_dir);
Error generate_cs_api(const String &p_output_dir); godotsharp_defs.hhttps://github.com/godotengine/godot/blob/master/modules/mono/godotsharp_defs.h #define BINDINGS_CLASS_NATIVECALLS "NativeCalls"
+#define BINDINGS_CLASS_NATIVECALLS_EXTENSION "ExtensionsNativeCalls"
#define BINDINGS_CLASS_NATIVECALLS_EDITOR "EditorNativeCalls" gd_mono.cpphttps://github.com/godotengine/godot/blob/master/modules/mono/mono_gd/gd_mono.cpp #ifdef TOOLS_ENABLED
+#include "../editor/bindings_generator.h"
#include "../editor/hostfxr_resolver.h"
#endif
+bool GodotSharp::_generate_extensions_bindings() {
+ BindingsGenerator generator;
+ return generator.generate_cs_extensions_project(".godot/mono/extension_bindings") == OK;
+}
+
void GodotSharp::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("generate_extensions_bindings"), &GodotSharp::_generate_extensions_bindings);
ClassDB::bind_method(D_METHOD("is_runtime_initialized"), &GodotSharp::_is_runtime_initialized);
ClassDB::bind_method(D_METHOD("_reload_assemblies"), &GodotSharp::_reload_assemblies);
} gd_mono.hhttps://github.com/godotengine/godot/blob/master/modules/mono/mono_gd/gd_mono.h void _reload_assemblies(bool p_soft_reload);
bool _is_runtime_initialized();
+ bool _generate_extensions_bindings(); CSharpGodotSharpExtensions
|
Ideally, it needs to generate a second project GodotSharpExtensionsUnitTests.dll |
Nope. This file doesn't actually have to be included in the project directly. It's
And why did you re-attach pieces of my code when I already attached the |
Help myself and others to quickly have an overview what and where need to change, especially if better UI experience needed |
I have been recently active in Godot VS2022 Test adaptor, which I think is a good test-driven development for Godot 4 including scene development. Godot 4 C++ is not really my strength. Anyone here has made further progress in realizing the GDExtension c# wrapper? |
Discussion from Discord I went through the Godot c++ patch. It shows where in Godot Mono modules need to be adapted or modified to hijeck the existing Godot 4 glue code used to crate GodotSharp into => generating the wrappers for Gdextension. The point, not to write your wrappers, but ===> Hiject the Godot's c# wrapper ENGINE into creating the GDExtension c# wrapper The Godot4 c++ codes needed for modifications have been identified. We need to share this so many could contribute how to make the c# wrapper generation process more robust and MOST importantly high performance. Other more straight forwards methods will lead to low performance wrappers, From what I have gathered. @mynameisfury First => start active on the thread #8191 => so the Godot team know there is strong interest |
Is there any current workaround to be able to extend a node registered in the gdextension from within C#? Even if it involves going through gdscript. I tried this solution (that was previously linked to this post) DmitriySalnikov/godot_debug_draw_3d#2 (comment) and still C# can't manage to find those nodes. |
The official Godot4 .NET GDextension is HERE!!!! https://chat.godotengine.org/channel/dotnet?msg=AuLM9LDLCJS4oX3B9 |
Godot community discussion |
Almost all the demo codes for c++ Gdextension are written in Gdscript The repos could help in writing integration tests for generated c# wrappers |
Describe the project you are working on
3D multiplayer game targeting Steam using C#.
Mid-port from Unity.
Uses Steam Matchmaking/Networking to allow easy joining/inviting between friends, and Steam Datagram Relay (SDR) to achieve connections between players without port forwarding etc.
Describe the problem or limitation you are having in your project
Many important features and 3rd party integrations are implemented as GDExtensions in Godot. In our project: GodotSteam and SteamMultiplayerPeer.
However, with a csharp focused godot project these extensions are inaccessible.
We've written a GDScript "bridge" for for GodotSharp that exposes and proxies calls from CSharp, but it's time consuming and error prone.
Not having access to community extensions is a big limitation of Godot currently (for csharp developers/ex-unity).
Describe the feature / enhancement and how it helps to overcome the problem or limitation
With the continued focus on supporting csharp as a "first class" option in Godot, it follows that being able to access GDExtensions would be of increased importance.
Generating csharp bindings on extension "import" when csharp use is detected would bring csharp feature parity closer.
Ideally this would not be something extension developers have to individually and manually add to their extensions. It should be effortless/automatic, not requiring opt in. Otherwise I fear it just won't happen (the current situation).
Optional Extra
Support the work to allow generating bindings not just for csharp, but for other language extensions like rust and swift.
Achieving arbitrary language binding generation would greatly increase the capability of Godot as a multi-langauge extension and fully unlock it for developers from other languages.
Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams
GDExtensions would include their source when being packaged. (I assume source is required to generate csharp bindings)
In the editor, upon download from the Godot Asset Library, Godot will generate csharp bindings and place them in the project, potentially alongside the extension in
addons
.Any required changes to .csproj or .sln would be made after generating the bindings.
If this enhancement will not be used often, can it be worked around with a few lines of script?
If users are not using Godot_mono, or in future don't have the csharp GDExtension enabled, generating bindings can be skipped.
Is there a reason why this should be core and not an add-on in the asset library?
I make this proposal here because csharp code is in core/the godot main repository.
The text was updated successfully, but these errors were encountered: