+ Reply to Thread
Results 1 to 10 of 10

Thread: Some questions about save files

  1. #1
    Member Tux's Avatar
    Join Date
    Jun 2011
    Age
    15
    Posts
    10

    Some questions about save files

    Hi,
    I'm currently developing a software which reads Pokémon save file data. Also, I have a few questions :
    • How does work the small/big blocks mechanics in a 256-kilobytes file ?
    • How does work the save file data in Generation III ?
    • Is the block footer structure the same beetween D/P/Pl/HG/SS/B/W ?
    • Where are located the ID, sID, 'Number of Party Pokémon', the Party Pokémon data, the PC Pokémon data in B/W? Same question for Generation III save file data.
    • Is something new about these save file informations beetween B/W and HG/SS ?
    • Is it the same blocks mechanics between B/W and HG/SS ? What are the blocks limits offsets in B/W ?
    Tux.

  2. #2
    Learning to breathe IRC VOPDeveloperGame Save ResearcherModerator codemonkey85's Avatar
    Join Date
    Apr 2009
    Location
    http://goo.gl/Wd4id
    Age
    27
    Posts
    800

    Re: Some questions about save files

    • For a 256 KB save file, I imagine there would be no backup blocks. But the game was not meant to save files of this size, so I never bothered with them personally.
    • The Gen III save structure is sort of complicated... I am looking for the documentation I used to figure it out so I don't have to try to explain it (since I'm sure I'd only befuddle you if I tried).

      EDIT: Ah, look what a quick Google search yields: http://furlocks-forest.net/wiki/?pag...BA_Save_Format

    • The block footers are very similar between all Gen IV games... I think there are minor differences in HGSS, but nothing too complicated IIRC.
    • Your best bet for locating the PKM data in B/W is to just use a save file containing a few PKM you know the PID of, and opening the save file in HxD or some other hex program and doing a search for those PIDs.
    • Um, yes?
    • I don't think B/W switch the blocks around like Gen IV did, making it much more straightforward to find the "current" information. I dunno anything specific about the B/W save data though.

    Also, don't forget that the Gen III PKM data looks different:

    http://bulbapedia.bulbagarden.net/wi...Generation_III

    http://bulbapedia.bulbagarden.net/wi...Generation_III

  3. #3
    Member Tux's Avatar
    Join Date
    Jun 2011
    Age
    15
    Posts
    10

    Re: Some questions about save files

    Thanks a lot ^^ !
    Also, I'm unable to recalculate the save file checksums --' . I have readen your PKMDS vb.net library (by the way, this is a excellent and useful library) source code, and have transcripted the checksums algorithm in C++, but I get wrong checksums ...
    For example, with 0 for begining block offset, and (0xC0EC + 20) for ending offset (inclusive) and 20 for the footer size, I get 0x5663 (or 0x6356) instead of 0x2306 (EDIT: 0x7A0A or 0x0A7A, offset 0xC0FE to 0xC0FF, sorry)

    Here is a part my source code :
    Code:
    int  Savefile::getSeeds(int * seeds) //Output is the 'seeds' parameter array
        {
            
    
                 int v0 = 0; //Signed 32-bit Integer
                 int v1;
                 int v2;
                 int result;
    
                do
                {   v1 = v0 << 8;
                    v2 = 0;
                    do
                    {    if ((unsigned char)(v1 >> 8 & 0x80) != 0) //unsigned char : unsigned 8-bit integer = Byte
                            v1 = (2 * v1) ^ 0x1021;
                        else
                            v1 *= 2;
             
                        v2 += 1;
                    }
                    while(v2 < 8);
                    result = (unsigned short) v1; //Unsigned 16-bit integer
                    seeds[v0] = result;
                    v0 ++;
                }
                while(v0 <= 0xFF);
                return result;
        }
    unsigned short calculateChecksum(FILE * savefile, unsigned int begin, unsigned int end, unsigned int footerSize)
        {
                 int seeds[0xFF];
                getSeeds(seeds);
                unsigned char * data = new unsigned char[end-begin-footerSize];
                fseek(savefile, begin, SEEK_SET); //Set the cursor at the beginning of the savefile + begin
                fread(data, 1, (end-begin) - footerSize, savefile); //Read end-begin-footerSize bytes of data into the array 'data'
    			
                 int checksum = 0xFFFF;
                 long long unsigned int i; //64-bit unsigned integer
                 int v4 = end - footerSize;
                 unsigned char v6;
    
                i = 0;
                while (v4 > 0)
                {
                    v4 -= 1;
                    v6 = (unsigned char)(data[i] ^ (unsigned char)(checksum >> 8));
                    checksum = (checksum << 8) ^ seeds[v6];
                    i++;
                }
    	    unsigned short retour = (unsigned short) checksum;
                delete[] data;
                // retour ^= 0;
                return retour;
        }
    Attached Files
    Last edited by Tux; Jun 11th, 2011 at 03:24 AM.

  4. #4
    Learning to breathe IRC VOPDeveloperGame Save ResearcherModerator codemonkey85's Avatar
    Join Date
    Apr 2009
    Location
    http://goo.gl/Wd4id
    Age
    27
    Posts
    800

    Re: Some questions about save files

    Just out of curiosity, which game's save file are you trying to calculate a checksum for?

    Also, I'm no help when it comes to C++.

  5. #5
    Member Tux's Avatar
    Join Date
    Jun 2011
    Age
    15
    Posts
    10

    Re: Some questions about save files

    I use my Pokémon Pearl's savefile.
    I don't understand what I got wrong ... Is The temporary variable(initializated at 0xFFFF), which is used to calculate the checksum , a signed 32-bit integer ?
    Which pairs of offsets (inclusive) should I use to calculate the checksum ?

  6. #6
    Learning to breathe IRC VOPDeveloperGame Save ResearcherModerator codemonkey85's Avatar
    Join Date
    Apr 2009
    Location
    http://goo.gl/Wd4id
    Age
    27
    Posts
    800

    Re: Some questions about save files

    Hmm. It's been quite some time since I've looked at this part of my library. I have a tight schedule this week but I'll try to look it over when I can.

  7. #7
    Member Tux's Avatar
    Join Date
    Jun 2011
    Age
    15
    Posts
    10

    Re: Some questions about save files

    Issue fixed ! (my program's generated checksum and Pokegen's are the same)
    The equivalent of the changes made in C++ are the following in VB .Net :
    Code:
     seeds = New Integer(&H100) {} 'instead of :  seeds = New Integer(&H100 - 1) {}, line 13304 in PKMDSLIB.vb of your library
    If (CType((v1 >> 8) And &H80, [Byte]) And &H80) <> 0 Then ' Instead of  : If (CType(v1 >> 8, [Byte]) And &H80) <> 0 Then, l. 13315, supposing CType() returns the 8 firts bits starting from right
    Also, thanks a lot for your help and for your library .

    PS : How is the checksum calculated in Gen III save files ?

  8. #8

    Re: Some questions about save files

    There are save file editors for gen 3, namely Pokemon Enciclopedia (spanish, translated on forums) and PokeStock (japanese).

    PSavFix (by loadingNOW iirc) corrects the Chksum, here's the code:

    Spoiler
    Code:
    ####MAKEFILE####
    #Change Dir to your GCC-bin dir
    
    DIR   := C:/MinGW/bin/
    CC      := $(DIR)gcc
    
    
    # --- proj
    PSavFix : Main.o 
    	$(CC) -o PSavFix Main.o
    
    PSavFIX.o : Main.c
    	$(CC) -c -O3 Main Main.c
    ##END MAKEFILE##
    ---------------------------------------------------------------
    ####MAIN.C####
    /*CODE C++*/
    #include 
    #include 
    #include 
    
    
    int Chksum(int length, int *Data)
    {
    	int Chk,i,tmp;
    	length = length>>2;
    	Chk=0;
    	for(i=0; i>16;
    	tmp +=Chk;
    
    	Chk = (tmp&0xFFFF);
    
    	return Chk;
    }
    
    
    int main(int argc, char** argv)
    {
    
    
    	char *Map,*p,*header;
    	int *Imap,*Data;
    	int Found,id,fix,CHK,OK,i;
    	FILE *fpm, *fp;
    	short *MapPtr;
    
    	short FLMAP[] = { 0xF24,0xF80,0xF80,0xF80,0xEC0,0xF80,0xF80,0xF80,0xF80,0xF80,0xF80,0xF80,0xF80,0x7D0,0x01C,0x100};
    	short RSMAP[] = { 0x890,0xF80,0xF80,0xF80,0xC40,0xF80,0xF80,0xF80,0xF80,0xF80,0xF80,0xF80,0xF80,0x7D0,0xF80,0xF80};
    	short MAX[]   = { 0xF80,0xF80,0xF80,0xF80,0xF80,0xF80,0xF80,0xF80,0xF80,0xF80,0xF80,0xF80,0xF80,0xF80,0xF80,0xF80};
    
    	OK   = 1;
    	fix  = 0;
    
    	if(argc!=4)
    	{
    		printf("Usage: %s [-fix|-nofix] [-RS|-FL|-MAX] [infile]\n", argv[0]);
    		return 0;
    	}
    
    
    	if(!strcmp(argv[2], "-RS"))
    	{
    		printf("Running in RS Mode\r\n");
    		MapPtr = &RSMAP[0];
    	}
    	else if(!strcmp(argv[2], "-FL"))
    	{
    		printf("Running in FL Mode\r\n");
    		MapPtr = &FLMAP[0];
    	}
    	else if(!strcmp(argv[2], "-MAX"))
    	{
    		printf("Running in MAXCompat Mode - note this mode is NOT recommented\r\n");
    		MapPtr = &MAX[0];
    	}
    	else
    	{
    		printf("Please select a mode (-RS -FL -MAX). Read readme for more Information. \r\n");
    		return 0;
    	}
    
    
    
    	// allocate main ram and load sav
    	header = (char *)malloc(0x1000);
    	Data = (int*)header;
    
    	printf("Loading: %s...\r\n", argv[3]);
    	fp = fopen(argv[3], "rb+");
    	if (!fp)
        {
    		printf("error loading sav \r\n");
            return 0;
        }	
    
        
    	//check if fix is ON
    	if(!strcmp(argv[1], "-fix"))
    	{
    		printf("Autofix: ON\r\n");
    		fix = 1;
    	}
    	else
    		printf("Autofix: OFF\r\n");
    
    
    
    	for(i = 0; i<0x20; i++)
    	{
    		fread(header, 1, 0x1000, fp);
    	    
    		CHK=Chksum(MapPtr[Data[1021]&0xF], Data);
    		Found = (Data[1021]>>16)&0xFFFF;
    		id = (Data[1021])&0xFF;
    
    		if((CHK==Found && Data[1022]==0x8012025) || (id==0 && CHK==0 && Found==0))
    			printf("Size: %03X Segment: %02X Calc: %04X Found: %04X Sig: %08X - OK\r\n",MapPtr[Data[1021]&0xF],id, CHK,Found, Data[1022]);
    		else
    		{
    			printf("Size: %03X Segment: %02X Calc: %04X Found: %04X Sig: %08X \r\n",MapPtr[Data[1021]&0xF],id, CHK,Found, Data[1022]);
    			OK = 0;
    			if(fix)
    			{
    				fseek(fp, -0xa,SEEK_CUR);
    				header[0xff6]= (0xFF &CHK);
    				header[0xff7]= (0xFF &(CHK>>8));
    				Data[1022]=0x8012025;		
    				p = &header[0xff6];
    				fwrite(p,1,6,fp);
    				fseek(fp, 0x4,SEEK_CUR);
    			}
    
    		}
    	}
    
    	fclose(fp);
        
    	if(OK)
    		printf("No Problems found :)\r\n");
    	else
    		printf("Problems found! :( (remember Sig=08012025)\r\n");
    	
    	return 0;
    }
    ##END MAIN.C##

  9. #9
    Member Tux's Avatar
    Join Date
    Jun 2011
    Age
    15
    Posts
    10

    Re: Some questions about save files

    That's great, thanks! Is it the same algorithm/"Map" for Pokémon Emerald?

  10. #10

    Re: Some questions about save files

    I'm not sure, probably.

+ Reply to Thread

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
PPN Top 50