godotengine / godot

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

"Class hides a global script class" script parsing issue #94378

Open SeanRamey opened 3 months ago

SeanRamey commented 3 months ago

Tested versions

v4.3.beta3.official [82cedc83c]

System information

Godot v4.3.beta3 - EndeavourOS #1 SMP PREEMPT_DYNAMIC Wed, 12 Jun 2024 20:17:17 +0000 - X11 - Vulkan (Forward+) - dedicated NVIDIA GeForce RTX 2080 SUPER (nvidia; 550.90.07) - Intel(R) Core(TM) i5-8400 CPU @ 2.80GHz (6 Threads)

Issue description

In certain cases, you might decide to remake or otherwise archive a script, but still keep it in the project files in the original place. Usually all you need to do is rename the script to something to indicate it's archive or backup status. This isn't a problem normally, UNLESS you use the class_name declaration and want to keep the same name from the old script to the new one. Godot parses ALL scripts regardless of their actual use, so as a result, when two scripts declare the same class_name it fails to parse the script and breaks the game. This may be the intended behavior, but IMO, it shouldn't be parsing ALL scripts, but instead ONLY the scripts that will actually be ran.

EDIT: For my personal game project, this behavior doesn't seem to start until 4.2, and 4.3 makes it even more picky. Under 4.1.4, there is no issue in my game. However, I'm not sure what the reason is, and the only differences I see from the MRP are that my scripts are in subfolders, and the difference between 4.2 and 4.3 for my game is that 4.2 didn't have issue with scripts with the same name in different folders even with the same class_name, while 4.3 does have issue.

Steps to reproduce

Create a script attached to a node. Use the class_name declaration in this script. Duplicate the script with a different name. Parse error.

Minimal reproduction project (MRP)

global_script_class_issue.zip

HolonProduction commented 3 months ago

The problem is, that class_name classes that inherit node, get an entry in the create node dialogue. Also they could be used in every other script by their class name. In those cases there is no way to know which of your two scripts with the same class name is meant. Therefore class_names have to be unique across all scripts.

The class names are a unique identifier for a script so we need to know which script is meant, only given a class name. (Note, how this decision would have to be made before we could even say which scripts will run.)

Furthermore, we can't know which scripts are run with 100% certainty, since you can always use load to dynamically load and run a script. (Comes down to the halting problem. This could only be analyzed for a subset of all possible scripts, we can't rely on it therefore)

SeanRamey commented 3 months ago

The problem is, that class_name classes that inherit node, get an entry in the create node dialogue. Also they could be used in every other script by their class name. In those cases there is no way to know which of your two scripts with the same class name is meant. Therefore class_names have to be unique across all scripts.

The class names are a unique identifier for a script so we need to know which script is meant, only given a class name. (Note, how this decision would have to be made before we could even say which scripts will run.)

Furthermore, we can't know which scripts are run with 100% certainty, since you can always use load to dynamically load and run a script. (Comes down to the halting problem. This could only be analyzed for a subset of all possible scripts, we can't rely on it therefore)

I see, but can you explain why this was previously not a problem in Godot 4.1.4? Was that just a bug?

dalexeev commented 3 months ago

Unused scripts are not fully loaded, but the editor checks their class_names and registers them with the ScriptServer. Then, when loading a script with the same class_name, GDScript generates an error.

KoBeWi commented 3 months ago

When project is opened, Godot scans the filesystem and updates class cache. It's been made much more reliable recently. Previously some scripts could be missed because the scan was buggy.

You can add .gdignore file to your folder if you want to keep files, but have them ignored.

vasilevp commented 2 months ago

You can add .gdignore file to your folder if you want to keep files, but have them ignored.

I've just started seeing this in a project where I have a directory containing addons as submodules, which are then symlinked into the addons/ folder. Even though this directory has a .gdignore file, Godot is complaining about these duplicates, however things seem to work fine.