BYAML (File Format)
The BYAML file format is a generic data container format used in Mario Kart 8. It is similar in some ways to XML, but it is a binary data format. Like XML files, BYAML files are somewhat self describing making it easier to understand and edit them than unformated binary data. In Mario Kart 8 they're used to describe course control information such as layout and checkpointing, as well as describing game-wide settings such as objects and AIs.
The file is broken up into a node structure, with possible interlinking between the nodes. Each node has a one byte format identifier. The file begins with a header which points to up to four special nodes: the node name table node; the string value table node; the path value node and finally the root node.
The BYAML file format starts with a 0x14 byte header structure.
|0x00||2||Magic string "BY" in ASCII, or "YB" for little endian files used on the Nintendo Switch.|
|0x02||2||Version 0x0001 in Mario Kart 8.|
|0x04||4||Node name table node Offset to the node name table node, relative to start (usually 0x014). Unknown if this can ever be 0. Must be a string value node (0xc2).|
|0x08||4||String value table node Offset to the string value table node, relative to start. May be 0 if string values unused. Must be a string value node (0xc2).|
|0x0c||4||Path value table node Offset to the path value table node, relative to start. May be 0 if path values unused. Must be a path value node (0xc3).|
|0x10||4||Root node Offset to the root node, relative to start. Must be either an array node (0xc0) or a dictionary node (0xc1).|
|0x14||End of file header|
Every node format has a unique one byte identifier as follows. Some nodes are considered value nodes as indicated below. The full nodes have a longer encoding in the file, which must be four byte aligned. The order of encoding full nodes within the file does not seem to matter.
|0xa0||Value (Index)||String. Value is an index into the string value table.|
|0xa1||Value (Index)||Path. Value is an index into the path value table.|
|0xc0||Full||Array. Node is an array of nodes, typically, though not necessarily, all of the same format.|
|0xc1||Full||Dictionary. Node is a mapping from strings in the node name table to other nodes.|
|0xc2||Full (Special Purpose)||String table. Special purpose node type only seen in the node name table and the string value table.|
|0xc3||Full (Special Purpose)||Path table. Special purpose node type only seen in the path value table.|
|0xd0||Value||Boolean. Node is 1 or 0 representing true or false respectively.|
|0xd1||Value||Integer. Node is a signed integer value.|
|0xd2||Value||Float. Node is a 32 bit floating point value.|
Value nodes can only be encoded as children of other nodes. Each value node has a direct four byte encoding. For string and path values, this encoding is simply a four byte index into the string or path tables respectively.
0xc0 - Array Node
An array node begins with the following header.
|0x00||1||0xc0 node type.|
|0x01||3||N= Count number of entries in array.|
|0x04||N||Variable length array of node types; the type of each element in the array.|
|0x04+N||End of node header|
There then follows padding bytes up to the nearest 4 bytes. After the padding is the variable length array of N node values. For value nodes this is the four byte node value. For full nodes this is an offset to the node relative to the start of the file.
0xc1 - Dictionary Node
Dictionary nodes are used to encode name value collections.
|0x00||1||0xc1 node type.|
|0x01||3||N= Count number of entries in dictionary.|
|0x04||End of node header|
What then follows is a variable length array of N dictionary entries. The order of entries in the dictionary does not seem to matter - however, original files sort the entries ordinally by key, and write offset values in the order they were added to the dictionary internally by the tool composing the BYAML data. A dictionary node begins with the following header. Each entry has the following structure.
|0x00||3||Name. Index into the node name value table for the name of this entry.|
|0x03||1||Node type. One of the node type constants.|
|0x04||4||Value. For value nodes this is the four byte node value. For full nodes this is an offset to the node relative to the start of the file.|
|0x08||End of entry|
0xc2 - String Table Node
A string table node begins with the following header.
|0x00||1||0xc2 node type.|
|0x01||3||N= Count number of entries in string value table.|
|0x04||4*(N+1)||Offsets. Variable length array of offsets to each string relative to the start of the node. The last entry is an offset to the end of the last string.|
|0x04+4*(N+1)||End of node header|
Immediately following the node header are the string values at the positions indicated by the offsets. Despite the length being clear from the table, the string values are null terminated, perhaps for ease of decoding. They are always stored in alphabetical order.
0xc3 - Path Table Node
A path table node begins with the following header.
|0x00||1||0xc3 node type.|
|0x01||3||N= Count number of entries in path value table.|
|0x04||4*(N+1)||Offsets. Variable length array of offsets to each path relative to the start of the node. The last entry is an offset to the end of the last path.|
|0x04+4*(N+1)||End of node header|
Immediately following the header are the paths at the positions indicated by the offsets. The length of each path is implicit; subtract the offset to the next path from the offset to this path. Each path consists of multiple points. Each point is a structure as follows.
|0x00||12||Position three floating point values, x, y and z.|
|0x0c||12||Normal three floating point values, x, y and z.|
|0x1c||End of point|
Since the BYAML format is a generic data container, this format specification cannot detail what structure a particular BYAML file ought to have. The following table links to articles on specific instances of BYAML files.
|AIRivalTable.byaml||Sets up your rivals based on the character you choose at random, but your character is set to -1 so it's not loaded as an AI. Seems harcoded.|
|AICourseTable_GP.byaml||Has floats for each course assigned to it, categorized through CC...range is 1 to -1.|
|AIItemTable.byaml||Contains AI data for throwing items, and holds a percentage value to each CC. (EASY, NORMAL, HARD, EXPERT) to see how accurate they are.|
|AILevelTable.byaml||Seems it contains speed data for CPUs...adds "speed ratios" depending on the CC.|
|AIProbability_Drift_Table.byaml||CPU chances of them drifting during a race, used to sort out difficulty.|
|AIProbability_JumpAction_Table.byaml||CPU chances of them tricking on ramps, used to sort out difficulty.|
|AIProbability_RocketStart_Table.byaml||CPU chances of getting the max start of a race, used to sort out difficulty.|
|battle_muunt.byaml||Parameters for the battle such as spawn location.|
|course_muunt.byaml||Parameters for the course such as lap path, gravity and object placement.|
|objflow.byaml||Object paramters such as hit box, resource list, animation, id.|
The following tools can handle BYAML files: