godot: Godot 4 .Net - Loading / Assigning a script exported from another project fails with error ("Cannot instance script because the associated class could not be found")
Godot version
v4.0.1.stable.mono.official [cacf49999]
System information
Windows 10
Issue description
Exporting a script from one godot project and loading it in another does not work (following https://docs.godotengine.org/en/stable/tutorials/export/exporting_pcks.html). The ResourceLoader.Load<Script>() call finds the script and succeeds, but when assigning the script to a node, the following error occurs:
E 0:00:00:0477 Godot.NativeInterop.NativeFuncs.generated.cs:332 @ void Godot.NativeInterop.NativeFuncs.godotsharp_method_bind_ptrcall(IntPtr , IntPtr , System.Void** , System.Void* ): Cannot instance script because the associated class could not be found. Script: 'res://HelloWorld.cs'. Make sure the script exists and contains a class definition with a name that matches the filename of the script exactly (it's case-sensitive).
<C++ Error> Method/function failed. Returning: false
<C++ Source> modules/mono/csharp_script.cpp:2301 @ can_instantiate()
<Stack Trace> Godot.NativeInterop.NativeFuncs.generated.cs:332 @ void Godot.NativeInterop.NativeFuncs.godotsharp_method_bind_ptrcall(IntPtr , IntPtr , System.Void** , System.Void* )
NativeCalls.cs:5208 @ void Godot.NativeCalls.godot_icall_1_583(IntPtr , IntPtr , Godot.Variant )
GodotObject.cs:434 @ void Godot.GodotObject.SetScript(Godot.Variant )
ImportScript.cs:24 @ void ImportScript._Ready()
Node.cs:1783 @ Boolean Godot.Node.InvokeGodotClassMethod(Godot.NativeInterop.godot_string_name& , Godot.NativeInterop.NativeVariantPtrArgs , Godot.NativeInterop.godot_variant& )
Node3D.cs:988 @ Boolean Godot.Node3D.InvokeGodotClassMethod(Godot.NativeInterop.godot_string_name& , Godot.NativeInterop.NativeVariantPtrArgs , Godot.NativeInterop.godot_variant& )
ImportScript_ScriptMethods.generated.cs:24 @ Boolean ImportScript.InvokeGodotClassMethod(Godot.NativeInterop.godot_string_name& , Godot.NativeInterop.NativeVariantPtrArgs , Godot.NativeInterop.godot_variant& )
CSharpInstanceBridge.cs:24 @ Godot.NativeInterop.godot_bool Godot.Bridge.CSharpInstanceBridge.Call(IntPtr , Godot.NativeInterop.godot_string_name* , Godot.NativeInterop.godot_variant** , Int32 , Godot.NativeInterop.godot_variant_call_error* , Godot.NativeInterop.godot_variant* )
Loading other resources (e.g. scenes) works. The assembly was also loaded successfully. Might be related to this reported issue: .NET 6 - Running exported PCK fails to load scripts or fails to load hostfxr #72159
Steps to reproduce
Note: With the minimal reproduction project, only steps 3-5 and step 8 are required.
- Create two new Godot Projects (an exporting and an importing project)
- In the exporting, create a new script “HelloWorld” in res:// that prints “Hello World” on _Ready
- Export the exporting project (with “Runnable” unchecked) into a .pck file for your platform
- Copy the exported .pck file and the project’s .dll from
.godot\mono\temp\bin\ExportRelease\win-x64 - Paste the two files to the res:// folder of the importing project
- In the importing project, create a 3D scene and add a new script to the root node
- In the new script, paste the _Ready function below
- Run the importing project and check the Debugger->Errors list
public override void _Ready()
{
// Prepare empty node
Node3D node = new Node3D();
AddChild(node);
// Load assembly and pck file
System.Reflection.Assembly.LoadFile(ProjectSettings.GlobalizePath("res://ExportingProject.dll"));
ProjectSettings.LoadResourcePack("res://ExportingProject.pck");
// Load script and assign it
Script script = ResourceLoader.Load<Script>("res://HelloWorld.cs");
node.SetScript(script);
}
Minimal reproduction project
About this issue
- Original URL
- State: open
- Created a year ago
- Reactions: 3
- Comments: 21 (4 by maintainers)
Commits related to this issue
- Update exporting_pcks.rst Updating C# assembly loading instructions according to https://github.com/godotengine/godot/issues/75352 — committed to Heremeus/godot-docs by Heremeus 8 months ago
I’m sorry you feel they way, but you’re not gonna get any promises that bugs will be fixed anywhere, not here, not with Unity, or any other commercial project, sure they have more resources, but no one can, or should, promise that bugs will be fixed. There’s plenty of bugs that have been present in bit commercial projects for years.
It’s of course not optimal, but this is a community driven project, based on best efforts and voluntary work. We who contribute here, save for a few people who actually are paid in various ways or sponsored, get no direct reward. And some of us spend significant portions of our spare time doing it, because we want to, and demand nothing in return. And I’m not complaining or demanding praise or thanks, just frankly stating what many of us who make this engine possible do and feel.
And honestly it’s disheartening when people complain over having an entirely free engine, with no royalty, no restrictions, and a massive community that pretty much every single day make improvements on some part of it, and it isn’t perfect.
I wasn’t telling you “if you want it fixed then fix it yourself”, I said “if you can help with this you are welcome to!”… And responded to your attitude that implied that bugs reported in this engine are not worked on, responded to, and resolved.
Quite honestly, this is one of the most disappointing answers that you could have given. Yes, I am aware that the bug is labeled as still open. Yes, I am aware that hoping that there was progress on the bug was a long shot. Yes, I am aware that every project is going to have bugs and broken features. No, I am not going to invest the significant amount of time it would take to learn the engine systems and implement the feature myself.
Godot as a whole is positioning itself to be a viable alternative to engines such as Unity and especially Unreal Engine when it comes to developing 2D games or 3D games that don’t require AAA visuals. However, wanting to have broader appeal means that you can’t hide behind the “We’re open source, so fix it yourself!” non-answer if you want to be taken seriously. You may consider that answer acceptable from the perspective of an open source project contributor, but it is significantly less so from an outsider’s perspective.
Would it be possible for me to learn enough about the engine and implement the feature myself? Perhaps. But that’s certainly not always going to be the case, especially since Godot is a beginner friendly engine by nature of having strong 2D support. It’s not unreasonable to think that some beginner developer might implement a game in Godot and then decide to learn how to make it moddable and encounter this issue. I would not expect someone with minimal programming experience to dive into Godot’s code and implement such a feature themselves.
As it stands, I have very little invested in Godot at the moment. I would like to invest more time into Godot. But answers such as this are not encouraging. Releasing DLC or making a game moddable is not some obscure use case for game developers. If such a feature is so fundamentally broken that it flat out doesn’t work, how many other features should I expect to come across that flat out don’t work either? I am not willing to invest the considerable amount of time it would take to release a well polished game if the platform I am working with is simply going to tell me to implement or fix it myself any time I come across a bug or broken feature.
Is this getting fixed in 4.2
Godot is a community ran project and bugs are fixed on best effort basis. If there is no one skilled enough in the area to fix, there is no fix… sadly.
Unfortunately from what I understand C# is one of the areas where it’s currently lacking (the two major c# guys decided to go on holidays or just take a break). (The other area where there’s a dearth of contributors is physics)
While the docs pages says this works like that and the page claims to be up to date, it is also wrong.
This feature has simply never been implemented after the move to .NET 6 for Godot 4.
https://github.com/OrdinaryGizmos/godot/commit/afa885888475372a34624e6394f8a93af1511322
I found a fix. The issue is that for Godot to know that there are scripts in your DLL, it has to call
Godot.Bridge.ScriptManagerBridge.LookupScriptsInAssembly(assembly);Further complicating the matter, the
AssemblyAttributethat it looks for isAssemblyHasScriptsAttributeand this is loaded fromGodotSharp.dllin a differentAssemblyLoadContextthan the game.My patch adds a custom resolver to the
Main.csfile in the mono glue that loadsGodotSharp.dll(or any dependencies) into the correctAssemblyLoadContext.After loading the assembly you will need to call
Godot.Bridge.ScriptManagerBridge.LookupScriptsInAssembly(assembly);This was tested on Godot 4.2-dev6 for my game. I plan on opening a pull request.
UPDATE: This fix in the commit is only for tools enabled builds. I am working on a fix for exported releases.
NEW UPDATE: I upgraded to 4.2-beta5 and rewrote my changes. You shouldn’t need to modify the engine code at all. All you need to do when loading a DLL is the following 3 lines. In this case
dllFileis abyte[]that I preloaded.@Heremeus Can you try out these three lines and see if that fixes it for you?