Difference between revisions of "Hey! Pikmin save file"

From Pikmin Technical Knowledge Base
Jump to navigation Jump to search
(Added some values.)
m
Line 11: Line 11:
 
! File || Block
 
! File || Block
 
|-
 
|-
| <code>0000</code> || <code>0000</code> || 4 bytes || Block magic word || Always <code>SAVE</code>.
+
| <code>0x0000</code> || <code>0x0000</code> || 4 bytes || Block magic word || Always <code>SAVE</code>.
 
|-
 
|-
| <code>000C</code> || <code>000C</code> || 4 bytes || Save data checksum || {{unsure|Calculated using an unknown algorithm.}}
+
| <code>0x000C</code> || <code>0x000C</code> || 4 bytes || Save data checksum || Calculated using [[#Checksum|this method]].
 
|}
 
|}
  
Line 22: Line 22:
 
! File || Block
 
! File || Block
 
|-
 
|-
| <code>0010</code> || <code>0000</code> || 4 bytes || Block magic word || Always <code>NEWS</code>.
+
| <code>0x0010</code> || <code>0x0000</code> || 4 bytes || Block magic word || Always <code>NEWS</code>.
 
|-
 
|-
 
|}
 
|}
Line 33: Line 33:
 
! File || Block
 
! File || Block
 
|-
 
|-
| <code>0020</code> || <code>0000</code> || 4 bytes || Block magic word || Always <code>OPTI</code>.
+
| <code>0x0020</code> || <code>0x0000</code> || 4 bytes || Block magic word || Always <code>OPTI</code>.
 
|-
 
|-
| <code>0024</code> || <code>0004</code> || 4 bytes || {{unknown|Unknown}} ||  
+
| <code>0x0024</code> || <code>0x0004</code> || 4 bytes || {{unknown|Unknown}} ||  
 
|-
 
|-
| <code>0028</code> || <code>0008</code> || 1 byte || Music volume || <code>00</code> to <code>03</code>.
+
| <code>0x0028</code> || <code>0x0008</code> || 1 byte || Music volume || 0 to 3.
 
|-
 
|-
| <code>0029</code> || <code>0009</code> || 1 byte || Sound effects volume || <code>00</code> to <code>03</code>.
+
| <code>0x0029</code> || <code>0x0009</code> || 1 byte || Sound effects volume || 0 to 3.
 
|-
 
|-
| <code>002A</code> || <code>000A</code> || 2 bytes || {{unknown|Unknown}} ||  
+
| <code>0x002A</code> || <code>0x000A</code> || 2 bytes || {{unknown|Unknown}} ||  
 
|}
 
|}
  
Line 50: Line 50:
 
! File || Block
 
! File || Block
 
|-
 
|-
| <code>002C</code> || <code>0000</code> || 4 bytes || Block magic word || Always <code>PBUF</code>.
+
| <code>0x002C</code> || <code>0x0000</code> || 4 bytes || Block magic word || Always <code>PBUF</code>.
 
|-
 
|-
 
|}
 
|}
Line 60: Line 60:
 
! File || Block
 
! File || Block
 
|-
 
|-
| <code>0080</code> || <code>0000</code> || 4 bytes || Block magic word || Always <code>PARK</code>.
+
| <code>0x0080</code> || <code>0x0000</code> || 4 bytes || Block magic word || Always <code>PARK</code>.
 
|-
 
|-
 
|}
 
|}
Line 70: Line 70:
 
! File || Block
 
! File || Block
 
|-
 
|-
| <code>04A4</code> || <code>0000</code> || 4 bytes || Block magic word || Always <code>MINI</code>.
+
| <code>0x04A4</code> || <code>0x0000</code> || 4 bytes || Block magic word || Always <code>MINI</code>.
 
|-
 
|-
 
|}
 
|}
Line 80: Line 80:
 
! File || Block
 
! File || Block
 
|-
 
|-
| <code>0588</code> || <code>0000</code> || 4 bytes || Block magic word || Always <code>CRNT</code>.
+
| <code>0x0588</code> || <code>0x0000</code> || 4 bytes || Block magic word || Always <code>CRNT</code>.
 
|-
 
|-
 
|}
 
|}
Line 90: Line 90:
 
! File || Block
 
! File || Block
 
|-
 
|-
| <code>09A8</code> || <code>0000</code> || 4 bytes || Block magic word || Always <code>GAME</code>.
+
| <code>0x09A8</code> || <code>0x0000</code> || 4 bytes || Block magic word || Always <code>GAME</code>.
 
|-
 
|-
| <code>09AC</code> || <code>0004</code> || 4 bytes || {{unknown|Unknown}} ||  
+
| <code>0x09AC</code> || <code>0x0004</code> || 4 bytes || {{unknown|Unknown}} ||  
 
|-
 
|-
| <code>09B0</code> || <code>0008</code> || 4 bytes || Sparklium total || Values over 99999 will make the game assume it's just 99999
+
| <code>0x09B0</code> || <code>0x0008</code> || 4 bytes || Sparklium total || Values over 99999 will make the game assume it's just 99999
 
|-
 
|-
| <code>09B4</code> || <code>000C</code> || 44 bytes || {{unknown|Unknown}} ||  
+
| <code>0x09B4</code> || <code>0x000C</code> || 44 bytes || {{unknown|Unknown}} ||  
 
|-
 
|-
 
|}
 
|}
Line 106: Line 106:
 
! File || Block
 
! File || Block
 
|-
 
|-
| <code>09E0</code> || <code>0000</code> || 4 bytes || Block magic word || Always <code>EVNT</code>.
+
| <code>0x09E0</code> || <code>0x0000</code> || 4 bytes || Block magic word || Always <code>EVNT</code>.
 
|-
 
|-
 
|}
 
|}
Line 116: Line 116:
 
! File || Block
 
! File || Block
 
|-
 
|-
| <code>0AE8</code> || <code>0000</code> || 4 bytes || Block magic word || Always <code>HELP</code>.
+
| <code>0x0AE8</code> || <code>0x0000</code> || 4 bytes || Block magic word || Always <code>HELP</code>.
 
|-
 
|-
 
|}
 
|}
Line 126: Line 126:
 
! File || Block
 
! File || Block
 
|-
 
|-
| <code>0BF0</code> || <code>0000</code> || 4 bytes || Block magic word || Always <code>RINF</code>.
+
| <code>0x0BF0</code> || <code>0x0000</code> || 4 bytes || Block magic word || Always <code>0xRINF</code>.
 
|-
 
|-
 
|}
 
|}
Line 136: Line 136:
 
! File || Block
 
! File || Block
 
|-
 
|-
| <code>0C2C</code> || <code>0000</code> || 4 bytes || Block magic word || Always <code>RSLT</code>.
+
| <code>0x0C2C</code> || <code>0x0000</code> || 4 bytes || Block magic word || Always <code>RSLT</code>.
 
|-
 
|-
 
|}
 
|}
Line 146: Line 146:
 
! File || Block
 
! File || Block
 
|-
 
|-
| <code>0C38</code> || <code>0000</code> || 4 bytes || Block magic word || Always <code>SPER</code>.
+
| <code>0x0C38</code> || <code>0x0000</code> || 4 bytes || Block magic word || Always <code>SPER</code>.
 
|-
 
|-
 
|}
 
|}
Line 156: Line 156:
 
! File || Block
 
! File || Block
 
|-
 
|-
| <code>0C48</code> || <code>0000</code> || 4 bytes || Block magic word || Always <code>STRE</code>.
+
| <code>0x0C48</code> || <code>0x0000</code> || 4 bytes || Block magic word || Always <code>STRE</code>.
 
|-
 
|-
 
|}
 
|}
Line 166: Line 166:
 
! File || Block
 
! File || Block
 
|-
 
|-
| <code>0C90</code> || <code>0000</code> || 4 bytes || Block magic word || Always <code>PLRP</code>.
+
| <code>0x0C90</code> || <code>0x0000</code> || 4 bytes || Block magic word || Always <code>PLRP</code>.
 
|-
 
|-
 
|}
 
|}
Line 178: Line 178:
 
! File || Block
 
! File || Block
 
|-
 
|-
| <code>0CE0</code> || <code>0000</code> || 4 bytes || Block magic word || Always <code>DATE</code>.
+
| <code>0x0CE0</code> || <code>0x0000</code> || 4 bytes || Block magic word || Always <code>DATE</code>.
 
|-
 
|-
| <code>0CE4</code> || <code>0004</code> || 8 bytes || {{unknown|Unknown}} ||  
+
| <code>0x0CE4</code> || <code>0x0004</code> || 8 bytes || {{unknown|Unknown}} ||  
 
|-
 
|-
| <code>0CEC</code> || <code>000C</code> || 1 byte || Month || 1 to 12.
+
| <code>0x0CEC</code> || <code>0x000C</code> || 1 byte || Month || 1 to 12.
 
|-
 
|-
| <code>0CED</code> || <code>000D</code> || 1 byte || Day || 1 to 31.
+
| <code>0x0CED</code> || <code>0x000D</code> || 1 byte || Day || 1 to 31.
 
|-
 
|-
| <code>0CEE</code> || <code>000E</code> || 1 byte || Hours || 0 to 23.
+
| <code>0x0CEE</code> || <code>0x000E</code> || 1 byte || Hours || 0 to 23.
 
|-
 
|-
| <code>0CEF</code> || <code>000F</code> || 1 byte || Minutes || 0 to 59.
+
| <code>0x0CEF</code> || <code>0x000F</code> || 1 byte || Minutes || 0 to 59.
 
|-
 
|-
| <code>0CF0</code> || <code>0010</code> || 1 byte || Seconds || 0 to 59.
+
| <code>0x0CF0</code> || <code>0x0010</code> || 1 byte || Seconds || 0 to 59.
 
|-
 
|-
| <code>0CF1</code> || <code>0011</code> || 11 bytes || {{unknown|Unknown}} ||  
+
| <code>0x0CF1</code> || <code>0x0011</code> || 11 bytes || {{unknown|Unknown}} ||  
 
|}
 
|}
  
Line 201: Line 201:
 
! File || Block
 
! File || Block
 
|-
 
|-
| <code>0CFC</code> || <code>0000</code> || 4 bytes || Block magic word || Always <code>TTDS</code>.
+
| <code>0x0CFC</code> || <code>0x0000</code> || 4 bytes || Block magic word || Always <code>TTDS</code>.
 
|-
 
|-
 
|}
 
|}
Line 211: Line 211:
 
! File || Block
 
! File || Block
 
|-
 
|-
| <code>0D08</code> || <code>0000</code> || 4 bytes || Block magic word || Always <code>WMAP</code>.
+
| <code>0x0D08</code> || <code>0x0000</code> || 4 bytes || Block magic word || Always <code>WMAP</code>.
 
|-
 
|-
 
|}
 
|}
Line 221: Line 221:
 
! File || Block
 
! File || Block
 
|-
 
|-
| <code>0D80</code> || <code>0000</code> || 4 bytes || Block magic word || Always <code>SAMI</code>.
+
| <code>0x0D80</code> || <code>0x0000</code> || 4 bytes || Block magic word || Always <code>SAMI</code>.
 
|-
 
|-
 
|}
 
|}
Line 229: Line 229:
  
 
The following python code can recalculate the checksum if the data after the checksum is modified:
 
The following python code can recalculate the checksum if the data after the checksum is modified:
import struct
+
<pre>
from zlib import crc32
+
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:
+
filepath = "radish0.sav"  # put the script in the same folder as the save file
    header = f.read(0xC)
+
with open(filepath, "rb") as f:
    chksum = struct.unpack("I", f.read(4))[0]
+
    header = f.read(0xC)
   
+
    chksum = struct.unpack("I", f.read(4))[0]
    data = f.read()
+
   
+
    data = f.read()
calculated_chksum = crc32(data[0:0xd87])
+
 
with open(filepath, "wb") as f:
+
calculated_chksum = crc32(data[0:0xd87])
    f.write(header)
+
with open(filepath, "wb") as f:
    f.write(struct.pack("I", calculated_chksum))
+
    f.write(header)
    f.write(data)
+
    f.write(struct.pack("I", calculated_chksum))
 +
    f.write(data)
 +
</pre>
  
 
[[Category:File formats]]
 
[[Category:File formats]]
 
[[Category:Hey! Pikmin]]
 
[[Category:Hey! Pikmin]]

Revision as of 22:53, 29 December 2017

This article is a stub.

The file format for a Hey! Pikmin saved game. Note: this comes from analyses of the .sav files generated by Citra.

Format

The save data is split into several blocks that start with 4-byte magic words.

SAVE

Offset Length Field Notes
File Block
0x0000 0x0000 4 bytes Block magic word Always SAVE.
0x000C 0x000C 4 bytes Save data checksum Calculated using this method.

NEWS

Offset Length Field Notes
File Block
0x0010 0x0000 4 bytes Block magic word Always NEWS.

OPTI

The player's preferences in the options menu.

Offset Length Field Notes
File Block
0x0020 0x0000 4 bytes Block magic word Always OPTI.
0x0024 0x0004 4 bytes Unknown[unsure]
0x0028 0x0008 1 byte Music volume 0 to 3.
0x0029 0x0009 1 byte Sound effects volume 0 to 3.
0x002A 0x000A 2 bytes Unknown[unsure]

PBUF

Offset Length Field Notes
File Block
0x002C 0x0000 4 bytes Block magic word Always PBUF.

PARK

Offset Length Field Notes
File Block
0x0080 0x0000 4 bytes Block magic word Always PARK.

MINI

Offset Length Field Notes
File Block
0x04A4 0x0000 4 bytes Block magic word Always MINI.

CRNT

Offset Length Field Notes
File Block
0x0588 0x0000 4 bytes Block magic word Always CRNT.

GAME

Offset Length Field Notes
File Block
0x09A8 0x0000 4 bytes Block magic word Always GAME.
0x09AC 0x0004 4 bytes Unknown[unsure]
0x09B0 0x0008 4 bytes Sparklium total Values over 99999 will make the game assume it's just 99999
0x09B4 0x000C 44 bytes Unknown[unsure]

EVNT

Offset Length Field Notes
File Block
0x09E0 0x0000 4 bytes Block magic word Always EVNT.

HELP

Offset Length Field Notes
File Block
0x0AE8 0x0000 4 bytes Block magic word Always HELP.

RINF

Offset Length Field Notes
File Block
0x0BF0 0x0000 4 bytes Block magic word Always 0xRINF.

RSLT

Offset Length Field Notes
File Block
0x0C2C 0x0000 4 bytes Block magic word Always RSLT.

SPER

Offset Length Field Notes
File Block
0x0C38 0x0000 4 bytes Block magic word Always SPER.

STRE

Offset Length Field Notes
File Block
0x0C48 0x0000 4 bytes Block magic word Always STRE.

PLRP

Offset Length Field Notes
File Block
0x0C90 0x0000 4 bytes Block magic word Always PLRP.

DATE

Time at which the save was made.

Offset Length Field Notes
File Block
0x0CE0 0x0000 4 bytes Block magic word Always DATE.
0x0CE4 0x0004 8 bytes Unknown[unsure]
0x0CEC 0x000C 1 byte Month 1 to 12.
0x0CED 0x000D 1 byte Day 1 to 31.
0x0CEE 0x000E 1 byte Hours 0 to 23.
0x0CEF 0x000F 1 byte Minutes 0 to 59.
0x0CF0 0x0010 1 byte Seconds 0 to 59.
0x0CF1 0x0011 11 bytes Unknown[unsure]

TTDS

Offset Length Field Notes
File Block
0x0CFC 0x0000 4 bytes Block magic word Always TTDS.

WMAP

Offset Length Field Notes
File Block
0x0D08 0x0000 4 bytes Block magic word Always WMAP.

SAMI

Offset Length Field Notes
File Block
0x0D80 0x0000 4 bytes Block magic word Always SAMI.

Checksum

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)