Skip to content

Instantly share code, notes, and snippets.

@tryashtar
Last active October 23, 2023 23:33
Show Gist options
  • Star 24 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tryashtar/87ad9654305e5df686acab05cc4b6205 to your computer and use it in GitHub Desktop.
Save tryashtar/87ad9654305e5df686acab05cc4b6205 to your computer and use it in GitHub Desktop.
Bedrock mcstructure file format

Bedrock .mcstructure files

Saving and Loading

mcstructure files are created by the Export button in a structure block. To load them in game with a load structure block, the files must be placed in a behavior pack. The path determines the structure identifier, which is typed into the structure block to load the structure.

Examples:
myBP/structures/house.mcstructuremystructure:house
myBP/structures/dungeon/entrance.mcstructuredungeon:entrance
myBP/structures/stuff/towers/diamond.mcstructurestuff:towers/diamond

The first subfolder defines the namespace, and subsequent folders define the path, ending with the structure file's name. This is different from Java's file structure, where the structures folder is inside the namespace folder itself.

Any files directly in the structures folder are given the mystructure namespace. If a structure exists in the structures folder and shares a name with a structure in an explicit mystructure folder, the game produces the following content log warning:

[Structure][warning]-There was a conflict loading a structure in the default namespace. A structure with name <name> was found in both in the root directory and the mystructure directory.

In this case, the file in the mystructure folder takes priority, resulting in the file directly in the structures folder being ignored.

Aside from behavior packs, structures can also be embedded directly in a world. The "Save" button in a structure block and the /structure save command both do this. Embedded structures take priority when loading, resulting in any identically-named structure in a behavior pack being ignored. Embedded structures can be removed with /structure delete.

File Format

mcstructure files are NBT files. Like all Bedrock Edition NBT files, they are stored in little-endian format. They are also uncompressed, making them very large. The tag structure is as follows:

Integer format_version: Currently always set to 1.
List size: List of three integers describing the size of the structure's bounds, measured in blocks.

Integer Size of the structure in the X direction (west/east).
Integer Size of the structure in the Y direction (down/up).
Integer Size of the structure in the Z direction (north/south).

Compound structure: Actual data compound.

List block_indices: List containing two sublists, one for each layer. These contain the blocks in the structure. Each block is stored as an integer index into the palette (see below). Entries proceed in ZYX order from the lowest corner to the highest one. To convert from an index to block coordinates: (i/SZ/SY, i/SZ%SY, i%SZ). To convert from coordinates to index: SZ*SY*X + SZ*Y + Z. Index values equal to -1 indicate no block, causing any existing block to remain upon loading. This occurs when structure voids are saved, and is the case for most blocks in the second layer. Both layers share the same palette.

List of Integer Indices for blocks in the primary layer.
List of Integer Indices for blocks in the secondary layer. This layer is usually empty, except for water when the block here is waterlogged.

List of Compound entities: List of entities as NBT, stored exactly the same as entities in the world file itself. Tags like Pos and UniqueID are saved, but replaced upon loading.

Compound palette: Contains multiple named palettes, presumably to support multiple variants of the same structure. However, currently only default is saved and loaded.

Compound A single palette (currently only named default).

List block_palette: List of block states. This list contains the ordered entries that the block indices are referring to.

Compound A single block state.

String name: The block's identifier, such as minecraft:planks.
Compound states: The block's states as keys and values. Examples: wood_type:"acacia", bite_counter:3, open_bit:1b. The values are the appropriate NBT type for the state: strings for enum values, integers for scalar numbers, and bytes for boolean values.
Integer version: Compatibility versioning number for this block. The four bytes making up this integer determine the game version number. For example, 17879555 is hex 01 10 D2 03, meaning 1.16.210.03.

Compound block_position_data: Contains additional data for individual blocks in the structure. Each key is an integer index into the flattened list of blocks inside of block_indices, and can be converted to block coordinates the same way.

Compound <index>: A single piece of additional block data, relevant to the block at its index position.

Compound block_entity_data: Block entity data as NBT, stored exactly the same as block entities in the world file itself. Position tags are saved, but replaced upon loading. Layer is unspecified, as multiple block entities cannot coexist in a block space.

List tick_queue_data: Contains one more compounds of scheduled tick information. This is used for blocks like coral to make it die, water to make it flow, and other various scheduled updates.

Compound A single pending tick.

Integer tick_delay: The amount of ticks remaining until this block should be updated. No other values seem to exist adjacent to this one at this time.

List structure_world_origin: List of three integers describing where in the world the structure was originally saved. Equal to the position of the saving structure block, plus its offset settings. This is used to determine where entities should be placed when loading. An entity's new absolute position is equal to its old position, minus these values, plus the origin of the structure's loading position.

Integer Structure origin X position.
Integer Structure origin Y position.
Integer Structure origin Z position.

What Happens If...

Results from testing to see what happens when modified structure files are loaded:

  • If the dimensions in size exceed the vanilla save limit of 64*256*64, the structure can still be loaded just as expected.
  • If the values in the block layer lists are not int tags, all values are treated as 0.
  • If a value in the block layer list is equal to or larger than the palette size, or less than -1, an air block is placed.
  • If the default palette is not present, loading the structure results in no blocks being placed.
  • If any of the tags that have constant names are unspecified or are the wrong tag type, the structure fails to load with the following content log error:
[Structure][error]-Loading structure '<identifier>' from behavior pack: '<path>' | "<tag>" field, a required field, is missing from the structure.
  • If block_indices does not contain exactly two values, the structure fails to load with the following content log error:
[Structure][error]-Loading structure '<identifier>' from behavior pack: '<path>' | The "block_indices" field should be an array with 2 arrays and instead we have <count> arrays.
  • If the values inside of block_indices are not list tags, the structure fails to load with the following content log error:
[Structure][error]-Loading structure '<identifier>' from behavior pack: '<path>' | The "block_indices" field's first array is either missing or not a list.
  • If the length of the two lists in block_indices are not equal, the structure fails to load with the following content log error:
[Structure][error]-Loading structure '<identifier>' from behavior pack: '<path>' | The "block_indices" field's arrays need to both be the same size.
  • If the length of the two lists in block_indices does not equal the product of the structure's dimensions, the structure fails to load with the following content log error:
[Structure][error]-Loading structure '<identifier>' from behavior pack: '<path>' | The "block_indices" field should have as many elements as defined by the "size" field.
@VideoCarp
Copy link

nice looks useful but hard to read

@LegoDori
Copy link

LegoDori commented Aug 4, 2020

How did You open the .mcstructure file? I tried multiple editors but still cant figure out how to do that.

@tryashtar
Copy link
Author

tryashtar commented Aug 5, 2020

Unfortunately I don't know of any regular applications that support little-endian NBT files. It would be nice if NBTExplorer did...
As for what I used, it was just https://github.com/mstefarov/fNbt to whip up something quick and dirty to open them up and print them out.

EDIT: I have made an NBT editor that supports these files, see here: https://github.com/tryashtar/nbt-studio

@T-P0ser
Copy link

T-P0ser commented Aug 14, 2020

Thank you so much for this!

@MilkyDeveloper
Copy link

Woah. Cool! Happy to see these technical features coming to bedrock.

@SirLich
Copy link

SirLich commented Aug 17, 2020

Looks like an amazing write-up. Would you have any interest (or objection?) in porting this over to https://wiki.bedrock.dev/?

@FeedFall8
Copy link

FeedFall8 commented Oct 29, 2020

such a amazing article

@notbeer
Copy link

notbeer commented Mar 31, 2021

I've seen someone come up with a script, which converts structure files to json files and it makes it so much easier to edit the structure with json file. Trying to work it out here on how to do that. Not sure, tbh.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment