Editing Hey! Pikmin save file
Jump to navigation
Jump to search
Warning: You are not logged in. Your IP address will be publicly visible if you make any edits. If you log in or create an account, your edits will be attributed to your username, along with other benefits.
The edit can be undone. Please check the comparison below to verify that this is what you want to do, and then save the changes below to finish undoing the edit.
Latest revision | Your text | ||
Line 3: | Line 3: | ||
== Format == | == Format == | ||
− | The save data is split into several blocks that start with 4-byte magic words | + | The save data is split into several blocks that start with 4-byte magic words. |
=== SAVE === | === SAVE === | ||
Line 11: | Line 11: | ||
! File || Block | ! File || Block | ||
|- | |- | ||
− | | <code> | + | | <code>0000</code> || <code>0000</code> || 4 bytes || Block magic word || Always <code>SAVE</code>. |
|- | |- | ||
− | | <code> | + | | <code>000C</code> || <code>000C</code> || 4 bytes || Save data checksum || {{unsure|Calculated using an unknown algorithm.}} |
|} | |} | ||
=== NEWS === | === NEWS === | ||
− | |||
{| class="wikitable sortable" | {| class="wikitable sortable" | ||
! colspan="2" | Offset || rowspan="2" | Length || rowspan="2" | Field || rowspan="2" | Notes | ! colspan="2" | Offset || rowspan="2" | Length || rowspan="2" | Field || rowspan="2" | Notes | ||
Line 23: | Line 22: | ||
! File || Block | ! File || Block | ||
|- | |- | ||
− | | <code> | + | | <code>0010</code> || <code>0000</code> || 4 bytes || Block magic word || Always <code>NEWS</code>. |
|- | |- | ||
− | |||
− | |||
− | |||
− | |||
− | |||
|} | |} | ||
Line 39: | Line 33: | ||
! File || Block | ! File || Block | ||
|- | |- | ||
− | | <code> | + | | <code>0020</code> || <code>0000</code> || 4 bytes || Block magic word || Always <code>OPTI</code>. |
|- | |- | ||
− | | <code> | + | | <code>0024</code> || <code>0004</code> || 4 bytes || {{unknown|Unknown}} || |
|- | |- | ||
− | | <code> | + | | <code>0028</code> || <code>0008</code> || 1 byte || Music volume || <code>00</code> to <code>03</code>. |
|- | |- | ||
− | | <code> | + | | <code>0029</code> || <code>0009</code> || 1 byte || Sound effects volume || <code>00</code> to <code>03</code>. |
|- | |- | ||
− | | <code> | + | | <code>002A</code> || <code>000A</code> || 2 bytes || {{unknown|Unknown}} || |
|} | |} | ||
=== PBUF === | === PBUF === | ||
− | |||
{| class="wikitable sortable" | {| class="wikitable sortable" | ||
! colspan="2" | Offset || rowspan="2" | Length || rowspan="2" | Field || rowspan="2" | Notes | ! colspan="2" | Offset || rowspan="2" | Length || rowspan="2" | Field || rowspan="2" | Notes | ||
Line 57: | Line 50: | ||
! File || Block | ! File || Block | ||
|- | |- | ||
− | | <code> | + | | <code>002C</code> || <code>0000</code> || 4 bytes || Block magic word || Always <code>PBUF</code>. |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
|- | |- | ||
− | |||
|} | |} | ||
Line 74: | Line 60: | ||
! File || Block | ! File || Block | ||
|- | |- | ||
− | | <code> | + | | <code>0080</code> || <code>0000</code> || 4 bytes || Block magic word || Always <code>PARK</code>. |
|- | |- | ||
|} | |} | ||
Line 84: | Line 70: | ||
! File || Block | ! File || Block | ||
|- | |- | ||
− | | <code> | + | | <code>04A4</code> || <code>0000</code> || 4 bytes || Block magic word || Always <code>MINI</code>. |
|- | |- | ||
|} | |} | ||
Line 94: | Line 80: | ||
! File || Block | ! File || Block | ||
|- | |- | ||
− | | <code> | + | | <code>0588</code> || <code>0000</code> || 4 bytes || Block magic word || Always <code>CRNT</code>. |
|- | |- | ||
|} | |} | ||
Line 104: | Line 90: | ||
! File || Block | ! File || Block | ||
|- | |- | ||
− | | <code> | + | | <code>09A8</code> || <code>0000</code> || 4 bytes || Block magic word || Always <code>GAME</code>. |
|- | |- | ||
− | | <code> | + | | <code>09AC</code> || <code>0004</code> || 4 bytes || {{unknown|Unknown}} || |
|- | |- | ||
− | | <code> | + | | <code>09B0</code> || <code>0008</code> || 4 bytes || Sparklium total || Values over 99999 will make the game assume it's just 99999 |
|- | |- | ||
− | | <code> | + | | <code>09B4</code> || <code>000C</code> || 44 bytes || {{unknown|Unknown}} || |
|- | |- | ||
|} | |} | ||
Line 120: | Line 106: | ||
! File || Block | ! File || Block | ||
|- | |- | ||
− | | <code> | + | | <code>09E0</code> || <code>0000</code> || 4 bytes || Block magic word || Always <code>EVNT</code>. |
|- | |- | ||
|} | |} | ||
Line 130: | Line 116: | ||
! File || Block | ! File || Block | ||
|- | |- | ||
− | | <code> | + | | <code>0AE8</code> || <code>0000</code> || 4 bytes || Block magic word || Always <code>HELP</code>. |
|- | |- | ||
|} | |} | ||
Line 140: | Line 126: | ||
! File || Block | ! File || Block | ||
|- | |- | ||
− | | <code> | + | | <code>0BF0</code> || <code>0000</code> || 4 bytes || Block magic word || Always <code>RINF</code>. |
|- | |- | ||
|} | |} | ||
Line 150: | Line 136: | ||
! File || Block | ! File || Block | ||
|- | |- | ||
− | | <code> | + | | <code>0C2C</code> || <code>0000</code> || 4 bytes || Block magic word || Always <code>RSLT</code>. |
|- | |- | ||
|} | |} | ||
Line 160: | Line 146: | ||
! File || Block | ! File || Block | ||
|- | |- | ||
− | | <code> | + | | <code>0C38</code> || <code>0000</code> || 4 bytes || Block magic word || Always <code>SPER</code>. |
|- | |- | ||
|} | |} | ||
Line 170: | Line 156: | ||
! File || Block | ! File || Block | ||
|- | |- | ||
− | | <code> | + | | <code>0C48</code> || <code>0000</code> || 4 bytes || Block magic word || Always <code>STRE</code>. |
|- | |- | ||
|} | |} | ||
Line 180: | Line 166: | ||
! File || Block | ! File || Block | ||
|- | |- | ||
− | | <code> | + | | <code>0C90</code> || <code>0000</code> || 4 bytes || Block magic word || Always <code>PLRP</code>. |
|- | |- | ||
|} | |} | ||
Line 192: | Line 178: | ||
! File || Block | ! File || Block | ||
|- | |- | ||
− | | <code> | + | | <code>0CE0</code> || <code>0000</code> || 4 bytes || Block magic word || Always <code>DATE</code>. |
− | |||
− | |||
|- | |- | ||
− | | <code> | + | | <code>0CE4</code> || <code>0004</code> || 8 bytes || {{unknown|Unknown}} || |
|- | |- | ||
− | | <code> | + | | <code>0CEC</code> || <code>000C</code> || 1 byte || Month || 1 to 12. |
|- | |- | ||
− | | <code> | + | | <code>0CED</code> || <code>000D</code> || 1 byte || Day || 1 to 31. |
|- | |- | ||
− | | <code> | + | | <code>0CEE</code> || <code>000E</code> || 1 byte || Hours || 0 to 23. |
|- | |- | ||
− | | <code> | + | | <code>0CEF</code> || <code>000F</code> || 1 byte || Minutes || 0 to 59. |
|- | |- | ||
− | | <code> | + | | <code>0CF0</code> || <code>0010</code> || 1 byte || Seconds || 0 to 59. |
|- | |- | ||
− | | <code> | + | | <code>0CF1</code> || <code>0011</code> || 11 bytes || {{unknown|Unknown}} || |
|} | |} | ||
Line 217: | Line 201: | ||
! File || Block | ! File || Block | ||
|- | |- | ||
− | | <code> | + | | <code>0CFC</code> || <code>0000</code> || 4 bytes || Block magic word || Always <code>TTDS</code>. |
|- | |- | ||
|} | |} | ||
Line 227: | Line 211: | ||
! File || Block | ! File || Block | ||
|- | |- | ||
− | | <code> | + | | <code>0D08</code> || <code>0000</code> || 4 bytes || Block magic word || Always <code>WMAP</code>. |
|- | |- | ||
|} | |} | ||
Line 237: | Line 221: | ||
! File || Block | ! File || Block | ||
|- | |- | ||
− | | <code> | + | | <code>0D80</code> || <code>0000</code> || 4 bytes || Block magic word || Always <code>SAMI</code>. |
|- | |- | ||
|} | |} | ||
== Checksum == | == Checksum == | ||
− | The checksum seems to be a CRC32 of the | + | The checksum seems to be a CRC32 of the 0xd87 bytes that follow after the checksum (i.e. just one byte short of the entire remaining data), with crc32 as implemented by e.g. zlib. |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | == | + | The following python code can recalculate the checksum if the data after the checksum is modified: |
− | + | import struct | |
+ | from zlib import crc32 | ||
+ | |||
+ | filepath = "radish0.sav" # put the script in the same folder as the save file | ||
+ | with open(filepath, "rb") as f: | ||
+ | header = f.read(0xC) | ||
+ | chksum = struct.unpack("I", f.read(4))[0] | ||
+ | |||
+ | data = f.read() | ||
+ | |||
+ | calculated_chksum = crc32(data[0:0xd87]) | ||
+ | with open(filepath, "wb") as f: | ||
+ | f.write(header) | ||
+ | f.write(struct.pack("I", calculated_chksum)) | ||
+ | f.write(data) | ||
[[Category:File formats]] | [[Category:File formats]] | ||
[[Category:Hey! Pikmin]] | [[Category:Hey! Pikmin]] |