Skip to content

Instantly share code, notes, and snippets.

@lewiji
Last active May 17, 2022 23:52
Show Gist options
  • Save lewiji/2b86f47dcb142a10e104504a343c38ff to your computer and use it in GitHub Desktop.
Save lewiji/2b86f47dcb142a10e104504a343c38ff to your computer and use it in GitHub Desktop.

Godot dotnet6 branch notes

Update 22/04/22

I've managed to get Windows MSVC editor builds working about as well as Linux builds on my fork: https://github.com/lewiji/godot/tree/dotnet6

This fork includes patches mentioned in the details below for libicu compatibility, as well as specific fixes for MSVC compatibility.

I've also set up Github CI builds there which should be working for both Linux and Windows editors (unsure about export templates though at least the Linux ones are building currently).

On both platforms, I'd recommend putting the editor into "self-contained" mode by creating an empty file called _sc_ or ._sc_ in the same folder as the editor. This will prevent any config/editor settings spilling over from Mono versions of godot if you've used them before.

You also will have to add the GodotSharp/Tools/nupkgs folder as a local nuget source; the Linux CI builds come with a script to do that, you can do it manually via the command dotnet nuget add source -n GodotSharp /full/path/to/GodotSharp/Tools/nupkgs or by manually editing your NuGet.Config file. Eventually this won't be necessary as the packages will be published to the public NuGet package source.

Also worth noting that currently the dotnet6 branch is a fair bit behind master which has received a lot of fixes and features as well as breaking changes in the meantime; the merge from dotnet6 into master isn't completely trivial and will take some effort, so if you've been warned not to start a serious project in Godot 4 alpha, this goes double for the dotnet6 branch as it stands today.

Update 31/03/22

In the current dotnet6 branch, there is an issue with certain Linux distros (Arch, at least) where the .NET runtime somehow gets confused by the partial libicu bundle data generated by the text_server_adv module (possibly the stub icu locale data that is used there means .NET isn't receiving correct locale data, but I'm unsure).

This causes the binary to throw a System.TypeInitializationException when the interop is initialised and calls System.Globalization.CompareInfo for some locale operations - seemingly because the culture info is left undefined/empty (?). There is a workaround and a fix for this:

Workaround: use scons flags module_text_server_adv_enabled=no module_text_server_fb_enabled=yes to disable the new text server and fallback to the old 3.x compatible text server. This disables the more advanced text features.

Fix: compiler flags were added to force libicu in the text server module to rename its internal functions with a suffix, which prevents this conflict: https://github.com/godotengine/godot/pull/59656/files

You can apply this to dotnet6 by applying these 2 patches in order (the first is a patch to fix another issue with a compilation flag builtin_icu=no which prevents this bundling completely, though this isn't necessary for this problem, it's required for the second patch to succeed):

https://patch-diff.githubusercontent.com/raw/godotengine/godot/pull/59621.patch

https://patch-diff.githubusercontent.com/raw/godotengine/godot/pull/59656.patch

Once patched, compile as below and

Update 22/03/22

I now have a working linuxbsd build thanks to the assistance of @raulsntos and others in the community. The crucial part missing from the original gist is that at the time of writing, the release_debug target strips (or doesn't compile in the first place, unsure) the engine binary of the methods needed for the C# runtime to call out to the engine C++ code. On a freshly installed Ubuntu 20.04 VM, I ran:

$ scons p=linuxbsd tools=yes module_mono_enabled=yes
$ bin/godot.linuxbsd.tools.64.mono --generate-mono-glue modules/mono/glue
$ python3 modules/mono/build_scripts/build_assemblies.py --godot-output-dir=bin --godot-target=release_debug
$ dotnet nuget add source /home/lewiji/godot/bin/GodotSharp/Tools/nupkgs -n GodotSharp

This built a working editor in Debug mode, which allowed me to create and run C# scripts successfully. The accidental stripping of needed methods will be fixed later, and release_debug works fine for the C# assemblies, just not for the main godot binary.


Original gist

I've compiled the commit comments from the branch to date here to make it a bit easier to read:

https://gist.github.com/lewiji/29ae4f75f00c90ba68900630d4df537c

So here's what i've done so far, caveat, this could be wrong/incomplete as so far I haven't got everything to actually work, but it seems to be roughly along the right lines. I'm just using the dotnet6 branch as is for now, haven't attempted to merge it into master.

scons build

Compiling like normal, one of the commits says the mono_glue flag is no longer needed, since the glue generation is now done in C# by the mono module while compiling, however, I found that it was needed. I ran into an error initially, which I've described below (may be linux only, so try compiling first).

After generating the glue, there's an additional step to build the assemblies.

$ scons p=linuxbsd tools=yes module_mono_enabled=yes mono_glue=no target=release_debug -j$(nproc)
$ ./bin/godot.linuxbsd.opt.tools.64.mono --generate-mono-glue modules/mono/glue

incorrect dotnet core host path (linux only?)

On both of my linux machines, trying to compile the engine this way immediately gives a RuntimeError, saying that it can't find: /usr/share/dotnet/packs/Microsoft.NETCore.App.Host.linux-x64/6.0.2/runtimes/linux-x64/native/libnethost.a:

At least on Arch and Fedora where I tried this, that path is actually platform specific, in this case the linux part of the folder name Microsoft.NETCore.App.Host.linux-x64 is actually either arch or fedora.34 on my systems. I guess this is dependent on the package manager used, maybe it doesn't apply to other platforms.

So, looking through the trace, I need to modify modules/mono/build_scripts/mono_configure.py. On line 115, inside the names_map declaration in the determine_runtime_identifier(env): function I changed:

"linuxbsd": "linux",

to:

"linuxbsd": "arch",

Which then correctly sets up the path to the runtime, and when re-running scons, the compilation succeeds.

build_assemblies.py script

This generates the binaries and nuget packages for the C# integration and tools.

$ ./modules/mono/build_scripts/build_assemblies.py --godot-output-dir=/home/ljp/dotnet6/bin --godot-target=release_debug --godot-platform=linuxbsd

This outputs a GodotSharp folder into the bin folder which includes assemblies for GodotSharp, GodotSharpEditor, and GodotPlugins in the API subfolder, and in the Tools subfolder, various GodotTools binaries that seem to be to do with logging, messaging, shared components. also inside the Tools folder is a nupkgs folder which contains the nuget packages for local sourcing them into the project

final build

Now the glue and the assemblies have been created, we can build the final binary,

$ scons p=linuxbsd tools=yes module_mono_enabled=yes mono_glue=yes target=release_debug -j$(nproc)

initial test

So far so good, now the issue is that though the editor binary runs and opens the project manager, and I can create new projects, I can't actually open any projects, I get an exception:

┌─[lewiji][roguelike][~/godot/dotnet6]
└─▪
└─▪ System.InvalidOperationException: Dependency resolution failed for component /home/lewiji/dev/test1244/.godot/mono/temp/bin/Debug/test1244.dll with error code -2147450734. Detailed error: Failed to locate managed application [/home/lewiji/dev/test1244/.godot/mono/temp/bin/Debug/test1244.dll]

   at System.Runtime.Loader.AssemblyDependencyResolver..ctor(String componentAssemblyPath)
   at GodotPlugins.PluginLoadContext..ctor(String pluginPath, ICollection`1 sharedAssemblies, AssemblyLoadContext mainLoadContext) in /home/ljp/dotnet6/modules/mono/glue/GodotSharp/GodotPlugins/PluginLoadContext.cs:line 18
   at GodotPlugins.Main.LoadPlugin(String assemblyPath) in /home/ljp/dotnet6/modules/mono/glue/GodotSharp/GodotPlugins/Main.cs:line 138
   at GodotPlugins.Main.LoadProjectAssembly(Char* nAssemblyPath) in /home/ljp/dotnet6/modules/mono/glue/GodotSharp/GodotPlugins/Main.cs:line 79
System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation.
 ---> System.TypeInitializationException: The type initializer for 'Godot.EditorPlugin' threw an exception.
 ---> System.EntryPointNotFoundException: Unable to find an entry point named 'godotsharp_string_new_with_utf16_chars' in shared library '__Internal'.
   at Godot.NativeInterop.NativeFuncs.godotsharp_string_new_with_utf16_chars(godot_string& r_dest, Char* p_contents)
   at Godot.NativeInterop.Marshaling.ConvertStringToNative(String p_mono_string) in /home/ljp/dotnet6/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs:line 811
   at Godot.NativeInterop.NativeFuncs.godotsharp_string_name_new_from_string(String name) in /home/ljp/dotnet6/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.extended.cs:line 49
   at Godot.StringName..ctor(String name) in /home/ljp/dotnet6/modules/mono/glue/GodotSharp/GodotSharp/Core/StringName.cs:line 65
   at Godot.StringName.op_Implicit(String from) in /home/ljp/dotnet6/modules/mono/glue/GodotSharp/GodotSharp/Core/StringName.cs:line 74
   at Godot.EditorPlugin..cctor() in /home/ljp/dotnet6/modules/mono/glue/GodotSharp/GodotSharpEditor/Generated/GodotObjects/EditorPlugin.cs:line 50
   --- End of inner exception stack trace ---
   at Godot.EditorPlugin..ctor() in /home/ljp/dotnet6/modules/mono/glue/GodotSharp/GodotSharpEditor/Generated/GodotObjects/EditorPlugin.cs:line 59
   at GodotTools.GodotSharpEditor..ctor()
   at GodotTools.GodotSharpEditor.InternalCreateInstance() in /home/ljp/dotnet6/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs:line 551
   --- End of inner exception stack trace ---
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Span`1& arguments, Signature sig, Boolean constructor, Boolean wrapExceptions)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)
   at GodotPlugins.Main.LoadToolsAssembly(Char* nAssemblyPath) in /home/ljp/dotnet6/modules/mono/glue/GodotSharp/GodotPlugins/Main.cs:line 116
ERROR: FATAL: Condition "editor_plugin_obj == nullptr" is true.
   at: _editor_init_callback (modules/mono/csharp_script.cpp:1175)

================================================================
handle_crash: Program crashed with signal 4
Engine version: Godot Engine v4.0.alpha.mono.custom_build (8b85bc71595e1b95f66857d13a6558d492505927)
Dumping the backtrace. Please include this when reporting the bug on https://github.com/godotengine/godot/issues
[1] /usr/share/dotnet/shared/Microsoft.NETCore.App/6.0.2/libcoreclr.so(+0x4b1b2e) [0x7f4b1c5d1b2e] (??:0)
[2] /usr/lib/libc.so.6(+0x42560) [0x7f4b4159c560] (??:0)
[3] /home/lewiji/godot/dotnet6/godot.linuxbsd.opt.tools.64.mono() [0x1092ecf] (??:0)
[4] /home/lewiji/godot/dotnet6/godot.linuxbsd.opt.tools.64.mono() [0x1b10043] (??:0)
[5] /home/lewiji/godot/dotnet6/godot.linuxbsd.opt.tools.64.mono() [0xa793b6] (??:0)
[6] /home/lewiji/godot/dotnet6/godot.linuxbsd.opt.tools.64.mono() [0xa2bd65] (??:0)
[7] /usr/lib/libc.so.6(+0x2d310) [0x7f4b41587310] (??:0)
[8] /usr/lib/libc.so.6(__libc_start_main+0x81) [0x7f4b415873c1] (??:0)
[9] /home/lewiji/godot/dotnet6/godot.linuxbsd.opt.tools.64.mono() [0xa3607e] (??:0)
-- END OF BACKTRACE --
================================================================

manual .NET solution/project setup

Ok, so the built project DLL doesn't exist, and I guess currently it just expects that it will, rather than the default behaviour of loading a regular, non-C# project and creating the C# stuff later. I noted in the commit log that currently the dotnet6 branch doesn't do the automated copying over of the required assemblies, so I tried to set up a C# project manually using the info I could glean from the repo changes:

  • used the official alpha 3 build to create a new Godot project called "testdotnet62",
  • opened the new godot project in official alpha 3, and exited godot editor again,
  • created a new, blank .NET Solution in the new project's folder from Rider,
  • added a .csproj file as follows:
<Project Sdk="Godot.NET.Sdk/4.0.0-dev8">
    <PropertyGroup>
            <RootNamespace>testdotnet62</RootNamespace>
            <LangVersion>10</LangVersion>
            <Nullable>enable</Nullable>
            <TargetFramework>net6.0</TargetFramework>
    </PropertyGroup>
</Project>

And added it to my solution. Note the Sdk version is 4.0.0-dev8, LangVersion is 10, and TargetFramework is net6.0. These settings are found in the changes to the mono editor module projects themselves, so I assumed the game config would be similar.

This won't actually load yet, because the 4.0.0-dev8 Sdk version is in this new local nuget package, rather than copied into the project as an assembly or published on nuget.org. As noted in a commit comment, you can use the dotnet cli tool to add the folder outputted from compiling Godot in bin/GodotSharp/Tools/nupkgs:

$ dotnet nuget add source ~/godot/dotnet6/GodotSharp/Tools/nupkgs/ -n GodotSharpTools

If I then open the project in Rider and use the NuGet package manager, I can now see this GodotSharpTools source in the nuget feeds list, and 3 packages are implicitly installed, I guess automatically by the Sdk dependency in the csproj: Godot.SourceGenerators, GodotSharp, and GodotSharpEditor. It's important I guess to check these are definitely installed from your local source and not nuget.org, for example, though Godot.SourceGenerators reports being installed as 4.0.0-0 in the nuget panel, and it even offers to upgrade it to 4.0.0-dev8 (which doesn't seem to do anything), if I navigate to the assembly in the Solution panel and open it in file I can see it's coming from the 4.0.0-dev8 package folder in ~/.nuget/packagesgodot.sourcegenerators/.)

Now the solution/project will load and I can see in my solution tree that the dependency root is .NET 6.0, under Assemblies > Implicit I can see GodotSharp and GodotSharpEditor, under Analyzers I can see Godot.SourceGenerators.

build solution and attempt to open it again

At this point, I can build the solution and it outputs the .dll that it was complaining about in the stack trace earlier. Great! Let's try again!

┌─[lewiji][roguelike][~/godot/dotnet6]
└─▪ System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation.
 ---> System.TypeInitializationException: The type initializer for 'Godot.EditorPlugin' threw an exception.
 ---> System.EntryPointNotFoundException: Unable to find an entry point named 'godotsharp_string_new_with_utf16_chars' in shared library '__Internal'.
   at Godot.NativeInterop.NativeFuncs.godotsharp_string_new_with_utf16_chars(godot_string& r_dest, Char* p_contents)
   at Godot.NativeInterop.Marshaling.ConvertStringToNative(String p_mono_string) in /home/ljp/dotnet6/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs:line 811
   at Godot.NativeInterop.NativeFuncs.godotsharp_string_name_new_from_string(String name) in /home/ljp/dotnet6/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.extended.cs:line 49
   at Godot.StringName..ctor(String name) in /home/ljp/dotnet6/modules/mono/glue/GodotSharp/GodotSharp/Core/StringName.cs:line 65
   at Godot.StringName.op_Implicit(String from) in /home/ljp/dotnet6/modules/mono/glue/GodotSharp/GodotSharp/Core/StringName.cs:line 74
   at Godot.EditorPlugin..cctor() in /home/ljp/dotnet6/modules/mono/glue/GodotSharp/GodotSharpEditor/Generated/GodotObjects/EditorPlugin.cs:line 50
   --- End of inner exception stack trace ---
   at Godot.EditorPlugin..ctor() in /home/ljp/dotnet6/modules/mono/glue/GodotSharp/GodotSharpEditor/Generated/GodotObjects/EditorPlugin.cs:line 59
   at GodotTools.GodotSharpEditor..ctor()
   at GodotTools.GodotSharpEditor.InternalCreateInstance() in /home/ljp/dotnet6/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs:line 551
   --- End of inner exception stack trace ---
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Span`1& arguments, Signature sig, Boolean constructor, Boolean wrapExceptions)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)
   at GodotPlugins.Main.LoadToolsAssembly(Char* nAssemblyPath) in /home/ljp/dotnet6/modules/mono/glue/GodotSharp/GodotPlugins/Main.cs:line 116
ERROR: FATAL: Condition "editor_plugin_obj == nullptr" is true.
   at: _editor_init_callback (modules/mono/csharp_script.cpp:1175)

================================================================
handle_crash: Program crashed with signal 4
Engine version: Godot Engine v4.0.alpha.mono.custom_build (8b85bc71595e1b95f66857d13a6558d492505927)
Dumping the backtrace. Please include this when reporting the bug on https://github.com/godotengine/godot/issues
[1] /usr/share/dotnet/shared/Microsoft.NETCore.App/6.0.2/libcoreclr.so(+0x4b1b2e) [0x7f2054dcab2e] (??:0)
[2] /usr/lib/libc.so.6(+0x42560) [0x7f2094c16560] (??:0)
[3] /home/lewiji/godot/dotnet6/godot.linuxbsd.opt.tools.64.mono() [0x1092ecf] (??:0)
[4] /home/lewiji/godot/dotnet6/godot.linuxbsd.opt.tools.64.mono() [0x1b10043] (??:0)
[5] /home/lewiji/godot/dotnet6/godot.linuxbsd.opt.tools.64.mono() [0xa793b6] (??:0)
[6] /home/lewiji/godot/dotnet6/godot.linuxbsd.opt.tools.64.mono() [0xa2bd65] (??:0)
[7] /usr/lib/libc.so.6(+0x2d310) [0x7f2094c01310] (??:0)
[8] /usr/lib/libc.so.6(__libc_start_main+0x81) [0x7f2094c013c1] (??:0)
[9] /home/lewiji/godot/dotnet6/godot.linuxbsd.opt.tools.64.mono() [0xa3607e] (??:0)
-- END OF BACKTRACE --
================================================================

...ah.

Well, at least it's not complaining about being unable to resolve the assembly, but we're still getting this Godot.EditorPlugin exception about something called godotsharp_string_new_with_utf16_chars.

Now, I'm pretty sure that the move from dynamic lookups to NativeInterop.NativeFuncs via this __Internal shared library happened in one of the dotnet6 branch commits, so will investigate further, once I'm done with this pesky interruption called the "day job" ;)

I half suspect it might be an issue on my machine, so it'd be good to see if anyone else has success with this - since at the trace is coming from libc, and my host machine is Arch linux, which I know has had a few issues with libc compatibility recently, as the package was without a maintainer for a long time, and was only recently updated after being left out of date for quite some time (years?). I've seen at least one other piece of software break with a stacktrace about libc in the last 2 weeks as a result, so it's possible that's the cause. I built the binary in a Fedora 34 VM, to get as close as possible to the official builds, so next I'll try compiling directly in arch, and if all else fails, Windows, to see what happens there.

@lewiji
Copy link
Author

lewiji commented Mar 27, 2022

Yes - same problem if I build and run on Arch host.

@lewiji
Copy link
Author

lewiji commented Mar 27, 2022

Btw, this looks relevant:

https://docs.microsoft.com/en-us/dotnet/core/extensions/globalization-icu#app-local-icu

Includes the possibility of dotnet apps to "carry and use their own copy of ICU" to prevent version mismatches - if that is the problem, of course.

@neikeq
Copy link

neikeq commented Mar 27, 2022

Yes - same problem if I build and run on Arch host.

Are you sure? This error seem to happen before running any of our C# code, while the previous backtraces you shared happen after that (the Unable to find an entry point named 'godotsharp_string_new_with_utf16_chars' error).

@lewiji
Copy link
Author

lewiji commented Mar 27, 2022

Yes - same problem if I build and run on Arch host.

Are you sure? This error seem to happen before running any of our C# code, while the previous backtraces you shared happen after that (the Unable to find an entry point named 'godotsharp_string_new_with_utf16_chars' error).

I'm fairly sure - in one of the comments above, I built it on my laptop which runs EndeavourOS, the first time I had ever built godot on that machine, and got the globalisation issue.

https://gist.github.com/lewiji/2b86f47dcb142a10e104504a343c38ff?permalink_comment_id=4109157#gistcomment-4109157

However, just to be doubly sure, I'll try again on my desktop.

Edit: and if that's the case, is it possible it now being a Debug build rather than ReleaseDebug is affecting things?

@lewiji
Copy link
Author

lewiji commented Mar 27, 2022

Yup, confirmed - just built a debug binary from scratch on Arch, and I still get the same exceptions from System.Globalization.CompareInfo

Given what you said above about the sequence of events, I'd be interested to know if these methods are being called or not in a release_debug binary, and if they are being called, what's happening differently.

@lewiji
Copy link
Author

lewiji commented Mar 27, 2022

@neikeq any idea how to attach C# debugger to the godot binary, so I can catch the exception in one of the solutions/projects in the modules/mono directory? Having trouble getting my IDE to recognise that the godot binary does C# things, and map the .cs code onto it, but I guess it's not as simple as just pointing it to the binary and crossing my fingers, lol.

@lewiji
Copy link
Author

lewiji commented Mar 27, 2022

Ah, could this be the issue? https://godotengine.org/article/complex-text-layouts-progress-report-3

builtin_graphite, builtin_harfbuzz and builtin_icu (default value: True) - If true, uses built-in version of the libraries instead of system copies (can be disabled for Linux distribution packages).

There are two text server implementations available by default:

ICU, HarfBuzz and SIL Graphite 2 based text server with the full complex text layout support (adv). Fallback text server without CTL support, it uses same text server API and provides roughly the same text rendering capabilities as in Godot 3.2 (fb).

Text servers can be enabled/disabled by using following build options: module_text_server_adv_enabled, module_text_server_fb_enabled.

So maybe I just need to build with one or more of these toggled from default?

@lewiji
Copy link
Author

lewiji commented Mar 27, 2022

So, I recompiled with the following flags:

scons p=linuxbsd tools=yes module_mono_enabled=yes module_text_server_adv_enabled=no module_text_server_fb_enabled=yes

Which disables the new text server in favour of the 3.x compatible one, and Godot launches.

I briefly scanned some of the source files for the new text server implementation, and noticed a LOT of mentions of icu and versions of icu, so there must be something odd going on there where perhaps that module is trying to build against a certain icu version, and the mono project uses something else?

@neikeq
Copy link

neikeq commented Mar 27, 2022

Do you mean building like that fixed the issue? I was going to reply that I doubted that had anything to do with it, as whatever Godot links shouldn't be affecting the .NET runtime, but it seems I may be wrong.

@lewiji
Copy link
Author

lewiji commented Mar 27, 2022

Yup, building from scratch on arch again, disabling the text_server_adv module, and enabling the text_server_fb module results in no more System.Globalization exceptions (except a single warning on boot about some locales not being available) and the editor can boot, I can create projects, attach scripts, run games, etc. It all works, just without the fancy new text features like RTL, which I guess rely on ICU quite heavily.

https://github.com/godotengine/godot/blob/a30d17fe23cab95716e4b1bff9dfac21b70b5481/modules/text_server_adv/text_server_adv.cpp

There's all sorts of references to icu in there, as well as mentions of static - there must be some incompatibility there with the .NET stuff, but it's a total mystery to me too. Godot seems to bundle some icu files under the thirdparty/icu4c folder, and the version found in there seems to match my arch version - 70.1, so I'm not sure how a mismatch would even occur against the dotnet runtime, unless the runtime itself statically links to an older libicu version or something, which seems unlikely.

@neikeq
Copy link

neikeq commented Mar 27, 2022

Debugging a hosted .NET Core app on Linux right now seems to be a bit tricky. I couldn't get attaching to a process to work, only launch. This is the configuration:

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": ".NET Core Launch (console)",
            "type": "coreclr",
            "request": "launch",
            "program": "PATH/TO/GODOT_EXECUTABLE",
            "args": ["--path", "PATH/TO/GODOT_PROJECT", "-v", "-e"],
            "cwd": "PATH/TO/GODOT_PROJECT",
            "stopAtEntry": false,
            "console": "internalConsole"
        }
    ]
}

I remember that one working, but I'm not completely sure, as I use Rider instead.

If you manage to get debugging working, I would put a breakpoint here to see the value of resultCode: https://github.com/dotnet/runtime/blob/9f513350e3cea5cc56f9d7fb8e006382ec5043ff/src/libraries/System.Private.CoreLib/src/System/Globalization/CompareInfo.Icu.cs#L820

@lewiji
Copy link
Author

lewiji commented Mar 28, 2022

Ah, I use Rider too, but figured it out! And yeah, a breakpoint set there gets triggered almost immediately. Unfortunately I'm having a hard time making any sense of it, and a lot of stuff seems to be unavailable to the debugger for some reason. Also couldn't find an easy way to export the data from the debug panel, so here are some screenshots which you may or may not be able to see clearly... let me know if there's anything in particular you think is worth investigating here.

image

Above is where the exception is thrown from - ComponentActivator.IsSupported

image

image

(One thing I notice in the above variable view is CompareInfo.Version is disabled, if I do what it says and enable it in the context menu, the process dies shortly afterwards with a timeout error.)

image

The s_sortNameToSortHandleCache is an empty dictionary, and the sortName is an empty string - not sure if this is relevant.

Smart stepping into it, it seems to get a success code (though again, debugger doesn't actually make the result available to me), and appears to be adding to this empty dictionary - however I can't see what sortName or sortHandle are:

image

image

So yeah, still a bloody mystery

@neikeq
Copy link

neikeq commented Mar 28, 2022

Oof, yeah no idea how to read those. I asked on rocketchat about the textserver. If there's no luck, I'll have to try to reproduce this on a VM.

@paulloz
Copy link

paulloz commented Apr 20, 2022

Not sure if this is a good place to ask for this? But I have this weird error when trying to compile the dotnet6 branch on Win10. If anyone has some pointers... This does not happen on the current master.

[Initial build] modules\mono\csharp_script.cpp(672): fatal error C1021: invalid preprocessor command 'warning'
[Initial build] Compiling modules\mono\utils\string_utils.cpp ...
string_utils.cpp
[Initial build] scons: *** [modules\mono\csharp_script.windows.opt.tools.64.obj] Error 2
Compiling modules\mono\mono_gd\support\android_support.cpp ...
android_support.cpp
modules\mono\mono_gd\gd_mono.cpp(522): fatal error C1021: invalid preprocessor command 'warning'
scons: *** [modules\mono\mono_gd\gd_mono.windows.opt.tools.64.obj] Error 2
scons: building terminated because of errors.

@lewiji
Copy link
Author

lewiji commented Apr 20, 2022

@paulloz worth noting that so far, I've been unable to get a Windows build of the dotnet6 branch working, even if I wrap/remove the unsupported #warning pragmas. I can build and get the editor to boot and create projects, but as soon as I try to add a C# script, hard crash (weirdly, with no exception logged, even in verbose mode). Digging into it, there seems to be a problem with MSVC stripping symbols even in debug mode, as internally the CLR throws "EntryPointNotFoundExceptions" on certain calls, though these exceptions don't seem to be relayed to the engine and the only way I could see them is by running VS 2022 native/managed mixed debugging where the exception is displayed as a string at certain points.

I think this is down to the use of DllImport for the native interop, though there still may be specific tweaks to the compiler flags for MSVC, I'm not experienced enough with Windows dev to know more (something to do with LTCG, possibly). On Linux, configuring the compiler not to strip any symbols solved any EntryPointNotFoundExceptions there, however those exceptions were explicitly thrown and seen in the Godot terminal output (and crashed as soon as the editor booted), but these exceptions on Windows seem different in behaviour. However @raulsntos is currently working on porting this to use explicit function pointers instead, which should solve part of the problem - just unsure about whether MSVC needs additional flags after this work is done.

Edit: you can also edit the mono_configure.py script in modules/mono/build_scripts with the following change:

lewiji/godot@521043a

To enable linking to libnethost.lib correctly, rather than the above workaround to change it to nethost.lib and manually copy the nethost.dll into the godot/bin directory.

@paulloz
Copy link

paulloz commented Apr 20, 2022

@GeorgeS2019 @lewiji Thanks for the pointers. And sorry if all of that was already stated elsewhere in here, this page is kinda dense 😅
Going to try all that out in the next few days and I'll get back to y'all.

@lewiji
Copy link
Author

lewiji commented Apr 21, 2022

@paulloz I just got MSVC windows builds working with a couple of changes, see my fork: https://github.com/lewiji/godot/tree/dotnet6

I've set up CI builds there, though at the time of writing, the Windows editor build still hasn't finished (after 45 mins). However, steps should be roughly as @GeorgeS2019 outlined above. release_debug mode seems to work too. Editor will show a few errors in output, but they can be ignored.

  • Checkout my fork on branch dotnet6 (or apply the relevant patches to mono_configure.py, native_interop.cpp and editor_internal_functions.cpp)
  • Open up a Visual Studio x64 developer command prompt
  • scons -j8 tools=yes module_mono_enabled=yes target=release_debug
  • .\bin\godot.windows.opt.tools.64.mono.exe --generate-mono-glue modules/mono/glue
  • python modules\mono\build_scripts\build_assemblies.py --godot-output-dir=bin --godot-target=release_debug
  • dotnet nuget add source -n GodotSharp C:\path\to\godot\bin\GodotSharp\Tools\nupkgs
  • (optional, but recommended) create a file in the bin folder called _sc_ (this will stop the editor from pulling/overwriting EditorSettings/config from/to the mono version)

@paulloz
Copy link

paulloz commented Apr 21, 2022

Yup, I've been able to build yesterday with @GeorgeS2019's explanation (thanks again).

@lewiji I'm checking out the changes on your branch right now 👌

Y'all are perfect. I'll be trying to re-dedicate some time to Godot from now on. Hopefully I can help on something in the coming weeks.

@paulloz
Copy link

paulloz commented Apr 21, 2022

It's alive 🙏
https://user-images.githubusercontent.com/437025/164548288-dba03a0b-81d6-44d4-9497-442dab8bfa9a.mp4

Kudos to everybody that helped to bring it to this point already.
Current status on my Win10 build with release_debug: the following happens every time a .cs script gets reloaded (e.g. open a scene that contains a .cs script, close it, reopen it and the crash will happen).

================================================================
CrashHandlerException: Program crashed
Engine version: Godot Engine v4.0.alpha.mono.custom_build (6e63dffa3897eda930ccd1bed32632a90766d7c9)
Dumping the backtrace. Please include this when reporting the bug on https://github.com/godotengine/godot/issues
[0] read_all_file_utf8 (C:\Users\paulloz\Desktop\Gamedev\godot\modules\mono\utils\string_utils.cpp:168)
[1] CSharpScript::load_source_code (C:\Users\paulloz\Desktop\Gamedev\godot\modules\mono\csharp_script.cpp:2655)
[2] ResourceFormatLoaderCSharpScript::load (C:\Users\paulloz\Desktop\Gamedev\godot\modules\mono\csharp_script.cpp:2727)
[3] ResourceLoader::_load (C:\Users\paulloz\Desktop\Gamedev\godot\core\io\resource_loader.cpp:197)
[4] ResourceLoader::_thread_load_function (C:\Users\paulloz\Desktop\Gamedev\godot\core\io\resource_loader.cpp:224)
[5] ResourceLoader::load (C:\Users\paulloz\Desktop\Gamedev\godot\core\io\resource_loader.cpp:571)
[6] ResourceLoaderText::load (C:\Users\paulloz\Desktop\Gamedev\godot\scene\resources\resource_format_text.cpp:461)
[7] ResourceFormatLoaderText::load (C:\Users\paulloz\Desktop\Gamedev\godot\scene\resources\resource_format_text.cpp:1366)
[8] ResourceLoader::_load (C:\Users\paulloz\Desktop\Gamedev\godot\core\io\resource_loader.cpp:197)
[9] ResourceLoader::_thread_load_function (C:\Users\paulloz\Desktop\Gamedev\godot\core\io\resource_loader.cpp:224)
[10] ResourceLoader::load (C:\Users\paulloz\Desktop\Gamedev\godot\core\io\resource_loader.cpp:571)
[11] EditorNode::load_scene (C:\Users\paulloz\Desktop\Gamedev\godot\editor\editor_node.cpp:3586)
[12] EditorNode::open_request (C:\Users\paulloz\Desktop\Gamedev\godot\editor\editor_node.cpp:3698)
[13] FileSystemDock::_select_file (C:\Users\paulloz\Desktop\Gamedev\godot\editor\filesystem_dock.cpp:985)
[14] FileSystemDock::_tree_activate_file (C:\Users\paulloz\Desktop\Gamedev\godot\editor\filesystem_dock.cpp:1003)
[15] Callable::call (C:\Users\paulloz\Desktop\Gamedev\godot\core\variant\callable.cpp:51)
[16] Object::emit_signal (C:\Users\paulloz\Desktop\Gamedev\godot\core\object\object.cpp:1105)
[17] Object::emit_signal (C:\Users\paulloz\Desktop\Gamedev\godot\core\object\object.cpp:1160)
[18] Tree::gui_input (C:\Users\paulloz\Desktop\Gamedev\godot\scene\gui\tree.cpp:3422)
[19] Control::_call_gui_input (C:\Users\paulloz\Desktop\Gamedev\godot\scene\gui\control.cpp:830)
[20] Viewport::_gui_call_input (C:\Users\paulloz\Desktop\Gamedev\godot\scene\main\viewport.cpp:1287)
[21] Viewport::_gui_input_event (C:\Users\paulloz\Desktop\Gamedev\godot\scene\main\viewport.cpp:1519)
[22] Viewport::push_input (C:\Users\paulloz\Desktop\Gamedev\godot\scene\main\viewport.cpp:2701)
[23] Window::_window_input (C:\Users\paulloz\Desktop\Gamedev\godot\scene\main\window.cpp:969)
[24] call_with_variant_args<VisualScriptEditor,Ref<InputEvent> const &> (C:\Users\paulloz\Desktop\Gamedev\godot\core\variant\binder_common.h:346)
[25] Callable::call (C:\Users\paulloz\Desktop\Gamedev\godot\core\variant\callable.cpp:51)
[26] DisplayServerWindows::_dispatch_input_event (C:\Users\paulloz\Desktop\Gamedev\godot\platform\windows\display_server_windows.cpp:1921)
[27] Input::_parse_input_event_impl (C:\Users\paulloz\Desktop\Gamedev\godot\core\input\input.cpp:653)
[28] Input::flush_buffered_events (C:\Users\paulloz\Desktop\Gamedev\godot\core\input\input.cpp:872)
[29] DisplayServerWindows::process_events (C:\Users\paulloz\Desktop\Gamedev\godot\platform\windows\display_server_windows.cpp:1642)
[30] OS_Windows::run (C:\Users\paulloz\Desktop\Gamedev\godot\platform\windows\os_windows.cpp:629)
[31] widechar_main (C:\Users\paulloz\Desktop\Gamedev\godot\platform\windows\godot_windows.cpp:163)
[32] _main (C:\Users\paulloz\Desktop\Gamedev\godot\platform\windows\godot_windows.cpp:187)
[33] main (C:\Users\paulloz\Desktop\Gamedev\godot\platform\windows\godot_windows.cpp:199)
[34] __scrt_common_main_seh (d:\a01\_work\43\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:288)
[35] BaseThreadInitThunk
-- END OF BACKTRACE --
================================================================

@lewiji
Copy link
Author

lewiji commented Apr 21, 2022

It's alive 🙏 https://user-images.githubusercontent.com/437025/164548288-dba03a0b-81d6-44d4-9497-442dab8bfa9a.mp4

Kudos to everybody that helped to bring it to this point already. Current status on my Win10 build with release_debug: the following happens every time a .cs script gets reloaded (e.g. open a scene that contains a .cs script, close it, reopen it and the crash will happen).

================================================================
CrashHandlerException: Program crashed
Engine version: Godot Engine v4.0.alpha.mono.custom_build (6e63dffa3897eda930ccd1bed32632a90766d7c9)
Dumping the backtrace. Please include this when reporting the bug on https://github.com/godotengine/godot/issues
[0] read_all_file_utf8 (C:\Users\paulloz\Desktop\Gamedev\godot\modules\mono\utils\string_utils.cpp:168)
[1] CSharpScript::load_source_code (C:\Users\paulloz\Desktop\Gamedev\godot\modules\mono\csharp_script.cpp:2655)
[2] ResourceFormatLoaderCSharpScript::load (C:\Users\paulloz\Desktop\Gamedev\godot\modules\mono\csharp_script.cpp:2727)
[3] ResourceLoader::_load (C:\Users\paulloz\Desktop\Gamedev\godot\core\io\resource_loader.cpp:197)
[4] ResourceLoader::_thread_load_function (C:\Users\paulloz\Desktop\Gamedev\godot\core\io\resource_loader.cpp:224)
[5] ResourceLoader::load (C:\Users\paulloz\Desktop\Gamedev\godot\core\io\resource_loader.cpp:571)
[6] ResourceLoaderText::load (C:\Users\paulloz\Desktop\Gamedev\godot\scene\resources\resource_format_text.cpp:461)
[7] ResourceFormatLoaderText::load (C:\Users\paulloz\Desktop\Gamedev\godot\scene\resources\resource_format_text.cpp:1366)
[8] ResourceLoader::_load (C:\Users\paulloz\Desktop\Gamedev\godot\core\io\resource_loader.cpp:197)
[9] ResourceLoader::_thread_load_function (C:\Users\paulloz\Desktop\Gamedev\godot\core\io\resource_loader.cpp:224)
[10] ResourceLoader::load (C:\Users\paulloz\Desktop\Gamedev\godot\core\io\resource_loader.cpp:571)
[11] EditorNode::load_scene (C:\Users\paulloz\Desktop\Gamedev\godot\editor\editor_node.cpp:3586)
[12] EditorNode::open_request (C:\Users\paulloz\Desktop\Gamedev\godot\editor\editor_node.cpp:3698)
[13] FileSystemDock::_select_file (C:\Users\paulloz\Desktop\Gamedev\godot\editor\filesystem_dock.cpp:985)
[14] FileSystemDock::_tree_activate_file (C:\Users\paulloz\Desktop\Gamedev\godot\editor\filesystem_dock.cpp:1003)
[15] Callable::call (C:\Users\paulloz\Desktop\Gamedev\godot\core\variant\callable.cpp:51)
[16] Object::emit_signal (C:\Users\paulloz\Desktop\Gamedev\godot\core\object\object.cpp:1105)
[17] Object::emit_signal (C:\Users\paulloz\Desktop\Gamedev\godot\core\object\object.cpp:1160)
[18] Tree::gui_input (C:\Users\paulloz\Desktop\Gamedev\godot\scene\gui\tree.cpp:3422)
[19] Control::_call_gui_input (C:\Users\paulloz\Desktop\Gamedev\godot\scene\gui\control.cpp:830)
[20] Viewport::_gui_call_input (C:\Users\paulloz\Desktop\Gamedev\godot\scene\main\viewport.cpp:1287)
[21] Viewport::_gui_input_event (C:\Users\paulloz\Desktop\Gamedev\godot\scene\main\viewport.cpp:1519)
[22] Viewport::push_input (C:\Users\paulloz\Desktop\Gamedev\godot\scene\main\viewport.cpp:2701)
[23] Window::_window_input (C:\Users\paulloz\Desktop\Gamedev\godot\scene\main\window.cpp:969)
[24] call_with_variant_args<VisualScriptEditor,Ref<InputEvent> const &> (C:\Users\paulloz\Desktop\Gamedev\godot\core\variant\binder_common.h:346)
[25] Callable::call (C:\Users\paulloz\Desktop\Gamedev\godot\core\variant\callable.cpp:51)
[26] DisplayServerWindows::_dispatch_input_event (C:\Users\paulloz\Desktop\Gamedev\godot\platform\windows\display_server_windows.cpp:1921)
[27] Input::_parse_input_event_impl (C:\Users\paulloz\Desktop\Gamedev\godot\core\input\input.cpp:653)
[28] Input::flush_buffered_events (C:\Users\paulloz\Desktop\Gamedev\godot\core\input\input.cpp:872)
[29] DisplayServerWindows::process_events (C:\Users\paulloz\Desktop\Gamedev\godot\platform\windows\display_server_windows.cpp:1642)
[30] OS_Windows::run (C:\Users\paulloz\Desktop\Gamedev\godot\platform\windows\os_windows.cpp:629)
[31] widechar_main (C:\Users\paulloz\Desktop\Gamedev\godot\platform\windows\godot_windows.cpp:163)
[32] _main (C:\Users\paulloz\Desktop\Gamedev\godot\platform\windows\godot_windows.cpp:187)
[33] main (C:\Users\paulloz\Desktop\Gamedev\godot\platform\windows\godot_windows.cpp:199)
[34] __scrt_common_main_seh (d:\a01\_work\43\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:288)
[35] BaseThreadInitThunk
-- END OF BACKTRACE --
================================================================

Will try and reproduce! I'd made a slight error in my patch to the internal calls cpp, doubled one of the pinvoke macros which @GeorgeS2019 caught. It was to do with resource metadata from files, so could be related, though, looking at the trace, possibly not. Those traces have been a bit unreliable on windows though, and the only way I've found to get to the true exception is attaching the Visual Studio debugger to the running process in, iirc, "mixed native/.NET 5+ clr" mode. Also possible this is a quirk of release_debug mode, as that doesn't seem to work at all on Linux at the moment which requires debug mode due to compiler fun, trying release_debug mode on Windows earlier today was a bit of an afterthought and I didn't give it a thorough test yet.

Unsure how receptive the main repo issues board is to dotnet6 branch issues a the moment, given this is still prerelease stuff, but now that a few of us have given it a go we do definitely need a more organised approach than comments on this gist.

@GeorgeS2019
Copy link

GeorgeS2019 commented Apr 21, 2022

@lewiji could u share e.g. small tutorial or instruction how to collect useful debugging information using VS2022 under "mixed native/.NET 5+ clr" mode.

@lewiji
Copy link
Author

lewiji commented Apr 21, 2022

Not at my Windows PC and likely won't be for a few days now, but iirc, with VS2022 (which I think is different than/streamlined vs VS2019 for this kind of managed debugging, so YMMV with 2019), I ran Godot normally from cmd/explorer, opened VS2022 and opened the godot source folder. Then went to the Debug menu, "attach to process", filtered the process list by "godot" and selected the godot process. There's a box with a "select" button for the type of debugging, but I think it auto detects the correct option, which is "Managed (.NET Core, .NET 5+) code". This should allow you to set breakpoints in both the C++ and C# code, and set up exception breaks for both (C# exceptions are listed as "CLR exception" type).

I also went into the Visual Studio settings, debugging section, and unticked "just my code" so that it would break on all exceptions rather than just user exceptions.

I couldn't figure out how to create a "launch config" that would allow me to launch Godot from VS with debugger already attached, it was complaining about having the wrong debugging mode selected no matter what I tried, but if you have a mostly working/booting editor already then "attach to process" works great.

@paulloz
Copy link

paulloz commented Apr 22, 2022

For anyone interested, a basic cppvsdbg config is VSCode does the job and gives most of the actual exception information (in this case being a read access violation in

godot.windows.tools.64.mono.exe!CowData<char32_t>::_ref(const CowData<char32_t> & p_from) Line 368 (c:\Users\paulloz\Desktop\Gamedev\godot\core\templates\cowdata.h:368)
godot.windows.tools.64.mono.exe!String::operator=(const String & p_str) Line 441 (c:\Users\paulloz\Desktop\Gamedev\godot\core\string\ustring.h:441)
godot.windows.tools.64.mono.exe!read_all_file_utf8(const String & p_path, String & r_content) Line 169 (c:\Users\paulloz\Desktop\Gamedev\godot\modules\mono\utils\string_utils.cpp:169)
godot.windows.tools.64.mono.exe!CSharpScript::load_source_code(const String & p_path) Line 2655 (c:\Users\paulloz\Desktop\Gamedev\godot\modules\mono\csharp_script.cpp:2655)
godot.windows.tools.64.mono.exe!ResourceFormatLoaderCSharpScript::load(const String & p_path, const String & p_original_path, Error * r_error, bool p_use_sub_threads, float * r_progress, ResourceFormatLoader::CacheMode p_cache_mode) Line 2726 (c:\Users\paulloz\Desktop\Gamedev\godot\modules\mono\csharp_script.cpp:2726)
...

I agree that comments on here are probably not ideal.

@GeorgeS2019
Copy link

a basic cppvsdbg config is VSCode AND comments on here are probably not ideal.

thx

@stalinofficial
Copy link

It's crashing on me when I try to change scene using GetTree().ChangeScene("res://..."). How can I debug this?

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment