godotengine / godot

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

Editor cannot assign custom node to member in C# script when using [Tool] annotation #96306

Open msbc1999 opened 3 weeks ago

msbc1999 commented 3 weeks ago

Tested versions

v4.3.stable.mono.official [77dcf97d8]

System information

Godot v4.3.stable.mono - Windows 10.0.22631 - Vulkan (Forward+) - integrated AMD Radeon(TM) Graphics (Advanced Micro Devices, Inc.; 31.0.12029.10015) - AMD Ryzen 9 5900HX with Radeon Graphics (16 Threads)

Issue description

When assigning a custom node to an [Export] member in a C# script, a cast error occurs because the item is assigned with the super type instead of the actual custom node type. This issue only occurs when the script is executed in the editor using the [Tool] annotation. When the project runs normally, the types are assigned correctly.

/root/godot/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/ExceptionUtils.cs:113 - System.InvalidCastException: Unable to cast object of type 'Godot.Node' to type 'CustomNode'.
     at class_error.FailureNode.SetGodotClassPropertyValue(godot_string_name& name, godot_variant& value) in C:\Mateus\Godot Engine\Projetos\class_error\Godot.SourceGenerators\Godot.SourceGenerators.ScriptPropertiesGenerator\class_error.FailureNode_ScriptProperties.generated.cs:line 27
     at Godot.Bridge.CSharpInstanceBridge.Set(IntPtr godotObjectGCHandle, godot_string_name* name, godot_variant* value) in /root/godot/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/CSharpInstanceBridge.cs:line 57

Steps to reproduce

Steps to reproduce:

  1. Create a custom node in C#.
  2. Create a new scene and attach a C# script to a node in the scene.
  3. Annotate the C# script with [Tool] and use the [Export] attribute to specify the custom node type for a member.
  4. In the editor, try to assign the custom node to the exported member.

Expected behavior: The custom node should be correctly assigned to the member of its specific type. Actual behavior: A cast error occurs because the assigned item type is its super type rather than the specific custom node type. Note: This issue only occurs when the script is executed in the editor. When the project runs normally, the node types are assigned correctly.

Minimal reproduction project (MRP)

mrp.zip In the "failure_scene.tscn", there is a custom node property that cannot be assigned in the editor.

Maximilian-Seitz commented 3 weeks ago

So this happens because, in principle, Godot won't instantiate custom nodes/resources in the editor (outside run-time) if they aren't tools.

So what happens then is that your variable expects a value of that class, but no such value exists (since that class won't be instantiated by the editor). So the CustomNode will have type Node in the editor, but the variable expects a CustomNode, which doesn't exist, leading to the error. This is inevitable with how C# variables work.

Workarounds:

Potential fix:

It may be possible to only attempt to set variables like these (with values that won't be instantiated) at runtime, when the values correctly exist. This could leave them empty while it's a tool, and only fill the value later.

The question is: Is that a reasonable solution? This will still be an issue, and as a rule (right now) tool scripts are meant to only interact with other tool scripts.

msbc1999 commented 3 weeks ago

With a [Tool] annotation, it works fine. However, I believe that, at the very least, the editor should prevent assigning non-tool custom types to a tool script, or perhaps provide a warning in the property. In GDScript, everything works because of the language’s loose typing nature, but in C#, as mentioned, it’s due to how variables work.

For now, I can work around this by making my custom node a tool. Thank you, guys. Have a nice day!