Repository: godotengine/godot (language: cpp)

Issue:
4.4rc: Repeatedly shows "files have been modified" dialog
### Tested versions

v4.4.rc1.official [8ed125b42]

I'm using Git for version control in my project.

### System information

Godot v4.4.rc1 - Windows 10 (build 19045) - Single-window, 1 monitor - Vulkan (Forward+)

### Issue description

Having updated my project to Godot 4.4rc1, I keep getting a dialog pop up for this particular `.gd` script file, saying it's been modified outside Godot, despite the file not having been modified. Every time I switch back to the Godot editor, the dialog shows up again.

![Image](https://github.com/user-attachments/assets/a255d76f-f004-4edf-85d8-9f2f6d22bb85)

### Steps to reproduce

Don't know; no idea why it's this particular file.

The problem seemed to fix itself when I closed all open scripts and reloaded the project.

### Minimal reproduction project (MRP)

It's strange; if I close anything, the problem *seems* to go away, but I'll look into it further if it reappears. Sorry if what I have for you is a bit useless (and feel free to close this issue if it's really no use).


Discussion / hints:
have you tried quitting your project, removing your .godot folder, and try reopening the project again?
It was the fix of similiar problem from the beta.
I also experienced this in Android Editor and closing the affected file solved the issue.
Also reproduced it on windows. I can only reproduce it with `export_presets.cfg`.

My steps to reproduce it:-

- Open export_presets.cfg in editor.
- Export your project (I'm exporting it to Android).
- Minimise the editor and then maximise it again.
I actually fixed the problem just by closing all the scripts I had open and then reloading the project; after that, the problem went away for me. Hopefully that will help narrow it down somewhat.
> I can only reproduce it with export_presets.cfg.

That's somewhat expected. The presets are modified (re-saved) when exporting and it counts as external modification. It goes away when when you pick either option that deals with the file.
I was able to reproduce using a shader file, but also in 4.4.beta3/4
I can confirm this error. I have this behavior only on one file of my project. No matter what I choose (reload or ignore) it will popup again after a delay. It's a script (*.gd) file which i don't modify outside of godot.
On 4.4rc1
Just reporting I am experiencing a similar issue on 4.4 stable.

> have you tried quitting your project, removing your .godot folder, and try reopening the project again? It was the fix of similiar problem from the beta.

Following this advice broke a whole bunch of local materials in my project. Might want to warn people. Given that it's part of the default gitignore, trying to roll back commits didn't fix it either, so I lost both the local materials and some work.
> Just reporting I am experiencing a similar issue on 4.4 stable.
> 
> > have you tried quitting your project, removing your .godot folder, and try reopening the project again? It was the fix of similiar problem from the beta.
> 
> Following this advice broke a whole bunch of local materials in my project. Might want to warn people. Given that it's part of the default gitignore, trying to roll back commits didn't fix it either, so I lost both the local materials and some work.

that's very strange, the .godot folder is not supposed to contain anything important to the project- that's why it can be .gitignored

if this were the case, anyone importing your project would have it broken like you have it now
> > Just reporting I am experiencing a similar issue on 4.4 stable.
> > > have you tried quitting your project, removing your .godot folder, and try reopening the project again? It was the fix of similiar problem from the beta.
> > 
> > 
> > Following this advice broke a whole bunch of local materials in my project. Might want to warn people. Given that it's part of the default gitignore, trying to roll back commits didn't fix it either, so I lost both the local materials and some work.
> 
> that's very strange, the .godot folder is not supposed to contain anything important to the project- that's why it can be .gitignored
> 
> if this were the case, anyone importing your project would have it broken like you have it now

What you say makes sense, and yet it is so. Having a pretty bad time trying to go from 4.3 to 4.4 so far.

Does anything in the .godot folder deal with UIDs? I'm pondering if something got messed up for me there.

> Following this advice broke a whole bunch of local materials in my project.

Broke in what way? They don't open? Got messed up?
And what do you mean exactly by "local materials"? If there are no changes to the source files, they should be recoverable.

EDIT:
Also it's not really related to this issue, so you should probably open a new one, with more details.
@KoBeWi - I've resolved it. The specifics of the case: I had a reference to a texture I had stored as a local shader parameter became invalid (purple and black checkers/missing texture). I've been using it pretty consistently for several weeks at this point, including having re-cloned my repository at some point. After deleting the .godot folder and re-opening the editor while hoping to solve this issue, the texture reference was missing even though it had not been moved or renamed. Godot 4.4 brings about the use of UIDs, and I did just upgrade my project, so that's why I'm curious about if /.godot has any relationship to the UID system.
There is UID cache in .godot, but it can be safely deleted and will be rebuilt automatically when missing.
Perhaps not when a project was recently upgraded with the UID generator tool.
I also just experienced this after upgrading to 4.4 stable from 4.3 stable on linux. In my case it happened with one specific gd script of no particular significance that I hadn't made changes to in weeks. It occurred reliably every time I ran the game from within the editor, and sometimes if the editor lost focus for a while. Not only were all of the timestamps reset on the affected file, but the inode number actually changed, as if the file was being replaced entirely with a copy. I did try closing and reopening the file, and also the whole editor, but the problem persisted. Removing .godot seems to have resolved it, but I haven't re-opened every single file and spent time using it after removing .godot. Will comment again if it recurs.

Don't know if it has any relevance, but I was toying with the new in-game editing tools, just selecting things not changing anything, and the editor crashed (leaving a frameless unresponsive game window). I do not recall if the problem started before this or not. The editor crashes on me fairly regularly anyway, but it's never done anything permanent like this before.

As an aside, realizing some random file is being entirely removed and replaced over and over for no known or intended reason deep in the bowels of months of work sure is disturbing. It might be good to offer via popup or checkbox to make a backup copy of the entire project before upgrading it. Even at the very least, a more stern warning like the UID thing.
I ran into this problem when I first upgraded my project from 4.3 to 4.4 and used the auto tool to help with the UIDs. Using the tool automatically opened all scripts from all scenes in the Editor, and I was getting this notification for 3 files on which I did no work. I closed all scripts in the Editor and the error stopped happening.
Managed to reproduce it from a copy made after upgrading my project but before removing .godot to fix it. Hope something in here helps narrow it down:

It is specifically triggered when saving any or all scenes, whether running the game or not. The editor doesn't notice the change until it loses and regains focus, but it's happening as soon as any scene is saved even if it has no relation to the affected script. So it naturally gets noticed most often when running the game from within the editor, which by default saves all scenes and switches focus.

Saving a script instead of a scene does not trigger it. Saving the affected script fixes it temporarily, until you close and reopen the editor. Closing either that script or all scripts doesn't fix it. It still happens if that script isn't open in the editor, you just don't see the change notification because it only watches open files. Having no scripts open and even a single unrelated scene open to be saved still triggers it.

So far, removing .godot is the only way I've permanently fixed it in my case, and it did hold up to some light use today with no unusual issues.
@asymptoticdivergence Can your share your reproducible copy? It would help to pin point the issue.
@syntaxerror247 It's almost 2 gigs zipped. I live out in the sticks, that's a 2+ hour upload on my DSL. Will see if it can be pruned down without accidentally fixing it. If not then I'll bite the bullet on the 2 hour upload 😆 
> @syntaxerror247 It's almost 2 gigs zipped. I live out in the sticks, that's a 2+ hour upload on my DSL. Will see if it can be pruned down without accidentally fixing it. If not then I'll bite the bullet on the 2 hour upload 😆 

No, I wouldn't ask to upload that big project.

It might be better to try to create a MRP (minimum reproduction project). Maybe we can try after creating a project in 4.3 and then migrating it to 4.4.
That sounds reasonable, if we can successfully guess what combination of factors leads to the failure. I'm assuming (perhaps incorrectly) that it would have been caught sooner if it were a simple common case.

I'll still try to shear what I have down and see what happens. Pretty sure the majority of that data is in unused assets I can get rid of right off the bat, if that doesn't shuffle some cache or index in a way which hides the problem.
https://github.com/asymptoticdivergence/godot-file-modified-bug Open that, save any scene even without changes, alt-tab away and back, and it'll tell you health.gd was modified. Or at least it reliably reproduces it on my system.

In the process of reducing it I discovered that removing .godot/imported preserves the bug, but removing .godot/editor removes the problem. As such, you'll also see a lot of cfg files for deleted files in the editor dir, because apparently it keeps those around even when you delete the files through the editor.

I know my content isn't the point, but fair warning anyway: I am not to be held liable if the sight of such a mess drives anybody to gouge their eyes out of their sockets with a rusty spoon. It's my first godot project, so I literally just ignored my usual concerns about file and code structure, naming and calling conventions, etc and just ran around trying everything different ways and discovering different aspects of the engine and language arbitrarily. That's why I don't mind sharing it, even though eventually I will refine it into an actual product: right now it's like that really broken car that you almost feel pity for any poor sap who tries to steal it
Thanks for sharing the project.
I won't go into details, but in your case the bug happened, because `health.gd` had Resource section unfolded:

![Image](https://github.com/user-attachments/assets/3a442437-61c5-4d22-adb9-e30ffcc34816)

When you fold it, the dialog no longer appears. Now that I know the cause I can come up with a fix.

Fix patch:
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index de52afa91cda..2261b14acbe3 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -1867,6 +1867,7 @@ int EditorNode::_save_external_resources(bool p_also_save_external_data) {
 		res->set_edited(false);
 	}
 
+	bool script_was_saved = false;
 	for (const String &E : edited_resources) {
 		Ref<Resource> res = ResourceCache::get_ref(E);
 		if (res.is_null()) {
@@ -1876,10 +1877,18 @@ int EditorNode::_save_external_resources(bool p_also_save_external_data) {
 		if (ps.is_valid()) {
 			continue; // Do not save PackedScenes, this will mess up the editor.
 		}
+		if (!script_was_saved) {
+			Ref<Script> scr = res;
+			script_was_saved = scr.is_valid();
+		}
 		ResourceSaver::save(res, res->get_path(), flg);
 		saved++;
 	}
 
+	if (script_was_saved) {
+		ScriptEditor::get_singleton()->update_script_times();
+	}
+
 	if (p_also_save_external_data) {
 		for (int i = 0; i < editor_data.get_editor_plugin_count(); i++) {
 			EditorPlugin *plugin = editor_data.get_editor_plugin(i);
diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp
index af7812abe806..d9bb5d79c544 100644
--- a/editor/plugins/script_editor_plugin.cpp
+++ b/editor/plugins/script_editor_plugin.cpp
@@ -2817,6 +2817,15 @@ void ScriptEditor::save_all_scripts() {
 	_update_script_names();
 }
 
+void ScriptEditor::update_script_times() {
+	for (int i = 0; i < tab_container->get_tab_count(); i++) {
+		ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i));
+		if (se) {
+			se->edited_file_data.last_modified_time = FileAccess::get_modified_time(se->edited_file_data.path);
+		}
+	}
+}
+
 void ScriptEditor::apply_scripts() const {
 	for (int i = 0; i < tab_container->get_tab_count(); i++) {
 		ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i));
diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h
index 02e0529a7cf6..30198f1cb1c6 100644
--- a/editor/plugins/script_editor_plugin.h
+++ b/editor/plugins/script_editor_plugin.h
@@ -569,6 +569,7 @@ class ScriptEditor : public PanelContainer {
 	PackedStringArray get_unsaved_scripts() const;
 	void save_current_script();
 	void save_all_scripts();
+	void update_script_times();
 
 	void set_window_layout(Ref<ConfigFile> p_layout);
 	void get_window_layout(Ref<ConfigFile> p_layout);


Test patch: