godotengine / godot

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

Improve error message for calling non-tool scripts from tool scripts #36592

Open aaronfranke opened 4 years ago

aaronfranke commented 4 years ago

Godot version: 3.2+

OS/device including version: Applies to all versions.

Issue description:

if current_node.has_method("set_view_mode"):
        current_node.set_view_mode(view_mode_index)

This gave me the error message: Invalid call. Nonexistent function 'set_view_mode'

This was extremely confusing until I asked for help online and we realized that current_node's script was missing the tool keyword and this code was in a tool script. It would be very helpful if there was a better error message when this situation occurs. Perhaps something like:

Cannot run set_view_mode on base [whatever] in the editor because the script is not a tool script.

theoway commented 4 years ago

@aaronfranke I'm not getting your point. Could you please show the steps to reproduce the error?

Zireael07 commented 4 years ago

A tool script cannot use things from scripts that are not tool scripts themselves, simply put.

theoway commented 4 years ago

@Zireael07 I tried to reproduce it, but couldn't. I made a tool script and tried to call a method from a non-tool script, but it worked. My engine version is 3.2 If anyone is getting the error, please do tell how to reproduce it,

dagophil commented 4 years ago

I just ran into the same issue and created a small project to reproduce it. I am using Godot Engine v3.2.1.stable.official.

gd_tool_logs_error.zip

Steps to reproduce:

The SomeTool node has the following script:

tool
extends Node

export var entity: NodePath setget _set_entity

func _set_entity(value: NodePath) -> void:
    entity = value
    var node := get_node_or_null(value)
    if node and node.has_method("do_it"):
        node.do_it()
nhartung commented 3 years ago

Confirmed on 3.2.2.

I have a tool script that does:

assert(parent.has_method("get_input_direction"))
var direction = parent.get_input_direction()

and the parent object (non-tool) in this case:

func get_input_direction():
    return InputLib.Movement.get_input_direction()

gives the error: "Invalid call. Nonexistent function 'get_input_direction' in base 'Area2D (Player.gd)'.

What's most annoying about this is that the error message is constantly produced, at a fast rate. I left my PC running overnight and came back to Godot spiking my CPU until I cleared the Output window in the editor.

nhartung commented 3 years ago

Also, is it true that a tool script cannot call a function from a non-tool object? Essentially, is this intended to be an error, or not? It's not clear to me from the discussion above. I don't see why this can't be supported.

What's curious is that the assert statement doesn't give an error. Meaning, the interpreter clearly understands that the parent provides the function.

Arnklit commented 3 years ago

You can also run into this issue when calling non-tool scripts from stuff like EditorSpatialGizmoPlugin. Which is how I wasted half an hour not understanding why I got the error this morning. So it's any script that runs in Editor mode should give a warning if you are calling a function on another script that does not run in Editor mode.

npip99 commented 8 months ago

This would be very helpful. Even doing plenty of research, "@tool at the top of the file" still doesn't shed light on the issue as my script did have @tool.

In my case, I had a @tool script calling a script that wasn't @tool, it wasn't clear even from the forums that this isn't allowed. Apparently at a lower-level, Godot instances placeholder scripts in the editor instead of the real script.

res://scripts/Tools.gd:20 - Invalid call. Nonexistent function 'regenerate_terrain' in base 'MeshInstance3D (TerrainMesh.gd)'.

Tools.gd was @tool, but TerriainMesh.gd wasn't; Error message should more clearly say "TerrainMesh.gd cannot be called from the editor without @tool!", or something of the like.

juanjp600 commented 2 weeks ago

I think there should be a diagnostic preventing tools from interacting with non-tool scripts, but that might be problematic because it would be a breaking change for at least one plugin that exists in the wild. It seems that, at least for GDScript, this is not an issue when a tool only accesses a non-tool's exported fields. It is still an issue for .NET, as seen in this sample project: Tool export mismatch.zip