LEB: Difference between revisions
mNo edit summary |
|||
(9 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
'''LEB''' is a custom format used to store room data in Link's Awakening. | '''LEB''' is a custom format used to store room data in Link's Awakening. This format is still in the process of being reverse engineered and so this page is currently incomplete. | ||
Note that many properties in these files define measurements in 3D space (X, Y, Z). X is horizontal across the screen, Y is perpendicular to the ground (the axis on which gravity acts), and Z is vertical across the screen. | |||
==Format== | ==Format== | ||
Line 72: | Line 72: | ||
====Version Section==== | ====Version Section==== | ||
Holds 3 bytes of data, which seem to always be 0x1001D4. Given the name, it's probably just a version marker and has no functional purpose. | |||
====Infomation Section==== | ====Infomation Section==== | ||
Holds 4 bytes of data. The purpose of this is unknown. | |||
====Point Section==== | ====Point Section==== | ||
This is a FixedHash child. It | This is a FixedHash child. It defines relevant co-ordinate points for actors in the room to use. Examples of this include points which actors can force Link to walk to during events, where a seashell should land from bonking a tree, and more. | ||
There is one entry per point. Points have data blocks of 0x18 bytes each. This block consists of 3 floats (4 bytes each) representing the (X, Y, Z) of the point. It appears that this is always followed by 0xC bytes of FF to fill out the block, but the reason for this is not known. | |||
====Rail Section==== | |||
This is another FixedHash child | This is another FixedHash child. The exact purpose of this section is not understand but it seems to work in conjunction with <code>point</code>. There is one entry per rail. | ||
Each rail has a data block of variable size, typically 0x32 or more bytes. | |||
{| class="wikitable" | |||
|+ | |||
!Offset | |||
!Type | |||
!Description | |||
|- | |||
|0x0 | |||
| | |||
|Appears to always be 0xC null bytes? | |||
|- | |||
|0xC | |||
| | |||
|Block of 4 structures with a parameter-like structure (see actor section) except for using 0xFFFFFF04 instead of 0x4. So far only observed to be blocks of [0x19, 0xFFFFFF04]. | |||
|- | |||
|0x2C | |||
|u16 | |||
|Number of entries in following list | |||
|- | |||
|0x2E | |||
|u16 | |||
|Number of indexes per entry? Only observed to ever be 0x01 so far, so no clear purpose. | |||
|- | |||
|0x30 | |||
|u16[...] | |||
|Indexes of points used per rail (in the <code>point</code> section). The logic behind how points are grouped into rails is not understood, but always seems to line up with how actors reference points. So, an actor that refers to (rail 0, point 0) and (rail 0, point 1) means that rail 0 references points 0 and 1. An actor referring only to (rail 2, point 2) and nothing else with rail 2 means that rail 2 only references point 2. | |||
|} | |||
====Actor Section==== | ====Actor Section==== | ||
This section is a FixedHash which holds actor data. Each entry corresponds to one actor. Every entry points to non-node data, | This section is a FixedHash which holds actor data. Each entry corresponds to one actor. Every entry points to non-node data, a block with a minimum size of 0x90 bytes, but can be longer. The names section is empty. The data block for each actor is formatted as follows. | ||
{| class="wikitable" | {| class="wikitable" | ||
|+ | |+ | ||
Line 114: | Line 140: | ||
|- | |- | ||
|0x14 | |0x14 | ||
| | |float[3] | ||
|''' | |'''Co-ordinates''' as [X, Y, Z]. One in-game "tile" is 1.5 units. | ||
The co-ordinate system spans entire maps and is not specific to each room. [0, 0, 0] is the very top left corner of the map, at the elevation of the main floor plane of the map. | |||
Each room is 10x8 tiles, so they span 15 units along the X axis and 12 along the Z axis. | |||
|- | |- | ||
|0x20 | |0x20 | ||
| | |float[3] | ||
| | |'''Rotation''' about the [X, Y, Z] axes respectively, in degrees. | ||
|- | |- | ||
|0x2C | |0x2C | ||
| | |float[3] | ||
| | |'''Scaling''' along the [X, Y, Z] axes respectively. Note that scaling doesn't seem to affect collision for every actor and only scales the model in some cases. | ||
|- | |- | ||
|0x38 | |0x38 | ||
|u32[16] | |u32[16] | ||
|'''Parameters'''. This section contains 16 u32's, which are grouped into 8 pairs of [parameter, parameter type]. | |'''Parameters'''. This section contains 16 u32's, which are grouped into 8 pairs of [parameter, parameter type]. | ||
The types are as follows: | |||
* | *0: the parameter is not used? Mainly observable in lighting actors. | ||
* | *2: Float | ||
* | *3: Unsigned integer (u32) | ||
* | *4: String, where the parameter value define the offset of the string in the top-level names section. | ||
Unused parameters are generally entered as offsets to a null byte in the names section, as a type 4 parameter. | |||
|- | |- | ||
|0x78 | |0x78 | ||
Line 184: | Line 187: | ||
The sections starts with | The sections starts with 12 bytes which define the structure and purpose of the data in the section, where the latter 6 bytes are always null. | ||
'''xx | '''ee kk bb xx''' '''yy zz''' 00 00 00 00 00 00 | ||
''' | '''e''' is 01 for any enemy actor and 00 otherwise. | ||
''' | '''k''' is 01 only for TagHolocaustChecker actors. Probably indicates looking at enemy spawns/kills. | ||
''' | '''b''' appears to be 01 for an enemy that appears from the +enemies tile in a chamber dungeon and 00 otherwise. | ||
''' | '''x''' indicates the number of entries in section 1. | ||
''' | '''y''' indicates the number of entries in section 3. | ||
''' | '''z''' indicates the number of entries in section 2. (This is not a typo, for some reason it defines the group sizes in the order 1, 3, 2.) | ||
Line 205: | Line 208: | ||
'''Section 2''' | '''Section 2''' defines a list of points the actor knows about. It consists of a sequence of 24-byte structures, which are each 2 parameters (8 bytes each), and 2 u32's, which respectively index into the <code>rail</code> section and the <code>point</code> section. This is used for various things, for example the Link:MoveToTargetLinkedPoint event action, or the location for item drops from the actor to land, or the location to dynamically spawn other actors (e.g. pickups in rapids rush). | ||
'''Section 3''' defines which actors | '''Section 3''' defines which actors can call upon use of this actor. It is simply a sequence of 4-byte actor indexes. This should line up with section 1 of other actors. As an example, if actor[2] defines control of actor[5] in its section 1, then actor[5]'s section 3 should contain 0x02. | ||
|} | |} | ||
====Grid Section==== | ====Grid Section==== | ||
This section is a child FixedHash which appears to define properties for each tile of the room. It has two or three entries: <code>data</code>, sometimes <code>chain</code>, and <code>info</code>. | |||
The data in the <code>data</code> section contains | |||
The data in the <code>data</code> section contains blocks 0x10 bytes each which define some properties for every tile on the screen, for a total of 0x500 bytes for top-down rooms and 0x140 bytes for sidescroller rooms. The format of these is not fully understood yet. | |||
{| class="wikitable" | |||
|+ | |||
!Offset | |||
!Type | |||
!Description | |||
|- | |||
|0x0 | |||
|bit field | |||
|The 4 bytes here seem to make up a bit field with a number of flags defining various tile properties. | |||
The first two bytes are set in a pattern that is consistent with the terrain collision of the room, but editing it does not seem to have any actual effect on the collision of the room. Will require more testing. | |||
Byte 1 (bits 76543210): | |||
7: indicates that there is solid collision to the south of this tile | |||
6: unused? | |||
5: indicates that there is solid collision to the east of this tile | |||
4: unused? | |||
3: indicates there is solid collision to the north of this tile | |||
2: unused? | |||
1: indicates that this tile contains solid collision | |||
0: indicates that the tile is deep water or lava (as opposed to shallow) | |||
Byte 2: | |||
7-2: unused? | |||
1: indicates that there is collision to the west of this tile | |||
0: unused? | |||
Note that in considering if there is collision next to a tile, it doesn't consider adjacent rooms. Tiles at the edge of a room will not "see" any collision past that edge. | |||
Byte 3: | |||
7: Appears to always be 0 | |||
6: Unknown. Set for the vast majority of tiles, but unset in a few specific cases. This is observable in overworld screens around the graveyard, and the bottom left of Signpost Maze (where the stairs to Mamu are). | |||
5: Appears to indicate whether the tile is allowed to "refresh its state" when you move away from the room. Most tiles have this bit set. This bit is set to 0 for every tile which contains a seashell under a rock, bush, or dig spot, and also the tile of the Slime Key (also a dig spot). Something these tiles have in common is being able to retain the state of the item on the ground for longer than other tiles' states (e.g. simple grass being cut). Oddly, every walkable tile in Lv1TailCave_04B (the spike turtle room) does not have this bit set, which differs from literally every other dungeon room. | |||
4: Whether or not the tile is a valid respawn point from loading a save file | |||
3: Whether or not the tile is a valid respawn point from voiding out | |||
2: Set if the tile is water/lava. Whether or not the tile is deep water seems to depend on something else. If set, the elevation for this tile does not appear to impact collision, only the height above the ground where splashing effects appear. | |||
1: Appears to always be 0 | |||
0: Whether you can use the shovel to dig on the tile. | |||
The last fourth byte appears to always be 0x80, or 0b10000000. | |||
|- | |||
|0x4 | |||
| | |||
|Unknown, seems to always be identical to the 4 bytes starting at 0x0. | |||
|- | |||
|0x8 | |||
|u32 | |||
|'''Chain index'''. Defines which chain to use as an index into the sequence of chains. If the tile doesn't refer to a chain tile, or there is no chain table defined, this will be 0xFFFFFFFF. | |||
|- | |||
|0xC | |||
|float | |||
|'''Elevation'''. Specifies the height of the surface that Link walks on over this tile. It is still unclear what causes tiles' elevations to be gradient (a ramp) or a sudden increase or decrease (a wall). | |||
|} | |||
The chain section is used for when there needs to be a higher walkable surface directly above a lower one. This is common in sidescroller rooms, but is also used in some overworld areas; mainly in Tal Tal Mountains where there are some walkable surfaces inside cliff faces which can be reached with out of bounds methods. Chain entries can still index to other chains. The data is stored in the same structures as the <code>data</code> section. | |||
The info block is always 0x10 bytes and holds some essentially metadata about the room, probably to be used alongside the other data here to determine collision. | |||
{| class="wikitable" | |||
|+ | |||
!Offset | |||
!Type | |||
!Description | |||
|- | |||
|0x0 | |||
|u16 | |||
|How many tiles tall the room is. Will always be 0x8 for top-down rooms and 0x2 for sidescroller rooms. | |||
|- | |||
|0x2 | |||
|u16 | |||
|How many tiles wide the room is. Seems to always be 0xA (10) | |||
|- | |||
|0x4 | |||
|float | |||
|The size of 1 tile in units. Seems to always be 1.5. | |||
|- | |||
|0x8 | |||
|float | |||
|X co-ordinate of the left edge of the room. | |||
|- | |||
|0xC | |||
|float | |||
|Z co-ordinate of the top edge of the room. For sidescroller rooms this seems to always be -1.5. | |||
|} | |||
===Names Section=== | ===Names Section=== |
Latest revision as of 07:20, 5 November 2021
LEB is a custom format used to store room data in Link's Awakening. This format is still in the process of being reverse engineered and so this page is currently incomplete.
Note that many properties in these files define measurements in 3D space (X, Y, Z). X is horizontal across the screen, Y is perpendicular to the ground (the axis on which gravity acts), and Z is vertical across the screen.
Format
LEB files are in a FixedHash format, with the data for actors stored in the data section and the names section. There is consistency in how the FixedHash is built for LEB files, with the exception of Lv07EagleTower_05E (the lower part of the Eagle boss room), which for some reason is different than all other rooms. Aside from this room, LEBs always have 0x17 hash table buckets and 0x4 child FixedHash nodes. The buckets are always the same, so the start of LEB files always look like:
3d01 1700 0400 0000 ffff ffff 0000 0000
2000 0000 ffff ffff ffff ffff ffff ffff
ffff ffff ffff ffff 4000 0000 ffff ffff
ffff ffff 5000 0000 ffff ffff 3000 0000
ffff ffff ffff ffff ffff ffff ffff ffff
ffff ffff ffff ffff ffff ffff ffff ffff
ffff ffff
Entries Section
There are 6 entries in most LEB files.
Node Index | Name Offset | Name Hash | Next entry offset | Data Offset |
---|---|---|---|---|
0xFFF0 | Offset of version in the names section
|
Hash of version
|
0xFFFFFFFF | Offset to version section |
0xFFF0 | Offset of infomation in the names section [sic]
|
Hash of infomation
|
0xFFFFFFFF | Offset to infomation |
0x0 | Offset of point in the names section
|
Hash of point
|
0xFFFFFFFF | Offset to point section |
0x1 | Offset of rail in the names section
|
Hash of rail
|
0xFFFFFFFF | Offset to rail section |
0x2 | Offset of actor in the names section
|
Hash of actor
|
0x10 | Offset to actor section |
0x3 | Offset of grid in the names section
|
Hash of grid
|
0xFFFFFFFF | Offset to grid secion |
Data Section
The data section contains one subsection for each entry (usually six).
Version Section
Holds 3 bytes of data, which seem to always be 0x1001D4. Given the name, it's probably just a version marker and has no functional purpose.
Infomation Section
Holds 4 bytes of data. The purpose of this is unknown.
Point Section
This is a FixedHash child. It defines relevant co-ordinate points for actors in the room to use. Examples of this include points which actors can force Link to walk to during events, where a seashell should land from bonking a tree, and more.
There is one entry per point. Points have data blocks of 0x18 bytes each. This block consists of 3 floats (4 bytes each) representing the (X, Y, Z) of the point. It appears that this is always followed by 0xC bytes of FF to fill out the block, but the reason for this is not known.
Rail Section
This is another FixedHash child. The exact purpose of this section is not understand but it seems to work in conjunction with point
. There is one entry per rail.
Each rail has a data block of variable size, typically 0x32 or more bytes.
Offset | Type | Description |
---|---|---|
0x0 | Appears to always be 0xC null bytes? | |
0xC | Block of 4 structures with a parameter-like structure (see actor section) except for using 0xFFFFFF04 instead of 0x4. So far only observed to be blocks of [0x19, 0xFFFFFF04]. | |
0x2C | u16 | Number of entries in following list |
0x2E | u16 | Number of indexes per entry? Only observed to ever be 0x01 so far, so no clear purpose. |
0x30 | u16[...] | Indexes of points used per rail (in the point section). The logic behind how points are grouped into rails is not understood, but always seems to line up with how actors reference points. So, an actor that refers to (rail 0, point 0) and (rail 0, point 1) means that rail 0 references points 0 and 1. An actor referring only to (rail 2, point 2) and nothing else with rail 2 means that rail 2 only references point 2.
|
Actor Section
This section is a FixedHash which holds actor data. Each entry corresponds to one actor. Every entry points to non-node data, a block with a minimum size of 0x90 bytes, but can be longer. The names section is empty. The data block for each actor is formatted as follows.
Offset | Type | Description |
---|---|---|
0x0 | u64 | Actor key. This value must match the hex value of the corresponding actor label in the (top-level) names section. |
0x8 | u32 | Names section offset. This stores the offset in the (top-level) names section for the start of the label that corresponds to this actor. |
0xC | u16 | Actor ID |
0xE | u16 | Padding? |
0x10 | u32 | Room ID. The actor loads when entering the specified room and unloads when leaving it. Generally this should be consistent across all actors in the file, since each room has its own file. |
0x14 | float[3] | Co-ordinates as [X, Y, Z]. One in-game "tile" is 1.5 units.
The co-ordinate system spans entire maps and is not specific to each room. [0, 0, 0] is the very top left corner of the map, at the elevation of the main floor plane of the map. Each room is 10x8 tiles, so they span 15 units along the X axis and 12 along the Z axis. |
0x20 | float[3] | Rotation about the [X, Y, Z] axes respectively, in degrees. |
0x2C | float[3] | Scaling along the [X, Y, Z] axes respectively. Note that scaling doesn't seem to affect collision for every actor and only scales the model in some cases. |
0x38 | u32[16] | Parameters. This section contains 16 u32's, which are grouped into 8 pairs of [parameter, parameter type].
The types are as follows:
Unused parameters are generally entered as offsets to a null byte in the names section, as a type 4 parameter. |
0x78 | Actor Switches. Defines 4 actor switches for the event. These are used for the behavior of many things like small keys, chests, NPCs, loading zones, doors, blocks, etc.
| |
0x84 | Actor Relationships. Defines the relationship this actor has with other actors in the room, primarily for use with events. This section uses a lot of actor indexes, which are the based on the order the actors are defined in the room. That is, the first defined actor is 0, the second is 1, etc.
e is 01 for any enemy actor and 00 otherwise. k is 01 only for TagHolocaustChecker actors. Probably indicates looking at enemy spawns/kills. b appears to be 01 for an enemy that appears from the +enemies tile in a chamber dungeon and 00 otherwise. x indicates the number of entries in section 1. y indicates the number of entries in section 3. z indicates the number of entries in section 2. (This is not a typo, for some reason it defines the group sizes in the order 1, 3, 2.)
|
Grid Section
This section is a child FixedHash which appears to define properties for each tile of the room. It has two or three entries: data
, sometimes chain
, and info
.
The data in the data
section contains blocks 0x10 bytes each which define some properties for every tile on the screen, for a total of 0x500 bytes for top-down rooms and 0x140 bytes for sidescroller rooms. The format of these is not fully understood yet.
Offset | Type | Description |
---|---|---|
0x0 | bit field | The 4 bytes here seem to make up a bit field with a number of flags defining various tile properties.
Byte 1 (bits 76543210): 7: indicates that there is solid collision to the south of this tile 6: unused? 5: indicates that there is solid collision to the east of this tile 4: unused? 3: indicates there is solid collision to the north of this tile 2: unused? 1: indicates that this tile contains solid collision 0: indicates that the tile is deep water or lava (as opposed to shallow)
7-2: unused? 1: indicates that there is collision to the west of this tile 0: unused?
7: Appears to always be 0 6: Unknown. Set for the vast majority of tiles, but unset in a few specific cases. This is observable in overworld screens around the graveyard, and the bottom left of Signpost Maze (where the stairs to Mamu are). 5: Appears to indicate whether the tile is allowed to "refresh its state" when you move away from the room. Most tiles have this bit set. This bit is set to 0 for every tile which contains a seashell under a rock, bush, or dig spot, and also the tile of the Slime Key (also a dig spot). Something these tiles have in common is being able to retain the state of the item on the ground for longer than other tiles' states (e.g. simple grass being cut). Oddly, every walkable tile in Lv1TailCave_04B (the spike turtle room) does not have this bit set, which differs from literally every other dungeon room. 4: Whether or not the tile is a valid respawn point from loading a save file 3: Whether or not the tile is a valid respawn point from voiding out 2: Set if the tile is water/lava. Whether or not the tile is deep water seems to depend on something else. If set, the elevation for this tile does not appear to impact collision, only the height above the ground where splashing effects appear. 1: Appears to always be 0 0: Whether you can use the shovel to dig on the tile.
|
0x4 | Unknown, seems to always be identical to the 4 bytes starting at 0x0. | |
0x8 | u32 | Chain index. Defines which chain to use as an index into the sequence of chains. If the tile doesn't refer to a chain tile, or there is no chain table defined, this will be 0xFFFFFFFF. |
0xC | float | Elevation. Specifies the height of the surface that Link walks on over this tile. It is still unclear what causes tiles' elevations to be gradient (a ramp) or a sudden increase or decrease (a wall). |
The chain section is used for when there needs to be a higher walkable surface directly above a lower one. This is common in sidescroller rooms, but is also used in some overworld areas; mainly in Tal Tal Mountains where there are some walkable surfaces inside cliff faces which can be reached with out of bounds methods. Chain entries can still index to other chains. The data is stored in the same structures as the data
section.
The info block is always 0x10 bytes and holds some essentially metadata about the room, probably to be used alongside the other data here to determine collision.
Offset | Type | Description |
---|---|---|
0x0 | u16 | How many tiles tall the room is. Will always be 0x8 for top-down rooms and 0x2 for sidescroller rooms. |
0x2 | u16 | How many tiles wide the room is. Seems to always be 0xA (10) |
0x4 | float | The size of 1 tile in units. Seems to always be 1.5. |
0x8 | float | X co-ordinate of the left edge of the room. |
0xC | float | Z co-ordinate of the top edge of the room. For sidescroller rooms this seems to always be -1.5. |
Names Section
The names section contains a list of actors by name, followed by a hyphen (-), followed by a 16-digit hexadecimal number. This also includes some plaintext parameters for some objects, such as the contents of a chest (ObjTreasureBox) or the destination of a loading zone (AreaLevelOpen). Note that these do not define what actors exist, in fact it seems like the actual labels here are meaningless aside from the aforementioned parameters.
All labels in the names section are separated by null bytes. Of note, there seems to always be one separator that 2 null bytes instead of 1. Depending on the file, this is either between point
and rail
at the start of the names section, or between the 1st and 2nd listed actors (it is more commonly the latter).