godotengine / godot

Godot Engine – Multi-platform 2D and 3D game engine
https://godotengine.org
MIT License
91.46k stars 21.27k forks source link

Exports with mono and C# scripts can corrupt the build results #97920

Closed DCTewi closed 1 month ago

DCTewi commented 1 month ago

Tested versions

By git bisect I found the first bad commit is [0dde931bc95e].

System information

Godot v4.4.dev.mono (3cad849b1) - Windows 10.0.22631 - Vulkan (Forward+)

Issue description

The exported project with mono throws many System.TypeInitializationException, and there are many native method bindings that can't be found, such as Object.tr or Control.get_theme_icon.

[0dde931bc95e] deleted some .inc files and changed the hashes of some functions, and those old hashes need to be fetched in a new way. The exported project was using the old hashes, resulting in not getting the target function pointers correctly.

One of the errors from exported projects:

ERROR: System.TypeInitializationException: A type initializer threw an exception. To determine which type, inspect the InnerException's StackTrace property.
 ---> Godot.GodotObject+NativeMethodBindNotFoundException: Unable to find the native method bind. (Method 'Control.get_theme_icon')
   at Godot.GodotObject.ClassDB_get_method_with_compatibility(StringName type, StringName method, UInt64 hash) + 0x100
   at Godot.Control..cctor() + 0x3240
   at System.Runtime.CompilerServices.ClassConstructorRunner.EnsureClassConstructorRun(StaticClassConstructionContext*) + 0x160
   --- End of inner exception stack trace ---
   at System.Runtime.CompilerServices.ClassConstructorRunner.EnsureClassConstructorRun(StaticClassConstructionContext*) + 0x247
   at System.Runtime.CompilerServices.ClassConstructorRunner.CheckStaticClassConstructionReturnGCStaticBase(StaticClassConstructionContext*, Object) + 0x1c
   at Godot.Control.InvokeGodotClassMethod(??? method, NativeVariantPtrArgs args, godot_variant& ret) + 0x64
   at Godot.Label.InvokeGodotClassMethod(??? method, NativeVariantPtrArgs args, godot_variant& ret) + 0x55
   at ExportBrokenExample.CustomLabel.InvokeGodotClassMethod(??? method, NativeVariantPtrArgs args, godot_variant& ret) + 0xf9
   at export_broken_example!<BaseAddress>+0x79fd9a
   at: void Godot.NativeInterop.ExceptionUtils.LogException(System.Exception) (:0)

Steps to reproduce

Sample Label Scene:

[gd_scene load_steps=2 format=3 uid="uid://dhkseg6v08mew"]

[ext_resource type="Script" path="res://CustomLabel.cs" id="1_ig7tw"]

[node name="Main" type="CanvasLayer"]

[node name="Label" type="Label" parent="."]
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
theme_override_font_sizes/font_size = 64
text = "Native invoke failed."
horizontal_alignment = 1
vertical_alignment = 1
script = ExtResource("1_ig7tw")

Sample Script:

using Godot;

namespace ExportBrokenExample;

public partial class CustomLabel : Label
{
    public override void _Ready()
    {
        base._Ready();

        Text = Tr("Native invoke successful.");
    }
}

Minimal reproduction project (MRP)

export_broken_example.zip

raulsntos commented 1 month ago

I tried building the export templates and GodotSharp assemblies from commit 3cad849b1f47747f69081086faa2db190706a829 and I'm unable to reproduce the issue.

It looks like you are using a custom build. I suspect the GodotSharp assemblies you are using were compiled using a different version of the Godot source code than the export templates, which is not supported.

Changing the hashes shouldn't break compat for C# as long as you use the GodotSharp assemblies that match your export templates.

DCTewi commented 1 month ago

I complied the editor and export template in the same commit of the code with the commands below:

bash -c "openssl rand -hex 32 > bin/godot.gdkey"
$env:SCRIPT_AES256_ENCRYPTION_KEY = (cat ./bin/godot.gdkey)
$env:BUILD_NAME = "dctewi"

$buildFlags = "production=yes", "debug_symbols=yes", "module_mono_enabled=yes", "p=windows", "arch=x86_64"

& scons $buildFlags target=editor
& scons $buildFlags target=template_debug
& scons $buildFlags target=template_release

./bin/godot.windows.editor.x86_64.mono.exe --headless --generate-mono-glue modules/mono/glue
python ./modules/mono/build_scripts/build_assemblies.py --godot-output-dir=./bin --godot-platform=windows

./bin/godot.windows.editor.x86_64.mono.exe --doctool

I don't know why the issue can be reproduced in my machine. I'll try to reproduce it with another PC without Godot installed or built.

raulsntos commented 1 month ago

When executing the build_assemblies.py script, you are not using the --push-nupkgs-local option. Make sure the GodotSharp packages are pushed to a local NuGet source; otherwise, your project may be using different packages than the ones you just built.

DCTewi commented 1 month ago

I installed the nuget packages later in bin/GodotSharp/Tools/nupkgs manually and I changed the status variable to custom in version.py so that my custom build nuget package had a version like 4.4-custom to avoid using a wrong version package. I'm not sure what went wrong.

raulsntos commented 1 month ago

You can list the registered NuGet sources with dotnet nuget list source. It should contain the local NuGet source where you are placing the NuGet packages, and it should be [Enabled]. Check if any of the other sources listed there also contains packages with the same version (4.4-custom), if so it may be getting the packages from the wrong source.

Also, the --push-nupkgs-local option takes care of clearing the cache for you. Since you are not using it, make sure to remove the GodotSharp packages from the NuGet cache; otherwise, it may be getting the cached packages instead of the new ones. You can list the cache locations with dotnet nuget locals all --list (look for global-packages).

DCTewi commented 1 month ago

After git clean -dfX, the hashes in the C# code files generated in modules\mono\glue\GodotSharp\GodotSharp\Generated\GodotObjects successfully changed to the new version of the hashes.

I thought perhaps some old compilation cache was affecting the code generation process. However, rebuilding Godot with a completely new repo does avoid the problem. It's time to close this issue.