DAT (File Format) (Mario Kart 7's Ghost Format)
DAT is the format of Time Trial ghost data in Mario Kart 7. This format is common between ghosts saved in the saved file, staff ghosts and ghosts received through StreetPass and SpotPass.
User-created ghosts are stored in the replay directory. There's also another directory named replay_, that serves as a backup for the replay directory. The SpotPass ghosts are located in the SpotPass data, which can be extracted using homebrew tools such as FBI (Ext Save Data > MARIO KART 7 > Browse SpotPass User Data). Staff ghosts are stored in the replay directory in the RomFS.
The file consists of a header describing metadata of the ghost such as vehicle and character used, the finishing time, etc. The main contents of the file is then the sequence of controller inputs made by the player, which can be used to replay the ghost. Following the ghost input data is a CRC-32 which the game uses to verify the file has not corrupted (this is not present in ghosts received through StreetPass and SpotPass).
The file always have a size of either 0x289C (with checksum) or 0x2898 (without checksum).
NOTE: All of the offsets described here correspond to the offsets of the file when converted from 32 bit little endian to 32 bit big endian.
An DAT file begins with the 0xC0 byte header.
|0x00||4||"DGDC" in ASCII (CDGD in big endian); CTR Dash Ghost Data file identifier.|
|0x04||4 bits||Unknown. Always 0.|
|0x04.4||1 bit||Raced using 1st person view 80% of the time flag; 0 = No, 1 = Yes. If yes, a black wheel icon will appear in the ghost card.|
|0x04.5||3 bits||Course lap type. 01 for section-based courses (Wuhu Loop / Maka Wuhu / Rainbow Road), and 03 for every other course. Strangely enough, the expert staff ghost for Maka Wuhu (replayF09.dat) and the easy and expert staff ghosts for Rainbow Road (replayS13.dat and replayF13.dat) are the only ghosts that set this value to 00.|
|0x05||10 bits||Milliseconds field of finishing time.|
|0x06.2||7 bits||Seconds field of finishing time.|
|0x07.1||7 bits||Minutes field of finishing time.|
|0x08||1 bit||Unknown. Always 0.|
|0x08.1||7 bits||Minutes field of lap 2.|
|0x09||10 bits||Milliseconds field of lap 1.|
|0x0A.2||7 bits||Seconds field of lap 1.|
|0x0B.1||7 bits||Minutes field of lap 1.|
|0x0C||1 bit||Unknown. Always 1. The game sets a value to this field in the instruction at 0x0044fcc0 + 0x118. It copies the value from field 0x9C of System::PlayerData (which is the least significant bit of byte 0x06 from the save data file) here (and also expects the value to be 1).|
Additionally, starting at 0x00474f5c + 0x16C, the game checks if this value is different from 0.
|0x0C.1||7 bits||Seconds field of lap 3.|
|0x0D||7 bits||Minutes field of lap 3.|
|0x0D.7||10 bits||Milliseconds field of lap 2.|
|0x0F.1||7 bits||Seconds field of lap 2.|
|0x10||22 bits||Unknown. Always 1. This field is set to 1 in the constructor of the ghost header, and System::GhostSaveDataHeader::isValid checks if said field is 1.|
|0x12.6||10 bits||Milliseconds field of lap 3.|
|0x14||1||Unknown. Always 0.|
|0x15||4 bits||Glider ID used by the ghost.|
|0x15.4||4 bits||Tire ID used by the ghost.|
|0x16||5 bits||Kart ID used by the ghost.|
|0x16.5||5 bits||Character ID used by the ghost.|
|0x17.2||6 bits||Course ID.|
|0x18||0x14||Mii's UTF-16 encoded name (in big endian).|
|0x2C||2||Unknown. Always 0. The game sets this field to 0 in the instruction 0x0044fcc0 + 0xE8|
|0x2E||2||Unknown. Always 0.|
|0x30||0x60||Driver's Mii data. The exact format of this Mii data is CFSD, as it contains a 2-byte checksum at the end of the data. Note that all ghosts save the Mii data, but, aside of the name, said data cannot be seen in-game unless the player has raced as a Mii.|
|0x90||2||Country code. Also used to determine whether the game should display the string "Nintendo" or "Retro Studios" for staff ghosts.|
01 (Japan) = "Nintendo", otherwise "Retro Studios".
|0x92||2||Unknown. Always 0.|
|0x94||2||Globe coordinates (latitude). The latitude of the physical coordinates on the Wi-Fi / Mario Kart Channel globe the Mii appears on.|
|0x96||2||Globe coordinates (longitude). The longitude of the physical coordinates on the Wi-Fi / Mario Kart Channel globe the Mii appears on.|
|0x98||4||Unknown. Always 0.|
|0x9C||4||Unknown. Modifying this value does not change anything in-game, so this may be some kind of revision number. All user-created ghosts set this value to 0x752F (29999), while the staff ghosts have different values depending on the ghost (they don't follow a specific pattern). Those values are: 0000, 0x4DFD (19965), 0x4E4B (20043), 0x4EC3 (20163), 0x4EEA (20202) and 0x4F9C (20380)|
This field is set to 0x752F in the instruction 0x0044fcc0 + 0x138
|0xA0||0x20||Unknown. Always 0.|
|0xC0||End of this header; start of data|
NOTE: The following RAM addresses are for the EUR Rev0 v1.1 version of the game.
- The function starting at 0x0044fcc0 writes the data of the ghost header upon saving a new ghost. r4 contains the pointer to the ghost header.
- System::GhostSaveDataHeader::GhostSaveDataHeader() is the constructor of the ghost data header. Said function starts at 0x00450130. r0 contains the pointer to the ghost header.
- System::GhostSaveData::GhostSaveData() is the constructor of the ghost data. Said function starts at 0x00444220. r0 contains the pointer to the ghost data.
- System::GhostSaveDataHeader::isValid() starts at 0x005165d0.
Controller Input Data
The header is then followed by the input data. The controller input data must be less than or equal to 0x27D8 bytes in length. The input data is padded to exactly 0x27D8 bytes in length.
The input data begins with the following 4 byte header (in 16 bit little endian).
|0x00||2||Length of face button input data.|
|0x02||2||Length of direction input data.|
|0x04||End of this header; start of face button input data.|
Just like in Mario Kart Wii, the actual input data then follows in complete sections in the order of face button inputs and direction inputs. Each uses a 2 byte format, 1 byte representing the state of the specified input then the next representing the duration for which that input was held in frames. The sections follow on sequentially from each other. If an input state is held for more than 255 frames, it is continued as the next input. The meaning of the state byte differs per section as follows.
|0x01||A button is pressed.|
|0x02||B button is pressed.|
|0x04||X button is pressed.|
|0x08||Y button is pressed.|
|0x10||L button is pressed.|
|0x20||R button is pressed.|
|0x40||1st person view is enabled.|
|0x80||Unknown, probably unused.|
|0x0F||Forward/backward input (a range; 0xE is forward, 0x0 is backward, 0x7 is neutral).|
|0xF0||Left/right input (0xE0 is right, 0x00 is left, 0x70 is neutral).|
All ghosts (except the ones received through StreetPass and SpotPass) have a CRC-32 of the file up to that point (in little endian) at offset 0x2898.
The following tools can handle DAT files: