godotengine / godot

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

.vs Visual Script file corrupting to RSCC #32511

Open sinaiyuc opened 5 years ago

sinaiyuc commented 5 years ago

Bugsquad note: This issue has been confirmed several times already. No need to confirm it further.


Godot version: 3.1.1 and 3.2

OS/device including version: Windows 10 and Mac OS 10.14.6

Issue description: Visual Script files are becoming corrupted and the data disappears. This is bad because you lose your entire visual graph and there is no way to get it back. What happens is that when you open up one of the corrupted files a blank .vs file opens at the top of the list and the file itself opens in the code editor and just says "RSCC."

Steps to reproduce: I am not sure exactly how to get the file to this state, but I have attached a minimal project below where there are 2 .vs files that are 1 version off of each other. I use Dropbox and so I can go back every time the file changes. One of the files doesn't corrupt (the one that has (1) at the end) and the other file will corrupt when you open up the file in GODOT. These files are 1 change apart from each other. So what ever I did to corrupt them I did right between. The next file (which I didn't include) is literally just RSCC with no other data in the file. Those 3 files all happened within minutes of each other.

I haven't been able to figure out exactly what causes the file to corrupt, but maybe someone smarter than me can see the difference between the two files and figure out what happened.

Minimal reproduction project: InfiniteRunner copy.zip

fire commented 5 years ago

I tried recreating the problem and got this crash on start.

image

InfiniteRunner copy.zip

akien-mga commented 5 years ago

RSCC is the magic header for compressed resource files. So if the file only contains this, it means that it's basically empty, and thus invalid. So there might be two issues:

fire commented 5 years ago

This might be a clue to why it breaks:

Baroon ValmYesterday at 12:02

also i have almost nothing to contribute to the issue there as all useful info is basicly there.. tho there IS a way to get the code back, that nameless little VS that is loaded on top contains the "Broken" code, and also you can just Duplicate the code that is loaded in .txt or even rename it and open it and it'll be exactly like it should be

akien-mga commented 4 years ago

I tried to write some error handling to solve the crash reported by @fire, but I get more crashes further down the road due to bad handling of various FileAccess-derived pointers.

Leaving it at it for now, but in case someone wants to dig further:

