Jump to content

Corrupted save file for Pokemon Ruby


Codeburner

Recommended Posts

Hi,

Short Version:

I have a corrupted save file for Pokemon Ruby and I'm not entirely sure what is wrong with it. I was hoping to see if there's any way we can fix the file and use it again because I had put 40+ hours in it. 

 

Long Version:

I have a cartridge for Pokemon Ruby and I have been playing it using an Analogue Pocket. The Pocket doesn't really secure the Gameboy Advance cartridges very well and they can easily disconnect. While I was loading up the game in the Pocket (I just saw the black screen with the Pokemon copyright details), I accidentally pushed the cartridge out with my hands. I turned it off because it was making a glitch sound and when I turned it on again, the game gave me the message that the save file was corrupted and it's was forcing me to start a new game. I know that there are two game slots in the save file, so I started a new game and saved it immediately to see if moving to the other slot could solve the problem, but it didn't. When you load the game, it says that the file is corrupted and it will use the backup instead (which is the one that has no progress at all). 

I used the Analogue Pocket's "Memories" feature where you can get save state files and I followed this post on Redit (Solution for extracting Pokemon Emerald cartridge saves with Memories) to extract the .sav file from the save state. 

I've been trying to find what the problem with the file is and even if it's possible to fix it. 

I looked at your PKHeX GitHub repository and created a simple .NET program that references the PKHeX.Core library to try to see if I could load the save file correctly. I can load the save file fine into your SAV3RS Class fine. However, I can see that it's selecting the slot with no progress as the active slot (much like the game) because the slot 0 doesn't have all the 14 data sectors correctly. 

using PKHeX.Core;

//  Extract the .sav file from the .sta file
byte[] saveData = ReadBytesInRange("PokemonRuby.sta", startOffset: 0x60F4A, endOffset: 0x80F49);

//  Save a copy of the .sav file
File.WriteAllBytes("PokemonRuby.sav", saveData);

Console.WriteLine("Checking sections of slot 0");
bool v0 = SAV3RS.IsAllMainSectorsPresent(saveData, 0, out _);

Console.WriteLine("Checking sections of slot 1");
bool v1 = SAV3RS.IsAllMainSectorsPresent(saveData, 1, out _);

Console.WriteLine("Does Slot 0 has all main sectors present? = {0}", v0);
Console.WriteLine("Does Slot 1 has all main sectors present? = {0}", v1);

Console.WriteLine("Done.");

static byte[] ReadBytesInRange(string filePath, long startOffset, long endOffset)
{
    using FileStream fileStream = new(filePath, FileMode.Open, FileAccess.Read);
    using BinaryReader binaryReader = new(fileStream);

    // Move the stream position to the start offset
    fileStream.Seek(startOffset, SeekOrigin.Begin);

    // Calculate the number of bytes to read
    int length = (int)(endOffset - startOffset);

    // Read the bytes into a byte array (inclusive)
    return binaryReader.ReadBytes(length + 1);
}

 If I log each section ID from the SAV3.IsAllMainSectorsPresent method I can see the sections from 0-13 loaded fine for slot 1, but not for slot 0.

Checking sections of slot 0
sector id = 5; BitTrack = 100000
sector id = 8; BitTrack = 100100000
sector id = 9; BitTrack = 1100100000
sector id = 8; BitTrack = 1100100000
sector id = 9; BitTrack = 1100100000
sector id = 12; BitTrack = 1001100100000
sector id = 13; BitTrack = 11001100100000
sector id = 0; BitTrack = 11001100100001
sector id = 1; BitTrack = 11001100100011
sector id = 0; BitTrack = 11001100100011
sector id = 1; BitTrack = 11001100100011
sector id = 4; BitTrack = 11001100110011
sector id = -1; BitTrack = 10000000000000000011001100110011
sector id = -1; BitTrack = 10000000000000000011001100110011
Checking sections of slot 1
sector id = 4; BitTrack = 10000
sector id = 5; BitTrack = 110000
sector id = 6; BitTrack = 1110000
sector id = 7; BitTrack = 11110000
sector id = 8; BitTrack = 111110000
sector id = 9; BitTrack = 1111110000
sector id = 10; BitTrack = 11111110000
sector id = 11; BitTrack = 111111110000
sector id = 12; BitTrack = 1111111110000
sector id = 13; BitTrack = 11111111110000
sector id = 0; BitTrack = 11111111110001
sector id = 1; BitTrack = 11111111110011
sector id = 2; BitTrack = 11111111110111
sector id = 3; BitTrack = 11111111111111
Does Slot 0 has all main sectors present? = False
Does Slot 1 has all main sectors present? = True
Done.

Maybe only section 12, 13, 0, 1 are loaded correctly for slot 0, but I'm not sure.

Do you have any clues or ideas? Have you seen something like this happen before? Is the data truly gone?

Thanks, I appreciate any help. Also, your coding syntax is beautiful. It's like reading Shakespeare in C#. 

PokemonRuby.sav PokemonRuby.sta

Edited by Codeburner
Finished incomplete sentenses
Link to comment
Share on other sites

If you open your save file in a hex editor (like HxD) you can visualize the 0x1000-sized save blocks for your data.

image.png

As you can see, the second slot has all block IDs present, while your other one has D,1,0,4 with duplicates containing different checksums. The games store box data in block chunks [3,D], and player data (progress, etc) in blocks [0,2]. Unfortunately, your backup there does not contain a block for #2.

I would try "transplanting" blocks (chunks of 0x1000 bytes) from the corrupt save into a donor save, to see what information you can recover. Maybe just overwriting the second save to see what data pops out in PKHeX.

Link to comment
Share on other sites

Hi thanks for the response, it really helped understand the save file better. I was able to copy the sections I had from the first slot over to the second one but nothing really changed, the game starts on the same initial save in Littleroot Town. Probably because I don’t have the sections 02 and 03. Unfortunately, I don’t think it’s possible to restore where I left off without the second section where we save the game state. 
Thanks again. 

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...