RKG (File Format)
RKG is the format of Time Trial ghost data. This format is common between ghosts saved in the saved file, staff ghosts and ghosts stored on Time Trial servers. In a savefile all ghosts are saved in the rksys file.
The file consists of a header describing the settings of the ghost such as vehicle and character, as well as the driver information such as the Mii, controller type and drift type. The header also contains metadata such as finishing time of the ghost. 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. This may be compressed or raw. Following the ghost input data is a CRC-32 which the game uses to verify the file has not corrupted.
If the game is perfectly deterministic, the same controller inputs should always yield the same finishing time. In practice however, Mario Kart Wii is not quite able to recreate the circumstances in which the ghost was recorded leading to the rare Wiggler Glitch. This causes the ghost to descynchronise from the original Time Trial, often failing to finish.
An RKG file begins with the 0x88 byte header.
|0x00||4||"RKGD" in ASCII; Revolution Kart Ghost Data file identifier.|
|0x04||7 bits||Minutes field of finishing time.|
|0x04.7||7 bits||Seconds field of finishing time.|
|0x05.6||10 bits||Milliseconds field of finishing time.|
|0x07||6 bits||Track ID.|
|0x07.6||2 bits||Unknown. Probably padding.|
|0x08||6 bits||Vehicle ID used by the ghost.|
|0x08.6||6 bits||Character ID used by the ghost.|
|0x09.4||7 bits||Year that the ghost was set, stored relative to the year 2000.|
|0x0A.3||4 bits||Month that the ghost was set.|
|0x0A.7||5 bits||Day that the ghost was set.|
|0x0B.4||4 bits||Controller ID; 0 for Wii Wheel, 1 for Wii Remote + Nunchuck, 2 for Classic Controller, 3 for GameCube Controller.|
|0x0C||4 bits||Unknown. Always 0?|
|0x0C.4||1 bit||Compressed flag; 1 for compressed, 0 for raw.|
|0x0C.5||2 bits||Unknown. Always 0?|
|0x0C.7||7 bits||Ghost type; 0x01 player's best time, 0x02 world record ghost, 0x03 continental record ghost, 0x04 rival ghost, 0x05 special ghost, 0x06 ghost race, 0x07-0x24 for all 30 friend ghosts, 0x25 normal staff ghost, 0x26 expert staff ghost.|
|0x0D.6||1 bit||Drift type; 1 for automatic, 0 for manual.|
|0x0D.7||1 bit||Unknown. Probably padding.|
|0x0E||2||Input data length, measured when decompressed and without padding.|
|0x10||1||Lap count; total laps driven by ghost.|
|0x11||3 × 5||Lap split times. Stored in the same 7 bit, 7 bit, 10 bit format as the finish time at offset 0x4. Unused split times are set to 0.|
|0x20||0x14||Unknown. Probably unused. The game attempts to store lap splits beyond the 5th here, but the internal data structures do not store that many splits, so RAM trash is stored instead when the lap count is greater than 5 (notably the finish time in the 6th split).|
|0x34||1||Country code or 0xFF if sharing location disabled.|
|0x35||1||State code or 0xFF if sharing location disabled.|
|0x36||2||Location code. 0x0000 typically, 0xFFFF if sharing location disabled.|
|0x38||4||Unknown. 0x00000000 typically.|
|0x3C||0x4A||Driver's Mii Data.|
|0x86||2||CRC16-CCITT-XModem of Mii.|
|0x88||End of this header; start of data|
Controller Input Data
The header is then followed by the input data. For compressed input data, the first 4 bytes are the length of the compressed data, followed by YAZ1 compressed data (including the YAZ1 header). The compressed data is always padded with zeros to a multiple of 4 bytes in length. Compressed data is used in the online rankings and in staff ghosts, uncompressed data is used in the save file. In a compressed ghost the compressed data (including YAZ1 header) must be less than or equal to 0x2774 bytes in length. For both compressed and uncompressed ghosts, the uncompressed input data must also be less than 0x2774 in length. In uncompressed files the input data is padded to exactly 0x2774 bytes in length. The length of the input data in the header always refers to the input data without padding.
The input data begins with the following 8 byte header.
|0x00||2||Count of face button inputs.|
|0x02||2||Count of direction inputs.|
|0x04||2||Count of trick inputs.|
|0x06||2||Unknown. Probably padding.|
|0x08||End of this header; start of face button input data.|
The actual input data then follows in complete sections in the order of face button inputs, direction inputs then trick 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 and are always 2 × count bytes in length. If an input state is held for more than 255 frames, it is continued as the next input. The meaning of the state bytes differs per section as follows.
|0x01||Accelerator button is pressed.|
|0x02||Brakes/drift button is pressed.|
|0x04||Fire item button is pressed.|
|0x08||Also set if brakes/drift button is pressed after having pressed the accelerator button and keep holding it.|
|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).|
|0x0F||Used if input state is held longer than 255 frames. Adds up with the input state duration byte for a total of 12 bits of size for input duration.|
|0x70||Trick input direction (0x00 no trick, 0x10 is up/wheelie, 0x20 is down, 0x30 is left, 0x40 is right).|
|0x80||Unknown. Probably unused.|
Following the data is a CRC-32 of the file up to that point. For compressed files, this is a CRC of the compressed data not the decompressed data.
The following tools can handle RKG files:
A kaitai format description file can be found on this GitHub repository.