diff --git a/core/io/file_access_compressed.cpp b/core/io/file_access_compressed.cpp
index 87ead37b91..345605f48a 100644
--- a/core/io/file_access_compressed.cpp
+++ b/core/io/file_access_compressed.cpp
@@ -64,6 +64,8 @@ Error FileAccessCompressed::open_after_magic(FileAccess *p_base) {
    cmode = (Compression::Mode)f->get_32();
    block_size = f->get_32();
    read_total = f->get_32();
+   ERR_FAIL_COND_V_MSG(block_size == 0, ERR_INVALID_DATA,
+           "Can't open compressed file '" + f->get_path() + "' with block size 0, it is corrupted.");
    int bc = (read_total / block_size) + 1;
    int acc_ofs = f->get_position() + bc * 4;
    int max_bs = 0;
@@ -125,13 +127,11 @@ Error FileAccessCompressed::_open(const String &p_path, int p_mode_flags) {
        char rmagic[5];
        f->get_buffer((uint8_t *)rmagic, 4);
        rmagic[4] = 0;
-       if (magic != rmagic) {
+       if (magic != rmagic || open_after_magic(f) != OK) {
            memdelete(f);
            f = NULL;
            return ERR_FILE_UNRECOGNIZED;
        }
-
-       open_after_magic(f);
    }

    return OK;
diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp
index 272d5c1116..27b2ea0a89 100644
--- a/core/io/resource_format_binary.cpp
+++ b/core/io/resource_format_binary.cpp
@@ -836,15 +836,19 @@ void ResourceInteractiveLoaderBinary::open(FileAccess *p_f) {
    uint8_t header[4];
    f->get_buffer(header, 4);
    if (header[0] == 'R' && header[1] == 'S' && header[2] == 'C' && header[3] == 'C') {
-       //compressed
+       // Compressed.
        FileAccessCompressed *fac = memnew(FileAccessCompressed);
-       fac->open_after_magic(f);
+       error = fac->open_after_magic(f);
+       if (error != OK) {
+           f->close();
+           memdelete(fac);
+           ERR_FAIL_MSG("Corrupted compressed binary resource file: " + local_path + ".");
+       }
        f = fac;
-
    } else if (header[0] != 'R' || header[1] != 'S' || header[2] != 'R' || header[3] != 'C') {
-       //not normal
-
+       // Not normal.
        error = ERR_FILE_UNRECOGNIZED;
+       f->close();
        ERR_FAIL_MSG("Unrecognized binary resource file: " + local_path + ".");
    }

@@ -931,14 +935,19 @@ String ResourceInteractiveLoaderBinary::recognize(FileAccess *p_f) {
    uint8_t header[4];
    f->get_buffer(header, 4);
    if (header[0] == 'R' && header[1] == 'S' && header[2] == 'C' && header[3] == 'C') {
-       //compressed
+       // Compressed.
        FileAccessCompressed *fac = memnew(FileAccessCompressed);
-       fac->open_after_magic(f);
+       error = fac->open_after_magic(f);
+       if (error != OK) {
+           f->close();
+           memdelete(fac);
+           return "";
+       }
        f = fac;
-
    } else if (header[0] != 'R' || header[1] != 'S' || header[2] != 'R' || header[3] != 'C') {
-       //not normal
+       // Not normal.
        error = ERR_FILE_UNRECOGNIZED;
+       f->close();
        return "";
    }

@@ -1043,26 +1052,29 @@ void ResourceFormatLoaderBinary::get_dependencies(const String &p_path, List<Str

 Error ResourceFormatLoaderBinary::rename_dependencies(const String &p_path, const Map<String, String> &p_map) {

-   //Error error=OK;
-
    FileAccess *f = FileAccess::open(p_path, FileAccess::READ);
    ERR_FAIL_COND_V_MSG(!f, ERR_CANT_OPEN, "Cannot open file '" + p_path + "'.");

-   FileAccess *fw = NULL; //=FileAccess::open(p_path+".depren");
+   FileAccess *fw = NULL;

    String local_path = p_path.get_base_dir();

    uint8_t header[4];
    f->get_buffer(header, 4);
    if (header[0] == 'R' && header[1] == 'S' && header[2] == 'C' && header[3] == 'C') {
-       //compressed
+       // Compressed.
        FileAccessCompressed *fac = memnew(FileAccessCompressed);
-       fac->open_after_magic(f);
+       Error err = fac->open_after_magic(f);
+       if (err) {
+           f->close();
+           memdelete(fac);
+           ERR_FAIL_V_MSG(err, "Corrupted compressed binary resource file: " + local_path + ".");
+       }
        f = fac;

        FileAccessCompressed *facw = memnew(FileAccessCompressed);
        facw->configure("RSCC");
-       Error err = facw->_open(p_path + ".depren", FileAccess::WRITE);
+       err = facw->_open(p_path + ".depren", FileAccess::WRITE);
        if (err) {
            memdelete(fac);
            memdelete(facw);
@@ -1072,9 +1084,7 @@ Error ResourceFormatLoaderBinary::rename_dependencies(const String &p_path, cons
        fw = facw;

    } else if (header[0] != 'R' || header[1] != 'S' || header[2] != 'R' || header[3] != 'C') {
-       //not normal
-
-       //error=ERR_FILE_UNRECOGNIZED;
+       // Not normal.
        memdelete(f);
        ERR_FAIL_V_MSG(ERR_FILE_UNRECOGNIZED, "Unrecognized binary resource file '" + local_path + "'.");
    } else {
@@ -1247,7 +1257,7 @@ String ResourceFormatLoaderBinary::get_resource_type(const String &p_path) const

    FileAccess *f = FileAccess::open(p_path, FileAccess::READ);
    if (!f) {
-       return ""; //could not rwead
+       return ""; // Could not read.
    }

    Ref<ResourceInteractiveLoaderBinary> ria = memnew(ResourceInteractiveLoaderBinary);
akien-mga commented 4 years ago

Regarding the OP, the file is saved as a text file with "RSCC" probably because:

So what would be needed is:

And fixing the crash in any case on such an invalid file as per above comment.

ghost commented 4 years ago

This bug is still in 3.2.1 My VS's are getting corrupted randomly!

bojidar-bg commented 4 years ago

@Gerarama the code change intended to fix this issue was merged in 3.2.1; 3.2.0 might still have the issue. Can you confirm you are on 3.2.1 or higher?

ghost commented 4 years ago

@bojidar-bg Oops , am sorry , i meant 3.2.1 not 3.2.0. i Edited it, Yes this problem happens in the new stable version. in fact , it happened twice at same time in my project , am forced to make backup to my project every time to make sure i don't lose my work.

Also , looks like this bug happens when copying Custom nodes, as the script linked to the custom node ALSO get copyed , and not refrenced to the saved script. I hope this help

mhilbrunner commented 4 years ago

am forced to make backup to my project every time to make sure i don't lose my work.

Version control like Git saves a lot of headaches

ghost commented 4 years ago

This bug is Horribly evil , There is one script that keeps getting corrupted over and over , and i keep restoring it over and over. This bug is so weird.

ghost commented 4 years ago

Update : When a script gets this problem , replacing it , restarting the engine , it get corrupte again. no matter what you do , it will keep getting corrupted. everytime you restart the engine!

ghost commented 4 years ago

Update , I have done some debugging to see when file get corrupted.

When you open godot , after restarting the file it remind the same size. and all Ok But inside Godot Editor you find it correpted , even tho All the data there.

Annotation 2020-06-10 092903

when opening Godot all this data goes into a new tab with no name as showen in this image.

Annostation 2020-06-10 092903

As soon as you start your game , or save the file , It get corrupted. So godot it self is cosing the file to be corrupted. and when a file get targeted , it will keep getting corrupted UNTIL you change it name to something else.

I hope this help to get rid of this Bug once and for all. Thanks

swarnimarun commented 4 years ago

Oh nice. That is sort of inline with my hypothesis of the bug.

Just there were too many places of fault to figure out the cause, this should help narrow it down further hopefully I can find and fix it soon.

mrjustaguy commented 4 years ago

The file loses all the data when you run/save the project because it saves it to just "RSCC", thus removing all the data..

The fact that all the data is in the file intact, and is in fact read by the editor (just seperated into a noname file, and only one of the scripts is ever in that form, only when the project is opened and doesn't matter if the script is opened/closed) might mean that there is something wrong with whatever is used to identify the script as what it is, and whatever it is, it is a part of said script, as moving the broken script between projects and Godot versions doesn't change it's broken state..

On the other hand, a simple rename of the file fixes the issue even without any modifications to said file (just rename in the OS when Godot isn't looking aka is dead)

The more interesting fact is that if a broken file is renamed to something else and then works just fine, and then put in a totally isolated Godot Project it will break if the name was placed back to it's original "broken" prior to project opening compared to the same scenario with a different name where it works fine despite the fact the project seeing both of the files for the very first time.. The Broken name however, only impacts the broken script, and should a new script be made with the name of the broken one it works fine...

All that said, Very strange behavior that leaves only guessing on the table as to what exactly is going on, however it's probably related with the loading...

mrjustaguy commented 4 years ago

Interesting.. VERY interesting..

See this: VS.zip

Cub.vs works, Cube.vs name is broken..

I made a script that loads Cub.vs and saves it as Cube.vs after that, I compared Cub.vs data to Cube.vs data and turned that into a string, and used Similarity() aand I should have gotten 1, instead I've gotten 0.998922 meaning the data isn't exactly the same, but it should be....

Edit: Oh, nvm upon closer inspection it's just the instance numbers being different, however the saved file even despite the lack of compression (it's 8kb from 2kb and even partially readable) still breaks with it's current name.

eameres commented 3 years ago

I just experienced this with 3.3.2 Is this still open?

mrjustaguy commented 3 years ago

Yes, very much open on the 3.x branch, Not sure about 4.0

Gallilus commented 3 years ago

I have had this issue many times when moving scripts between custom builds. So when I found the workaround I posted #51291 Now Tested in 3.4beta3

  1. Open the project in 3.4beta3 Cub.vs = OK ( in my experience its 50/50. Sometimes imported files are not able to open )
  2. Cub.vs -> Cube.vs + restart project = RSCC
  3. Cub.vs -> Cubee.tres + restart project = OK
  4. Cubee.tres -> Cubeee.vs + restart project = OK
  5. Cubeee.vs -> Cubeeee.vs + restart project = OK

VS (2).zip

So making a uneducated that we need to look for the error in the save system. Is there a version control system in the compressed? maybe that checks for backwards compatibility issues?

kezzbracey commented 2 years ago

Adding a report that this issue is occurring on 3.3.3 stable, Ubuntu Linux.

Have lost a couple of scripts. Renaming hasn't worked to restore them so far.

Will report back if I learn anything new.

mrjustaguy commented 2 years ago

Renaming hasn't worked to restore them probably because they got saved after that to their corrupted state resulting in the file becoming just a txt with RSCC and absolutely no other data, not even corrupt data, just an RSCC line and not a single byte more is left. Because of this, Rename has to be done the moment you spot the RSCC issue, and don't under any circumstance try to save the file, or the data is permanently deleted.

derammo commented 2 years ago

I had a vs file get truncated several times today on 4.0 master during testing. At one point, it got truncated to just "RSCC" and then the bytes 0x02 0x0a

derammo commented 2 years ago

I am now able to observe this under the debugger. It is definitely a real bug and not related to any random corruption.

Zireael07 commented 2 years ago

Can you share the details of what happens? This way it can get fixed, hopefully...

derammo commented 2 years ago

@Zireael07 I am working on that. My comment was meant to say I confirmed this is a real bug and am working on it. If you would like to hear the half-baked status :) I am available on chat.

fire commented 2 years ago

I'd like the hear the half-baked status.

YuriSizov commented 2 years ago

I'm removing this from the 4.0 milestone as visual scripting is no longer a part of Godot 4. Last time I'd checked, this issue was constantly present in master, so maybe we should move this report to the new VS repo. But since it is reported for 3.x as well, we might want to fix it in 3.x. So for the moment I'm keeping the issue in this repo.