Repository: godotengine/godot (language: cpp)

Issue:
Script reference is broken when script is moved in FileSystem dock
### Tested versions

4.4 beta1
Didn't test other versions, but probably a regression.

### System information

W10

### Issue description

When you have a script opened and then you move it to another directory, the script reference in the editor is broken. The internal path does not update, so re-focusing editor causes errors about missing file and trying to save the file will have no effect.

### Steps to reproduce

1. Open a script file in script editor
2. In FileSystem dock, move the file to another directory
3. Open the moved file in external editor
4. In Godot, modify and save the still opened script
5. See in external editor that changes are not saved

Alternatively:
3. Unfocus and focus the editor
4. Error in output

### Minimal reproduction project (MRP)

N/A


Discussion / hints:
Investigated a bit and something weird is going on.

The bug only happens if both the scene and its script are open. During the filesystem dock move, a scene reload is requested, which ends up asking the script editor to edit the script. When iterating over the already opened scripts in the script editor, the following check for whether the script is already open weirdly fails:

https://github.com/godotengine/godot/blob/0726d3c7d5125d1a72ec318a2ec4ff11f9f7f8bb/editor/plugins/script_editor_plugin.cpp#L2564

Try setting a breakpoint here and then moving the file, the debugger shows 2 different objects with different pointer addresses and refcounts. The `path_cache` value also differs. The object with the correct path is the one passed to the function, and the wrong path belongs to the object returned by `se->get_edited_resource()`.
It's another regression from #96499
CC @beev1s
Investigated some more and I think that PR should be reverted.

It is difficult to pin down, but it seems that, by sometimes avoiding registration in `ResourceCache`, the scripts end up getting duplicated. Some codepaths assume that scripts will be in the `ResourceCache`, so it doesn't seem like a good idea to occasionally avoid it.

One of the reasons for duplication seems to be this getting skipped when moving (because the script is not in the `ResourceCache`)

https://github.com/godotengine/godot/blob/1586c5674bbafe1d7f4bd457d446f132b475890c/editor/filesystem_dock.cpp#L1560-L1577

The `set_path()` call would normally update the path in the `GDScriptCache`, but it gets skipped, then if the scene the script is attached to is open, the scene reloads the script, which is not found in the `GDScriptCache` at the new path, then the script gets recompiled and duplicated.

Fix patch:
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp
index 2383401630c4..8ff0c63bd451 100644
--- a/modules/gdscript/gdscript.cpp
+++ b/modules/gdscript/gdscript.cpp
@@ -1075,26 +1075,6 @@ void GDScript::_bind_methods() {
 	ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "new", &GDScript::_new, MethodInfo("new"));
 }
 
-void GDScript::set_path_cache(const String &p_path) {
-	if (ResourceCache::has(p_path)) {
-		set_path(p_path, true);
-		return;
-	}
-
-	if (is_root_script()) {
-		Script::set_path_cache(p_path);
-	}
-
-	String old_path = path;
-	path = p_path;
-	path_valid = true;
-	GDScriptCache::move_script(old_path, p_path);
-
-	for (KeyValue<StringName, Ref<GDScript>> &kv : subclasses) {
-		kv.value->set_path_cache(p_path);
-	}
-}
-
 void GDScript::set_path(const String &p_path, bool p_take_over) {
 	if (is_root_script()) {
 		Script::set_path(p_path, p_take_over);
diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h
index 9e96b8833496..fa141d65ac5e 100644
--- a/modules/gdscript/gdscript.h
+++ b/modules/gdscript/gdscript.h
@@ -309,7 +309,6 @@ class GDScript : public Script {
 
 	virtual Error reload(bool p_keep_state = false) override;
 
-	virtual void set_path_cache(const String &p_path) override;
 	virtual void set_path(const String &p_path, bool p_take_over = false) override;
 	String get_script_path() const;
 	Error load_source_code(const String &p_path);
diff --git a/modules/gdscript/gdscript_cache.cpp b/modules/gdscript/gdscript_cache.cpp
index c9a5f26c82b4..90af67ccd609 100644
--- a/modules/gdscript/gdscript_cache.cpp
+++ b/modules/gdscript/gdscript_cache.cpp
@@ -312,7 +312,7 @@ Ref<GDScript> GDScriptCache::get_shallow_script(const String &p_path, Error &r_e
 
 	Ref<GDScript> script;
 	script.instantiate();
-	script->set_path_cache(p_path);
+	script->set_path(p_path, true);
 	if (remapped_path.get_extension().to_lower() == "gdc") {
 		Vector<uint8_t> buffer = get_binary_tokens(remapped_path);
 		if (buffer.is_empty()) {
@@ -360,7 +360,6 @@ Ref<GDScript> GDScriptCache::get_full_script(const String &p_path, Error &r_erro
 			return script;
 		}
 	}
-	script->set_path(p_path, true);
 
 	const String remapped_path = ResourceLoader::path_remap(p_path);
 


Test patch: