BYML: Difference between revisions

3,744 bytes added ,  1 year ago
Updated file format to version 7 for TotK
imported>Leoetlino
(Created page with "'''BYML''' is a file format that is used as a generic data container throughout ''Breath of the Wild''. It is a simplified, binary form of YAML. Only the v...")
 
(Updated file format to version 7 for TotK)
 
(10 intermediate revisions by 2 users not shown)
Line 1: Line 1:
'''BYML''' is a file format that is used as a generic data container throughout ''Breath of the Wild''. It is a simplified, binary form of [[wikipedia:YAML|YAML]].
<onlyinclude>'''BYML''' is a simplified, binary form of [[wikipedia:YAML|YAML]].</onlyinclude>


Only the version 2 format is documented in this article.
Only the version 2+ format is documented in this article.


== Structure ==
== Structure ==
Line 7: Line 7:


=== Header ===
=== Header ===
{|class="wikitable"
{| class="wikitable"
!align="center" width="4%"| Offset
! align="center" width="4%" | Offset
!align="center" width="3%"| Size
! align="center" width="3%" | Size
!width="91%"| Description
! width="91%" | Description
|-
|-
|align="center"| 0x00
| align="center" | 0x00
|align="center"| 2
| align="center" | 2
| String “BY” (big endian) or “YB” (little endian) in ASCII (file identifier).
| “BY” (big endian) or “YB” (little endian).
|-
|-
|align="center"| 0x02
| align="center" | 0x02
|align="center"| 2
| align="center" | 2
| Version 0x0002 in Breath of the Wild. Values of 1 and 3 are accepted as well.
| Version 2 in ''Breath of the Wild'', Versions 4 to 7 in ''Tears of the Kingdom''. 1 and 3 are also valid version numbers.
|-
|-
|align="center"| 0x04
| align="center" | 0x04
|align="center"| 4
| align="center" | 4
| Offset to the hash key table, relative to start (usually 0x010). May be 0 if no hash nodes are used. Must be a string value node (0xc2).
| Offset to the hash key table, relative to start (usually 0x010). May be 0 if no hash nodes are used. Must be a string value node (0xc2).
|-
|-
|align="center"| 0x08
| align="center" | 0x08
|align="center"| 4
| align="center" | 4
| Offset to the string table, relative to start. May be 0 if no strings are used. Must be a string value node (0xc2).
| Offset to the string table, relative to start. May be 0 if no strings are used. Must be a string value node (0xc2).
|-
|-
|align="center"| 0x0c
| align="center" | 0x0c
|align="center"| 4
| align="center" | 4
| Offset to the root node, relative to start. May be 0 if the document is totally empty. Must be either an array node (0xc0) or a hash node (0xc1).
| Offset to the root node, relative to start. May be 0 if the document is totally empty. Must be either an array node (0xc0) or one of the hash nodes (0x20, 0x21 or 0xc1).
|}
|}


Line 37: Line 37:
Every node format has a unique one byte identifier as follows. Some nodes are considered value nodes as indicated below. The container 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.
Every node format has a unique one byte identifier as follows. Some nodes are considered value nodes as indicated below. The container 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.


{|class="wikitable"
{| class="wikitable"
!align="center" width="8%"| Identifier
! align="center" width="8%" | Identifier
!align="center" width="17%"| Type
! align="center" width="17%" | Type
!width="73%"| Description
! width="63%" | Description
! width="10%" | Version
|-
| align="center" | 0x20
| align="center" | Container
| Plain hash. Node is a mapping from 32-bit hashes to other nodes.
| 7+
|-
| align="center" | 0x21
| align="center" | Container
| Value hash. Node is a mapping from 32-bit hashes to other nodes and a second 4 byte value.
| 7+
|-
|-
|align="center"| 0xA0
| align="center" | 0xA0
|align="center"| Value (Index)
| align="center" | Value (Index)
| String. Value is an index into the string table.
| String. Value is an index into the string table.
| 2+
|-
|-
|align="center"| 0xC0
| align="center" | 0xA1
|align="center"| Container
| align="center" | Value (Special)
| Binary data.
| 4+
|-
| align="center" | 0xA2
| align="center" | Value (Special)
| File data. Node contains the binary data of another file.
| 5+
|-
| align="center" | 0xC0
| align="center" | Container
| Array. Node is an array of nodes, typically, though not necessarily, all of the same format.
| Array. Node is an array of nodes, typically, though not necessarily, all of the same format.
| 2+
|-
|-
|align="center"| 0xC1
| align="center" | 0xC1
|align="center"| Container
| align="center" | Container
| Hash. Node is a mapping from strings in the hash key table to other nodes.
| String hash. Node is a mapping from strings in the hash key table to other nodes.
| 2+
|-
|-
|align="center"| 0xC2
| align="center" | 0xC2
|align="center"| Container (Special)
| align="center" | Container (Special)
| String table. Special purpose node type only seen in the hash key table and the string table.
| String table. Special purpose node type only seen in the hash key table and the string table.
| 2+
|-
|-
|align="center"| 0xD0
| align="center" | 0xD0
|align="center"| Value
| align="center" | Value
| Bool. Node is 1 or 0 representing true or false respectively.
| Bool. Node is 1 or 0 representing true or false respectively.
| 2+
|-
|-
|align="center"| 0xD1
| align="center" | 0xD1
|align="center"| Value
| align="center" | Value
| Int. Node is a signed 32 bit integer value.
| Int. Node is a signed 32 bit integer value.
| 2+
|-
|-
|align="center"| 0xD2
| align="center" | 0xD2
|align="center"| Value
| align="center" | Value
| Float. Node is a binary32 floating-point number.
| Float. Node is a binary32 floating-point number.
| 2+
|-
|-
|align="center"| 0xD3
| align="center" | 0xD3
|align="center"| Value
| align="center" | Value
| UInt. Node is an unsigned 32 bit integer value. The game uses this for some CRC32 hashes and for masks.
| UInt. Node is an unsigned 32 bit integer value. The game uses this for some CRC32 hashes and for masks.
| 2+
|-
|-
|align="center"| 0xD4
| align="center" | 0xD4
|align="center"| Value (Special)
| align="center" | Value (Special)
| Int64. Node is a 64 bit integer value. Not seen in Breath of the Wild.
| Int64. Node is a 64 bit integer value.
| 3+
|-
|-
|align="center"| 0xD5
| align="center" | 0xD5
|align="center"| Value (Special)
| align="center" | Value (Special)
| UInt64. Node is an unsigned 64 bit integer value. Not seen in Breath of the Wild.
| UInt64. Node is an unsigned 64 bit integer value.
| 3+
|-
|-
|align="center"| 0xD6
| align="center" | 0xD6
|align="center"| Value (Special)
| align="center" | Value (Special)
| Double. Node is a binary64 floating-point number. Not seen in Breath of the Wild.
| Double. Node is a binary64 floating-point number.
| 3+
|-
|-
|align="center"| 0xFF
| align="center" | 0xFF
|align="center"| Value
| align="center" | Value
| Null. Value is always 0. Not seen in Breath of the Wild.
| Null. Value is always 0.
| 3+
|}
|}


Line 97: Line 130:
For string nodes, this encoding is simply a four byte index into the string table respectively.
For string nodes, this encoding is simply a four byte index into the string table respectively.


For special value nodes, the value is an offset to a 64 bit integer / floating-point number relative to the start of the file.
For special value nodes, the value is an offset relative to the start of the file.
 
==== 0x20 - Hash Node ====
 
Hash / dictionary nodes are used to encode name value collections. Entries must sorted by their hash value.
 
{| class="wikitable"
! align="center" | Offset
! align="center" | Size
! Description
|-
| align="center" | 0x00
| align="center" | 1
| 0x20 node type.
|-
| align="center" | 0x01
| align="center" | 3
| Number of entries in dictionary.
|-
| align="center" | 0x04
| align="center" | 8*N
| Dictionary entries.
|-
| align="center" | 0x04+8*N
| align="center" | 1*N
| Array of N types, on for each entry in the dictionary. This is padded to 4 bytes.
|}
 
Each entry in the dictionary has the following structure.
 
{| class="wikitable"
! align="center" width="5%" | Offset
! align="center" width="3%" | Size
! width="90%" | Description
|-
| align="center" | 0x00
| align="center" | 4
| Hash. A 32-bit hash of the key.
|-
| align="center" | 0x04
| align="center" | 4
| Value. For regular value nodes, this is the 4 byte node value. For other nodes, this is a 4 byte offset to the node relative to the start of the file.
|}
 
==== 0x21 - Value Hash Node ====
 
This type is the similar to the hash node with the addition of a 4-byte value in each dictionary entry.
 
{| class="wikitable"
! align="center" width="5%" | Offset
! align="center" width="3%" | Size
! width="90%" | Description
|-
| align="center" | 0x00
| align="center" | 4
| Value. For regular value nodes, this is the 4 byte node value. For other nodes, this is a 4 byte offset to the node relative to the start of the file.
|-
| align="center" | 0x04
| align="center" | 4
| Hash. A 32-bit hash of the key.
|-
| align="center" | 0x08
| align="center" | 4
| Unknown. Always 0 in ''Tears of the Kingdom''.
|}
 
==== 0xA1 - Binary Data Node ====
{| class="wikitable"
! align="center" | Offset
! align="center" | Size
! Description
|-
| align="center" | 0x00
| align="center" | 4
| Data length
|-
| align="center" | 0x04
| align="center" | variable
| Data
|}
 
==== 0xA2 - File Node ====
{| class="wikitable"
! align="center" | Offset
! align="center" | Size
! Description
|-
| align="center" | 0x00
| align="center" | 4
| File length
|-
| align="center" | 0x04
| align="center" | 4
| Unknown. Always 0x1000.
|-
| align="center" | 0x08
| align="center" | variable
| File data
|}


==== 0xC0 - Array Node ====
==== 0xC0 - Array Node ====


{|class="wikitable"
{| class="wikitable"
!align="center" width="12%"| Offset
! align="center" width="12%" | Offset
!align="center" width="6%"| Size
! align="center" width="6%" | Size
!width="81%"| Description
! width="81%" | Description
|-
|-
|align="center"| 0x00
| align="center" | 0x00
|align="center"| 1
| align="center" | 1
| 0xC0 node type.
| 0xC0 node type.
|-
|-
|align="center"| 0x01
| align="center" | 0x01
|align="center"| 3
| align="center" | 3
| Number of entries in array.
| Number of entries in array.
|-
|-
|align="center"| 0x04
| align="center" | 0x04
|align="center"| N
| align="center" | N
| Array of N node types; the type of each element in the array.
| Array of N node types; the type of each element in the array.
|-
|-
|align="center"| 0x04 + N’
| align="center" | 0x04 + N’
|align="center"| 4*N
| align="center" | 4*N
| Array of N node values. For regular value nodes, this is a 4 byte node value. For other nodes, this is a 4 byte offset to the node relative to the start of the file.
| Array of N node values. For regular value nodes, this is a 4 byte node value. For other nodes, this is a 4 byte offset to the node relative to the start of the file.
|}
|}
Line 125: Line 256:
N’ is N rounded up to the nearest multiple of 4.
N’ is N rounded up to the nearest multiple of 4.


==== 0xC1 - Hash Node ====
==== 0xC1 - String Hash Node ====


Hash / dictionary nodes are used to encode name value collections. The order of entries in the dictionary does not seem to matter.
Hash / dictionary nodes are used to encode name value collections. Entries must be lexicographically sorted<ref>Nintendo's BYML library performs a binary search when looking up items by key in a hash node.</ref>.


{|class="wikitable"
{| class="wikitable"
!align="center"| Offset
! align="center" | Offset
!align="center"| Size
! align="center" | Size
! Description
! Description
|-
|-
|align="center"| 0x00
| align="center" | 0x00
|align="center"| 1
| align="center" | 1
| 0xC1 node type.
| 0xC1 node type.
|-
|-
|align="center"| 0x01
| align="center" | 0x01
|align="center"| 3
| align="center" | 3
| Number of entries in dictionary.
| Number of entries in dictionary.
|}
|}
Line 145: Line 276:
What then follows is a variable length array of dictionary entries. Each entry has the following structure.
What then follows is a variable length array of dictionary entries. Each entry has the following structure.


{|class="wikitable"
{| class="wikitable"
!align="center" width="5%"| Offset
! align="center" width="5%" | Offset
!align="center" width="3%"| Size
! align="center" width="3%" | Size
!width="90%"| Description
! width="90%" | Description
|-
|-
|align="center"| 0x00
| align="center" | 0x00
|align="center"| 3
| align="center" | 3
| Name. Value is an index in the hash key table.
| Name. Value is an index in the hash key table.
|-
|-
|align="center"| 0x03
| align="center" | 0x03
|align="center"| 1
| align="center" | 1
| The node type.
| The node type.
|-
|-
|align="center"| 0x04
| align="center" | 0x04
|align="center"| 4
| align="center" | 4
| Value. For regular value nodes, this is the 4 byte node value. For other nodes, this is a 4 byte offset to the node relative to the start of the file.
| Value. For regular value nodes, this is the 4 byte node value. For other nodes, this is a 4 byte offset to the node relative to the start of the file.
|}
|}
Line 165: Line 296:
==== 0xC2 - String Table Node ====
==== 0xC2 - String Table Node ====


{|class="wikitable"
{| class="wikitable"
!align="center" width="4%"| Offset
! align="center" width="4%" | Offset
!align="center" width="7%"| Size
! align="center" width="7%" | Size
!width="87%"| Description
! width="87%" | Description
|-
|-
|align="center"| 0x00
| align="center" | 0x00
|align="center"| 1
| align="center" | 1
| 0xC2 node type.
| 0xC2 node type.
|-
|-
|align="center"| 0x01
| align="center" | 0x01
|align="center"| 3
| align="center" | 3
| Number of entries in the string table.
| Number of entries in the string table.
|-
|-
|align="center"| 0x04
| align="center" | 0x04
|align="center"| Y=4*(N+1)
| align="center" | Y=4*(N+1)
| Array of N+1 offsets to each string relative to the start of the node. The last entry is an offset to the end of the last string.
| Array of N+1 offsets to each string relative to the start of the node. The last entry is an offset to the end of the last string.
|-
|-
|align="center"| 0x04+Y’
| align="center" | 0x04+Y’
|align="center"| variable
| align="center" | variable
| Array of N null-terminated strings stored in alphabetical order.
| Array of N null-terminated strings stored in alphabetical order.
|}
|}


Y’ is Y rounded up to the nearest multiple of 4.
Y’ is Y rounded up to the nearest multiple of 4.
== Usage in Nintendo games ==
{|class="wikitable"
! Game !! Endianness !! Version || Notes
|-
| ''Breath of the Wild'' (Wii U) || Big endian || 2 || Uses SMO's library (in al::)
|-
| ''Breath of the Wild'' (Switch) || Little endian || 2 || Uses SMO's library (in al::), but with unused code and support for big endian eliminated
|-
| ''Super Mario Odyssey'' (Switch) || Little endian (supports big endian as well) || 3 ||
|-
| ''Splatoon 2'' (Switch) || Little endian (supports big endian as well) || 3? || Uses SMO's library, but in the Lp::Utl:: namespace
|-
| ''Animal Crossing: New Horizons'' (Switch) || Little endian (supports big endian as well) || 4 ||
|}
The v3 format seems to be identical to v2 but with the 64-bit node types added.
=== Extensions ===
Nintendo uses several file extensions for BYML files in BotW. The basic format is the same even though each kind has a different purpose and contains different parameters. Known extensions:
* [[Baischedule|.baischedule]]
* [[Baniminfo|.baniminfo]]
* [[Bgdata|.bgdata]]
* [[Bgsvdata|.bgsvdata]]
* [[Bquestpack|.bquestpack]]
* [[BYML|.byml]]
* [[BYML|.byaml]]
* [[Mubin|.mubin]]
TotK has added the following extensions:
* .bgyml


== Tools ==
== Tools ==
* [https://github.com/SeekingFunChild/Byaml_Editor Byaml Editor]
{{tool table|category=Tools (BYML)}}
* [https://github.com/arbiter34/ninten-file-tool ninten-file-tool]: sbyml/sbwlp/smubin/baniminfo encode/decode with Yaz0 (byml/prod w/ yaz0)
* [https://github.com/leoetlino/byml-v2 byml-v2]: BYML <-> YAML converter which supports v2 and v3 files, all the new node types and both Switch and Wii U files. Can also be used as a library.


''This article was adapted from documentation in the [https://github.com/handsomematt/botw-modding/blob/master/docs/file_formats/byml.md handsomematt/botw-modding repo].''
''This article was adapted from documentation in the [https://github.com/handsomematt/botw-modding/blob/master/docs/file_formats/byml.md handsomematt/botw-modding repo].''
[[Category:File formats]]
2

edits