├── .github └── workflows │ └── run-pytest.yml ├── .gitignore ├── .readthedocs.yml ├── LICENSE ├── MANIFEST.in ├── README.md ├── anvil ├── __init__.py ├── biome.py ├── block.py ├── chunk.py ├── empty_chunk.py ├── empty_region.py ├── empty_section.py ├── errors.py ├── legacy.py ├── legacy_biomes.json ├── legacy_blocks.json ├── raw_section.py ├── region.py └── versions.py ├── docs ├── Makefile ├── _static │ └── custom.css ├── api.rst ├── conf.py ├── index.rst ├── make.bat └── requirements.txt ├── examples ├── _path.py ├── basic_world_gen.py ├── cube.py └── top_view.py ├── pytest.ini ├── setup.py └── tests ├── context.py ├── requirements.txt ├── test_benchmark.py ├── test_mixed_chunk_types.py ├── test_read_region.py └── test_stream_blocks.py /.github/workflows/run-pytest.yml: -------------------------------------------------------------------------------- 1 | # This workflow will install Python dependencies and run tests with a single version of Python 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions 3 | 4 | name: Tests 5 | 6 | on: 7 | push: 8 | branches: [ master ] 9 | pull_request: 10 | branches: [ master ] 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - uses: actions/checkout@v2 19 | - name: Set up Python 3.9 20 | uses: actions/setup-python@v2 21 | with: 22 | python-version: 3.9 23 | - name: Install dependencies 24 | run: | 25 | python -m pip install --upgrade pip 26 | pip install pytest 27 | if [ -f tests/requirements.txt ]; then pip install -r tests/requirements.txt; fi 28 | - name: Test with pytest 29 | run: | 30 | pytest 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__/ 2 | textures/ 3 | dist/ 4 | build/ 5 | *.egg-info/ 6 | .pytest_cache/ 7 | .vscode/ 8 | docs/_build/ 9 | examples/test_112.py 10 | venv 11 | -------------------------------------------------------------------------------- /.readthedocs.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | 3 | sphinx: 4 | configuration: docs/conf.py 5 | 6 | python: 7 | version: 3.7 8 | install: 9 | - requirements: docs/requirements.txt 10 | - requirements: tests/requirements.txt 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 mateus 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include anvil/legacy_blocks.json 2 | include anvil/legacy_biomes.json 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # anvil-parser2 2 | [![Documentation Status](https://readthedocs.org/projects/anvil-parser/badge/?version=latest)](https://anvil-parser.readthedocs.io/en/latest/?badge=latest) 3 | [![Tests](https://github.com/0xTiger/anvil-parser/actions/workflows/run-pytest.yml/badge.svg)](https://github.com/0xTiger/anvil-parser/actions/workflows/run-pytest.yml) 4 | [![PyPI - Downloads](https://img.shields.io/pypi/dm/anvil-parser)](https://pypi.org/project/anvil-parser2/) 5 | 6 | A parser for the [Minecraft anvil file format](https://minecraft.wiki/w/Anvil_file_format). This package was forked from [matcool's anvil-parser](https://github.com/matcool/anvil-parser) in order to additionally support minecraft versions 1.18 and above. 7 | # Installation 8 | ``` 9 | pip install anvil-parser2 10 | ``` 11 | 12 | # Usage 13 | ## Reading 14 | ```python 15 | import anvil 16 | 17 | region = anvil.Region.from_file('r.0.0.mca') 18 | 19 | # You can also provide the region file name instead of the object 20 | chunk = anvil.Chunk.from_region(region, 0, 0) 21 | 22 | # If `section` is not provided, will get it from the y coords 23 | # and assume it's global 24 | block = chunk.get_block(0, 0, 0) 25 | 26 | print(block) # 27 | print(block.id) # air 28 | print(block.properties) # {} 29 | ``` 30 | ## Making own regions 31 | ```python 32 | import anvil 33 | from random import choice 34 | 35 | # Create a new region with the `EmptyRegion` class at 0, 0 (in region coords) 36 | region = anvil.EmptyRegion(0, 0) 37 | 38 | # Create `Block` objects that are used to set blocks 39 | stone = anvil.Block('minecraft', 'stone') 40 | dirt = anvil.Block('minecraft', 'dirt') 41 | 42 | # Make a 16x16x16 cube of either stone or dirt blocks 43 | for y in range(16): 44 | for z in range(16): 45 | for x in range(16): 46 | region.set_block(choice((stone, dirt)), x, y, z) 47 | 48 | # Save to a file 49 | region.save('r.0.0.mca') 50 | ``` 51 | # Todo 52 | *things to do before 1.0.0* 53 | - [x] Proper documentation 54 | - [x] Biomes 55 | - [x] CI 56 | - [ ] More tests 57 | - [ ] Tests for 20w17a+ BlockStates format 58 | # Note 59 | Testing done in 1.14.4 - 1.19, should work fine for other versions. 60 | Writing chunks and regions is broken from 1.16 onwards 61 | -------------------------------------------------------------------------------- /anvil/__init__.py: -------------------------------------------------------------------------------- 1 | from .chunk import Chunk 2 | from .block import Block, OldBlock 3 | from .biome import Biome 4 | from .region import Region 5 | from .empty_region import EmptyRegion 6 | from .empty_chunk import EmptyChunk 7 | from .empty_section import EmptySection 8 | from .raw_section import RawSection 9 | -------------------------------------------------------------------------------- /anvil/biome.py: -------------------------------------------------------------------------------- 1 | from .legacy import LEGACY_BIOMES_ID_MAP 2 | 3 | class Biome: 4 | """ 5 | Represents a minecraft biome. 6 | 7 | Attributes 8 | ---------- 9 | namespace: :class:`str` 10 | Namespace of the biome, most of the time this is ``minecraft`` 11 | id: :class:`str` 12 | ID of the biome, for example: forest, warm_ocean, etc... 13 | """ 14 | __slots__ = ('namespace', 'id') 15 | 16 | def __init__(self, namespace: str, biome_id: str=None): 17 | """ 18 | Parameters 19 | ---------- 20 | namespace 21 | Namespace of the biome. If no biome_id is given, assume this is ``biome_id`` and set namespace to ``"minecraft"`` 22 | biome_id 23 | ID of the biome 24 | """ 25 | if biome_id is None: 26 | self.namespace = 'minecraft' 27 | self.id = namespace 28 | else: 29 | self.namespace = namespace 30 | self.id = biome_id 31 | 32 | def name(self) -> str: 33 | """ 34 | Returns the biome in the ``minecraft:biome_id`` format 35 | """ 36 | return self.namespace + ':' + self.id 37 | 38 | def __repr__(self): 39 | return f'Biome({self.name()})' 40 | 41 | def __eq__(self, other): 42 | if not isinstance(other, Biome): 43 | return False 44 | return self.namespace == other.namespace and self.id == other.id 45 | 46 | def __hash__(self): 47 | return hash(self.name()) 48 | 49 | @classmethod 50 | def from_name(cls, name: str): 51 | """ 52 | Creates a new Biome from the format: ``namespace:biome_id`` 53 | 54 | Parameters 55 | ---------- 56 | name 57 | Biome in said format 58 | """ 59 | namespace, biome_id = name.split(':') 60 | return cls(namespace, biome_id) 61 | 62 | @classmethod 63 | def from_numeric_id(cls, biome_id: int): 64 | """ 65 | Creates a new Biome from the numeric biome_id format 66 | 67 | Parameters 68 | ---------- 69 | biome_id 70 | Numeric ID of the biome 71 | """ 72 | if biome_id not in LEGACY_BIOMES_ID_MAP: 73 | raise KeyError(f'Biome {biome_id} not found') 74 | name = LEGACY_BIOMES_ID_MAP[biome_id] 75 | return cls('minecraft', name) -------------------------------------------------------------------------------- /anvil/block.py: -------------------------------------------------------------------------------- 1 | from nbt import nbt 2 | from frozendict import frozendict 3 | from .legacy import LEGACY_ID_MAP 4 | 5 | class Block: 6 | """ 7 | Represents a minecraft block. 8 | 9 | Attributes 10 | ---------- 11 | namespace: :class:`str` 12 | Namespace of the block, most of the time this is ``minecraft`` 13 | id: :class:`str` 14 | ID of the block, for example: stone, diamond_block, etc... 15 | properties: :class:`dict` 16 | Block properties as a dict 17 | """ 18 | __slots__ = ('namespace', 'id', 'properties') 19 | 20 | def __init__(self, namespace: str, block_id: str=None, properties: dict=None): 21 | """ 22 | Parameters 23 | ---------- 24 | namespace 25 | Namespace of the block. If no block_id is given, assume this is ``block_id`` and set namespace to ``"minecraft"`` 26 | block_id 27 | ID of the block 28 | properties 29 | Block properties 30 | """ 31 | if block_id is None: 32 | self.namespace = 'minecraft' 33 | self.id = namespace 34 | else: 35 | self.namespace = namespace 36 | self.id = block_id 37 | self.properties = properties or {} 38 | 39 | def name(self) -> str: 40 | """ 41 | Returns the block in the ``minecraft:block_id`` format 42 | """ 43 | return self.namespace + ':' + self.id 44 | 45 | def __repr__(self): 46 | return f'Block({self.name()})' 47 | 48 | def __eq__(self, other): 49 | if not isinstance(other, Block): 50 | return False 51 | return self.namespace == other.namespace and self.id == other.id and self.properties == other.properties 52 | 53 | def __hash__(self): 54 | return hash(self.name()) ^ hash(frozendict(self.properties)) 55 | 56 | @classmethod 57 | def from_name(cls, name: str, *args, **kwargs): 58 | """ 59 | Creates a new Block from the format: ``namespace:block_id`` 60 | 61 | Parameters 62 | ---------- 63 | name 64 | Block in said format 65 | , args, kwargs 66 | Will be passed on to the main constructor 67 | """ 68 | namespace, block_id = name.split(':') 69 | return cls(namespace, block_id, *args, **kwargs) 70 | 71 | @classmethod 72 | def from_palette(cls, tag: nbt.TAG_Compound): 73 | """ 74 | Creates a new Block from the tag format on Section.Palette 75 | 76 | Parameters 77 | ---------- 78 | tag 79 | Raw tag from a section's palette 80 | """ 81 | name = tag['Name'].value 82 | properties = dict(tag.get('Properties', dict())) 83 | return cls.from_name(name, properties=properties) 84 | 85 | @classmethod 86 | def from_numeric_id(cls, block_id: int, data: int=0): 87 | """ 88 | Creates a new Block from the block_id:data fromat used pre-flattening (pre-1.13) 89 | 90 | Parameters 91 | ---------- 92 | block_id 93 | Numeric ID of the block 94 | data 95 | Numeric data, used to represent variants of the block 96 | """ 97 | # See https://minecraft.wiki/w/Java_Edition_data_value/Pre-flattening 98 | # and https://minecraft.wiki/w/Java_Edition_data_value for current values 99 | key = f'{block_id}:{data}' 100 | if key not in LEGACY_ID_MAP: 101 | raise KeyError(f'Block {key} not found') 102 | name, properties = LEGACY_ID_MAP[key] 103 | return cls('minecraft', name, properties=properties) 104 | 105 | 106 | class OldBlock: 107 | """ 108 | Represents a pre 1.13 minecraft block, with a numeric id. 109 | 110 | Attributes 111 | ---------- 112 | id: :class:`int` 113 | Numeric ID of the block 114 | data: :class:`int` 115 | The block data, used to represent variants of the block 116 | """ 117 | __slots__ = ('id', 'data') 118 | 119 | def __init__(self, block_id: int, data: int=0): 120 | """ 121 | Parameters 122 | ---------- 123 | block_id 124 | ID of the block 125 | data 126 | Block data 127 | """ 128 | self.id = block_id 129 | self.data = data 130 | 131 | def convert(self) -> Block: 132 | return Block.from_numeric_id(self.id, self.data) 133 | 134 | def __repr__(self): 135 | return f'OldBlock(id={self.id}, data={self.data})' 136 | 137 | def __eq__(self, other): 138 | if isinstance(other, int): 139 | return self.id == other 140 | elif not isinstance(other, Block): 141 | return False 142 | else: 143 | return self.id == other.id and self.data == other.data 144 | 145 | def __hash__(self): 146 | return hash(self.id) ^ hash(self.data) 147 | -------------------------------------------------------------------------------- /anvil/chunk.py: -------------------------------------------------------------------------------- 1 | from typing import Union, Tuple, Generator, Optional 2 | from nbt import nbt 3 | from .biome import Biome 4 | from .block import Block, OldBlock 5 | from .region import Region 6 | from .errors import OutOfBoundsCoordinates, ChunkNotFound 7 | from .versions import VERSION_21w43a, VERSION_20w17a, VERSION_19w36a, VERSION_17w47a, VERSION_PRE_15w32a 8 | 9 | 10 | def bin_append(a, b, length=None): 11 | """ 12 | Appends number a to the left of b 13 | bin_append(0b1, 0b10) = 0b110 14 | """ 15 | length = length or b.bit_length() 16 | return (a << length) | b 17 | 18 | 19 | def nibble(byte_array, index): 20 | value = byte_array[index // 2] 21 | if index % 2: 22 | return value >> 4 23 | else: 24 | return value & 0b1111 25 | 26 | 27 | def _palette_from_section(section: nbt.TAG_Compound) -> nbt.TAG_List: 28 | if 'block_states' in section: 29 | return section["block_states"]["palette"] 30 | else: 31 | return section["Palette"] 32 | 33 | 34 | def _states_from_section(section: nbt.TAG_Compound) -> list: 35 | # BlockStates is an array of 64 bit numbers 36 | # that holds the blocks index on the palette list 37 | if 'block_states' in section: 38 | states = section['block_states']['data'] 39 | else: 40 | states = section['BlockStates'] 41 | 42 | # makes sure the number is unsigned 43 | # by adding 2^64 44 | # could also use ctypes.c_ulonglong(n).value but that'd require an extra import 45 | 46 | return [state if state >= 0 else states + 2 ** 64 47 | for state in states.value] 48 | 49 | 50 | def _section_height_range(version: Optional[int]) -> range: 51 | if version > VERSION_17w47a: 52 | return range(-4, 20) 53 | else: 54 | return range(16) 55 | 56 | 57 | class Chunk: 58 | """ 59 | Represents a chunk from a ``.mca`` file. 60 | 61 | Note that this is read only. 62 | 63 | Attributes 64 | ---------- 65 | x: :class:`int` 66 | Chunk's X position 67 | z: :class:`int` 68 | Chunk's Z position 69 | version: :class:`int` 70 | Version of the chunk NBT structure 71 | data: :class:`nbt.TAG_Compound` 72 | Raw NBT data of the chunk 73 | tile_entities: :class:`nbt.TAG_Compound` 74 | ``self.data['TileEntities']`` as an attribute for easier use 75 | """ 76 | 77 | __slots__ = ("version", "data", "x", "z", "tile_entities") 78 | 79 | def __init__(self, nbt_data: nbt.NBTFile): 80 | try: 81 | self.version = nbt_data["DataVersion"].value 82 | except KeyError: 83 | # Version is pre-1.9 snapshot 15w32a, so world does not have a Data Version. 84 | # See https://minecraft.wiki/w/Data_version 85 | self.version = VERSION_PRE_15w32a 86 | 87 | if self.version >= VERSION_21w43a: 88 | self.data = nbt_data 89 | self.tile_entities = self.data["block_entities"] 90 | else: 91 | self.data = nbt_data["Level"] 92 | self.tile_entities = self.data["TileEntities"] 93 | self.x = self.data["xPos"].value 94 | self.z = self.data["zPos"].value 95 | 96 | def get_section(self, y: int) -> nbt.TAG_Compound: 97 | """ 98 | Returns the section at given y index 99 | can also return nothing if section is missing, aka it's empty 100 | 101 | Parameters 102 | ---------- 103 | y 104 | Section Y index 105 | 106 | Raises 107 | ------ 108 | anvil.OutOfBoundsCoordinates 109 | If Y is not in range of 0 to 15 110 | """ 111 | section_range = _section_height_range(self.version) 112 | if y not in section_range: 113 | raise OutOfBoundsCoordinates(f"Y ({y!r}) must be in range of " 114 | f"{section_range.start} to {section_range.stop}") 115 | 116 | if 'sections' in self.data: 117 | sections = self.data["sections"] 118 | else: 119 | try: 120 | sections = self.data["Sections"] 121 | except KeyError: 122 | return None 123 | 124 | for section in sections: 125 | if section["Y"].value == y: 126 | return section 127 | 128 | def get_palette(self, section: Union[int, nbt.TAG_Compound]) -> Tuple[Block]: 129 | """ 130 | Returns the block palette for given section 131 | 132 | Parameters 133 | ---------- 134 | section 135 | Either a section NBT tag or an index 136 | 137 | 138 | :rtype: Tuple[:class:`anvil.Block`] 139 | """ 140 | if isinstance(section, int): 141 | section = self.get_section(section) 142 | if section is None: 143 | return 144 | palette = _palette_from_section(section) 145 | return tuple(Block.from_palette(i) for i in palette) 146 | 147 | def get_biome(self, x: int, y: int, z: int) -> Biome: 148 | """ 149 | Returns the biome in the given coordinates 150 | 151 | Parameters 152 | ---------- 153 | int x, y, z 154 | Biome's coordinates in the chunk 155 | 156 | Raises 157 | ------ 158 | anvil.OutOfBoundCoordidnates 159 | If X, Y or Z are not in the proper range 160 | 161 | :rtype: :class:`anvil.Biome` 162 | """ 163 | section_range = _section_height_range(self.version) 164 | if x not in range(16): 165 | raise OutOfBoundsCoordinates(f"X ({x!r}) must be in range of 0 to 15") 166 | if z not in range(16): 167 | raise OutOfBoundsCoordinates(f"Z ({z!r}) must be in range of 0 to 15") 168 | if y // 16 not in section_range: 169 | raise OutOfBoundsCoordinates(f"Y ({y!r}) must be in range of " 170 | f"{section_range.start * 16} to {section_range.stop * 16 - 1}") 171 | 172 | if 'Biomes' not in self.data: 173 | # Each biome index refers to a 4x4x4 volumes here so we do integer division by 4 174 | section = self.get_section(y // 16) 175 | biomes = section['biomes'] 176 | biomes_palette = biomes['palette'] 177 | if 'data' in biomes: 178 | biomes = biomes['data'] 179 | else: 180 | # When there is only one biome in the section of the palette 'data' 181 | # is not present 182 | return Biome.from_name(biomes_palette[0].value) 183 | 184 | 185 | index = ((y % 16 // 4) * 4 * 4) + (z // 4) * 4 + (x // 4) 186 | bits = (len(biomes_palette) - 1).bit_length() 187 | state = index * bits // 64 188 | data = biomes[state] 189 | 190 | # shift the number to the right to remove the left over bits 191 | # and shift so the i'th biome is the first one 192 | shifted_data = data >> ((bits * index) % 64) 193 | 194 | # if there aren't enough bits it means the rest are in the next number 195 | if 64 - ((bits * index) % 64) < bits: 196 | data = biomes[state + 1] 197 | 198 | # get how many bits are from a palette index of the next biome 199 | leftover = (bits - ((state + 1) * 64 % bits)) % bits 200 | 201 | # Make sure to keep the length of the bits in the first state 202 | # Example: bits is 5, and leftover is 3 203 | # Next state Current state (already shifted) 204 | # 0b101010110101101010010 0b01 205 | # will result in bin_append(0b010, 0b01, 2) = 0b01001 206 | shifted_data = bin_append( 207 | data & 2**leftover - 1, shifted_data, bits - leftover 208 | ) 209 | 210 | palette_id = shifted_data & 2**bits - 1 211 | return Biome.from_name(biomes_palette[palette_id].value) 212 | 213 | else: 214 | biomes = self.data["Biomes"] 215 | if self.version < VERSION_19w36a: 216 | # Each biome index refers to a column stored Z then X. 217 | index = z * 16 + x 218 | else: 219 | # https://minecraft.wiki/w/Java_Edition_19w36a 220 | # Get index on the biome list with the order YZX 221 | # Each biome index refers to a 4x4 areas here so we do integer division by 4 222 | index = (y // 4) * 4 * 4 + (z // 4) * 4 + (x // 4) 223 | biome_id = biomes[index] 224 | return Biome.from_numeric_id(biome_id) 225 | 226 | def get_block( 227 | self, 228 | x: int, 229 | y: int, 230 | z: int, 231 | section: Union[int, nbt.TAG_Compound] = None, 232 | force_new: bool = False, 233 | ) -> Union[Block, OldBlock]: 234 | """ 235 | Returns the block in the given coordinates 236 | 237 | Parameters 238 | ---------- 239 | int x, y, z 240 | Block's coordinates in the chunk 241 | section : int 242 | Either a section NBT tag or an index. If no section is given, 243 | assume Y is global and use it for getting the section. 244 | force_new 245 | Always returns an instance of Block if True, otherwise returns type OldBlock for pre-1.13 versions. 246 | Defaults to False 247 | 248 | Raises 249 | ------ 250 | anvil.OutOfBoundCoordidnates 251 | If X, Y or Z are not in the proper range 252 | 253 | :rtype: :class:`anvil.Block` 254 | """ 255 | if x not in range(16): 256 | raise OutOfBoundsCoordinates(f"X ({x!r}) must be in range of 0 to 15") 257 | if z not in range(16): 258 | raise OutOfBoundsCoordinates(f"Z ({z!r}) must be in range of 0 to 15") 259 | section_range = _section_height_range(self.version) 260 | if y // 16 not in section_range: 261 | raise OutOfBoundsCoordinates(f"Y ({y!r}) must be in range of " 262 | f"{section_range.start * 16} to {section_range.stop * 16 - 1}") 263 | 264 | if section is None: 265 | section = self.get_section(y // 16) 266 | # global Y to section Y 267 | y %= 16 268 | 269 | if self.version < VERSION_17w47a: 270 | # Explained in depth here https://minecraft.wiki/w/index.php?title=Chunk_format&oldid=1153403#Block_format 271 | 272 | if section is None or "Blocks" not in section: 273 | if force_new: 274 | return Block.from_name("minecraft:air") 275 | else: 276 | return OldBlock(0) 277 | 278 | index = y * 16 * 16 + z * 16 + x 279 | 280 | block_id = section["Blocks"][index] 281 | if "Add" in section: 282 | block_id += nibble(section["Add"], index) << 8 283 | 284 | block_data = nibble(section["Data"], index) 285 | 286 | block = OldBlock(block_id, block_data) 287 | if force_new: 288 | return block.convert() 289 | else: 290 | return block 291 | 292 | # If its an empty section its most likely an air block 293 | if section is None: 294 | return Block.from_name("minecraft:air") 295 | try: 296 | states = _states_from_section(section) 297 | except KeyError: 298 | return Block.from_name("minecraft:air") 299 | 300 | # Number of bits each block is on BlockStates 301 | # Cannot be lower than 4 302 | palette = _palette_from_section(section) 303 | 304 | bits = max((len(palette) - 1).bit_length(), 4) 305 | 306 | # Get index on the block list with the order YZX 307 | index = y * 16 * 16 + z * 16 + x 308 | # in 20w17a and newer blocks cannot occupy more than one element on the BlockStates array 309 | stretches = self.version < VERSION_20w17a 310 | 311 | # get location in the BlockStates array via the index 312 | if stretches: 313 | state = index * bits // 64 314 | else: 315 | state = index // (64 // bits) 316 | 317 | data = states[state] 318 | 319 | if stretches: 320 | # shift the number to the right to remove the left over bits 321 | # and shift so the i'th block is the first one 322 | shifted_data = data >> ((bits * index) % 64) 323 | else: 324 | shifted_data = data >> (index % (64 // bits) * bits) 325 | 326 | # if there aren't enough bits it means the rest are in the next number 327 | if stretches and 64 - ((bits * index) % 64) < bits: 328 | data = states[state + 1] 329 | 330 | # get how many bits are from a palette index of the next block 331 | leftover = (bits - ((state + 1) * 64 % bits)) % bits 332 | 333 | # Make sure to keep the length of the bits in the first state 334 | # Example: bits is 5, and leftover is 3 335 | # Next state Current state (already shifted) 336 | # 0b101010110101101010010 0b01 337 | # will result in bin_append(0b010, 0b01, 2) = 0b01001 338 | shifted_data = bin_append( 339 | data & 2**leftover - 1, shifted_data, bits - leftover 340 | ) 341 | 342 | # get `bits` least significant bits 343 | # which are the palette index 344 | palette_id = shifted_data & 2**bits - 1 345 | return Block.from_palette(palette[palette_id]) 346 | 347 | def stream_blocks( 348 | self, 349 | index: int = 0, 350 | section: Union[int, nbt.TAG_Compound] = None, 351 | force_new: bool = False, 352 | ) -> Generator[Block, None, None]: 353 | """ 354 | Returns a generator for all the blocks in given section 355 | 356 | Parameters 357 | ---------- 358 | index 359 | At what block to start from. 360 | 361 | To get an index from (x, y, z), simply do: 362 | 363 | ``y * 256 + z * 16 + x`` 364 | section 365 | Either a Y index or a section NBT tag. 366 | force_new 367 | Always returns an instance of Block if True, otherwise returns type OldBlock for pre-1.13 versions. 368 | Defaults to False 369 | 370 | Raises 371 | ------ 372 | anvil.OutOfBoundCoordidnates 373 | If `section` is not in the range of 0 to 15 374 | 375 | Yields 376 | ------ 377 | :class:`anvil.Block` 378 | """ 379 | 380 | if isinstance(section, int): 381 | section_range = _section_height_range(self.version) 382 | if section not in section_range: 383 | raise OutOfBoundsCoordinates(f"section ({section!r}) must be in range of " 384 | f"{section_range.start} to {section_range.stop}") 385 | 386 | # For better understanding of this code, read get_block()'s source 387 | 388 | if section is None or isinstance(section, int): 389 | section = self.get_section(section or 0) 390 | 391 | if self.version < VERSION_17w47a: 392 | if section is None or "Blocks" not in section: 393 | air = Block.from_name("minecraft:air") if force_new else OldBlock(0) 394 | for _ in range(4096): 395 | yield air 396 | return 397 | 398 | while index < 4096: 399 | block_id = section["Blocks"][index] 400 | if "Add" in section: 401 | block_id += nibble(section["Add"], index) << 8 402 | 403 | block_data = nibble(section["Data"], index) 404 | 405 | block = OldBlock(block_id, block_data) 406 | if force_new: 407 | yield block.convert() 408 | else: 409 | yield block 410 | 411 | index += 1 412 | return 413 | 414 | air = Block.from_name("minecraft:air") 415 | if section is None: 416 | for _ in range(4096): 417 | yield air 418 | return 419 | try: 420 | states = _states_from_section(section) 421 | except KeyError: 422 | for _ in range(4096): 423 | yield air 424 | return 425 | 426 | palette = _palette_from_section(section) 427 | bits = max((len(palette) - 1).bit_length(), 4) 428 | 429 | stretches = self.version < VERSION_20w17a 430 | 431 | if stretches: 432 | state = index * bits // 64 433 | else: 434 | state = index // (64 // bits) 435 | 436 | data = states[state] 437 | 438 | bits_mask = 2**bits - 1 439 | 440 | if stretches: 441 | offset = (bits * index) % 64 442 | else: 443 | offset = index % (64 // bits) * bits 444 | 445 | data_len = 64 - offset 446 | data >>= offset 447 | 448 | while index < 4096: 449 | if data_len < bits: 450 | state += 1 451 | new_data = states[state] 452 | 453 | if stretches: 454 | leftover = data_len 455 | data_len += 64 456 | 457 | data = bin_append(new_data, data, leftover) 458 | else: 459 | data = new_data 460 | data_len = 64 461 | 462 | palette_id = data & bits_mask 463 | yield Block.from_palette(palette[palette_id]) 464 | 465 | index += 1 466 | data >>= bits 467 | data_len -= bits 468 | 469 | def stream_chunk( 470 | self, index: int = 0, section: Union[int, nbt.TAG_Compound] = None 471 | ) -> Generator[Block, None, None]: 472 | """ 473 | Returns a generator for all the blocks in the chunk 474 | 475 | This is a helper function that runs Chunk.stream_blocks from section 0 to 15 476 | 477 | Yields 478 | ------ 479 | :class:`anvil.Block` 480 | """ 481 | for section in _section_height_range(self.version): 482 | for block in self.stream_blocks(section=section): 483 | yield block 484 | 485 | def get_tile_entity(self, x: int, y: int, z: int) -> Optional[nbt.TAG_Compound]: 486 | """ 487 | Returns the tile entity at given coordinates, or ``None`` if there isn't a tile entity 488 | 489 | To iterate through all tile entities in the chunk, use :class:`Chunk.tile_entities` 490 | """ 491 | for tile_entity in self.tile_entities: 492 | t_x, t_y, t_z = [tile_entity[k].value for k in "xyz"] 493 | if x == t_x and y == t_y and z == t_z: 494 | return tile_entity 495 | 496 | @classmethod 497 | def from_region(cls, region: Union[str, Region], chunk_x: int, chunk_z: int): 498 | """ 499 | Creates a new chunk from region and the chunk's X and Z 500 | 501 | Parameters 502 | ---------- 503 | region 504 | Either a :class:`anvil.Region` or a region file name (like ``r.0.0.mca``) 505 | 506 | Raises 507 | ---------- 508 | anvil.ChunkNotFound 509 | If a chunk is outside this region or hasn't been generated yet 510 | """ 511 | if isinstance(region, str): 512 | region = Region.from_file(region) 513 | nbt_data = region.chunk_data(chunk_x, chunk_z) 514 | if nbt_data is None: 515 | raise ChunkNotFound(f"Could not find chunk ({chunk_x}, {chunk_z})") 516 | return cls(nbt_data) 517 | -------------------------------------------------------------------------------- /anvil/empty_chunk.py: -------------------------------------------------------------------------------- 1 | from typing import List 2 | from .block import Block 3 | from .biome import Biome 4 | from .empty_section import EmptySection 5 | from .errors import OutOfBoundsCoordinates, EmptySectionAlreadyExists 6 | from nbt import nbt 7 | from .legacy import LEGACY_BIOMES_ID_MAP 8 | 9 | 10 | def _get_legacy_biome_id(biome: Biome) -> int: 11 | for k, v in LEGACY_BIOMES_ID_MAP.items(): 12 | if v == biome.id: 13 | return k 14 | raise ValueError(f'Biome id "{biome.id}" has no legacy equivalent') 15 | 16 | 17 | class EmptyChunk: 18 | """ 19 | Used for making own chunks 20 | 21 | Attributes 22 | ---------- 23 | x: :class:`int` 24 | Chunk's X position 25 | z: :class:`int` 26 | Chunk's Z position 27 | sections: List[:class:`anvil.EmptySection`] 28 | List of all the sections in this chunk 29 | version: :class:`int` 30 | Chunk's DataVersion 31 | """ 32 | __slots__ = ('x', 'z', 'sections', 'biomes', 'version') 33 | def __init__(self, x: int, z: int): 34 | self.x = x 35 | self.z = z 36 | self.sections: List[EmptySection] = [None]*16 37 | self.biomes: List[Biome] = [Biome('ocean')]*16*16 38 | self.version = 1976 39 | 40 | def add_section(self, section: EmptySection, replace: bool = True): 41 | """ 42 | Adds a section to the chunk 43 | 44 | Parameters 45 | ---------- 46 | section 47 | Section to add 48 | replace 49 | Whether to replace section if one at same Y already exists 50 | 51 | Raises 52 | ------ 53 | anvil.EmptySectionAlreadyExists 54 | If ``replace`` is ``False`` and section with same Y already exists in this chunk 55 | """ 56 | if self.sections[section.y] and not replace: 57 | raise EmptySectionAlreadyExists(f'EmptySection (Y={section.y}) already exists in this chunk') 58 | self.sections[section.y] = section 59 | 60 | def get_block(self, x: int, y: int, z: int) -> Block: 61 | """ 62 | Gets the block at given coordinates 63 | 64 | Parameters 65 | ---------- 66 | int x, z 67 | In range of 0 to 15 68 | y 69 | In range of 0 to 255 70 | 71 | Raises 72 | ------ 73 | anvil.OutOfBoundCoordidnates 74 | If X, Y or Z are not in the proper range 75 | 76 | Returns 77 | ------- 78 | block : :class:`anvil.Block` or None 79 | Returns ``None`` if the section is empty, meaning the block 80 | is most likely an air block. 81 | """ 82 | if x not in range(16): 83 | raise OutOfBoundsCoordinates(f'X ({x!r}) must be in range of 0 to 15') 84 | if z not in range(16): 85 | raise OutOfBoundsCoordinates(f'Z ({z!r}) must be in range of 0 to 15') 86 | if y not in range(256): 87 | raise OutOfBoundsCoordinates(f'Y ({y!r}) must be in range of 0 to 255') 88 | section = self.sections[y // 16] 89 | if section is None: 90 | return 91 | return section.get_block(x, y % 16, z) 92 | 93 | def set_block(self, block: Block, x: int, y: int, z: int): 94 | """ 95 | Sets block at given coordinates 96 | 97 | Parameters 98 | ---------- 99 | int x, z 100 | In range of 0 to 15 101 | y 102 | In range of 0 to 255 103 | 104 | Raises 105 | ------ 106 | anvil.OutOfBoundCoordidnates 107 | If X, Y or Z are not in the proper range 108 | """ 109 | if x not in range(16): 110 | raise OutOfBoundsCoordinates(f'X ({x!r}) must be in range of 0 to 15') 111 | if z not in range(16): 112 | raise OutOfBoundsCoordinates(f'Z ({z!r}) must be in range of 0 to 15') 113 | if y not in range(256): 114 | raise OutOfBoundsCoordinates(f'Y ({y!r}) must be in range of 0 to 255') 115 | section = self.sections[y // 16] 116 | if section is None: 117 | section = EmptySection(y // 16) 118 | self.add_section(section) 119 | section.set_block(block, x, y % 16, z) 120 | 121 | def set_biome(self, biome: Biome, x: int, z: int): 122 | """ 123 | Sets biome at given coordinates 124 | 125 | Parameters 126 | ---------- 127 | int x, z 128 | In range of 0 to 15 129 | 130 | Raises 131 | ------ 132 | anvil.OutOfBoundCoordidnates 133 | If X or Z are not in the proper range 134 | 135 | """ 136 | if x not in range(16): 137 | raise OutOfBoundsCoordinates(f'X ({x!r}) must be in range of 0 to 15') 138 | if z not in range(16): 139 | raise OutOfBoundsCoordinates(f'Z ({z!r}) must be in range of 0 to 15') 140 | 141 | index = z * 16 + x 142 | self.biomes[index] = biome 143 | 144 | def save(self) -> nbt.NBTFile: 145 | """ 146 | Saves the chunk data to a :class:`NBTFile` 147 | 148 | Notes 149 | ----- 150 | Does not contain most data a regular chunk would have, 151 | but minecraft stills accept it. 152 | """ 153 | root = nbt.NBTFile() 154 | root.tags.append(nbt.TAG_Int(name='DataVersion',value=self.version)) 155 | level = nbt.TAG_Compound() 156 | # Needs to be in a separate line because it just gets 157 | # ignored if you pass it as a kwarg in the constructor 158 | level.name = 'Level' 159 | level.tags.extend([ 160 | nbt.TAG_List(name='Entities', type=nbt.TAG_Compound), 161 | nbt.TAG_List(name='TileEntities', type=nbt.TAG_Compound), 162 | nbt.TAG_List(name='LiquidTicks', type=nbt.TAG_Compound), 163 | nbt.TAG_Int(name='xPos', value=self.x), 164 | nbt.TAG_Int(name='zPos', value=self.z), 165 | nbt.TAG_Long(name='LastUpdate', value=0), 166 | nbt.TAG_Long(name='InhabitedTime', value=0), 167 | nbt.TAG_Byte(name='isLightOn', value=1), 168 | nbt.TAG_String(name='Status', value='full') 169 | ]) 170 | sections = nbt.TAG_List(name='Sections', type=nbt.TAG_Compound) 171 | biomes = nbt.TAG_Int_Array(name='Biomes') 172 | 173 | biomes.value = [_get_legacy_biome_id(biome) for biome in self.biomes] 174 | for s in self.sections: 175 | if s: 176 | p = s.palette() 177 | # Minecraft does not save sections that are just air 178 | # So we can just skip them 179 | if len(p) == 1 and p[0].name() == 'minecraft:air': 180 | continue 181 | sections.tags.append(s.save()) 182 | level.tags.append(sections) 183 | level.tags.append(biomes) 184 | root.tags.append(level) 185 | return root 186 | -------------------------------------------------------------------------------- /anvil/empty_region.py: -------------------------------------------------------------------------------- 1 | from typing import Union, List, BinaryIO 2 | from .empty_chunk import EmptyChunk 3 | from .chunk import Chunk 4 | from .empty_section import EmptySection 5 | from .block import Block 6 | from .biome import Biome 7 | from .errors import OutOfBoundsCoordinates 8 | from .versions import VERSION_21w43a 9 | from io import BytesIO 10 | from nbt import nbt 11 | import zlib 12 | import math 13 | 14 | def from_inclusive(a, b): 15 | """Returns a range from a to b, including both endpoints""" 16 | c = int(b > a)*2-1 17 | return range(a, b+c, c) 18 | 19 | class EmptyRegion: 20 | """ 21 | Used for making own regions 22 | 23 | Attributes 24 | ---------- 25 | chunks: List[:class:`anvil.EmptyChunk`] 26 | List of chunks in this region 27 | x: :class:`int` 28 | z: :class:`int` 29 | """ 30 | __slots__ = ('chunks', 'x', 'z') 31 | def __init__(self, x: int, z: int): 32 | # Create a 1d list for the 32x32 chunks 33 | self.chunks: List[EmptyChunk] = [None] * 1024 34 | self.x = x 35 | self.z = z 36 | 37 | def inside(self, x: int, y: int, z: int, chunk: bool=False) -> bool: 38 | """ 39 | Returns if the given coordinates are inside this region 40 | 41 | Parameters 42 | ---------- 43 | int x, y, z 44 | Coordinates 45 | chunk 46 | Whether coordinates are global or chunk coordinates 47 | """ 48 | factor = 32 if chunk else 512 49 | rx = x // factor 50 | rz = z // factor 51 | return not (rx != self.x or rz != self.z or y not in range(256)) 52 | 53 | def get_chunk(self, x: int, z: int) -> EmptyChunk: 54 | """ 55 | Returns the chunk at given chunk coordinates 56 | 57 | Parameters 58 | ---------- 59 | int x, z 60 | Chunk's coordinates 61 | 62 | Raises 63 | ------ 64 | anvil.OutOfBoundCoordidnates 65 | If the chunk (x, z) is not inside this region 66 | 67 | :rtype: :class:`anvil.EmptyChunk` 68 | """ 69 | if not self.inside(x, 0, z, chunk=True): 70 | raise OutOfBoundsCoordinates(f'Chunk ({x}, {z}) is not inside this region') 71 | return self.chunks[z % 32 * 32 + x % 32] 72 | 73 | def add_chunk(self, chunk: EmptyChunk): 74 | """ 75 | Adds given chunk to this region. 76 | Will overwrite if a chunk already exists in this location 77 | 78 | Parameters 79 | ---------- 80 | chunk: :class:`EmptyChunk` 81 | 82 | Raises 83 | ------ 84 | anvil.OutOfBoundCoordidnates 85 | If the chunk (x, z) is not inside this region 86 | """ 87 | if not self.inside(chunk.x, 0, chunk.z, chunk=True): 88 | raise OutOfBoundsCoordinates(f'Chunk ({chunk.x}, {chunk.z}) is not inside this region') 89 | self.chunks[chunk.z % 32 * 32 + chunk.x % 32] = chunk 90 | 91 | def add_section(self, section: EmptySection, x: int, z: int, replace: bool=True): 92 | """ 93 | Adds section to chunk at (x, z). 94 | Same as ``EmptyChunk.add_section(section)`` 95 | 96 | Parameters 97 | ---------- 98 | section: :class:`EmptySection` 99 | Section to add 100 | int x, z 101 | Chunk's coordinate 102 | replace 103 | Whether to replace section if it already exists in the chunk 104 | 105 | Raises 106 | ------ 107 | anvil.OutOfBoundsCoordinates 108 | If the chunk (x, z) is not inside this region 109 | """ 110 | if not self.inside(x, 0, z, chunk=True): 111 | raise OutOfBoundsCoordinates(f'Chunk ({x}, {z}) is not inside this region') 112 | chunk = self.chunks[z % 32 * 32 + x % 32] 113 | if chunk is None: 114 | chunk = EmptyChunk(x, z) 115 | self.add_chunk(chunk) 116 | chunk.add_section(section, replace) 117 | 118 | def set_block(self, block: Block, x: int, y: int, z: int): 119 | """ 120 | Sets block at given coordinates. 121 | New chunk is made if it doesn't exist. 122 | 123 | Parameters 124 | ---------- 125 | block: :class:`Block` 126 | Block to place 127 | int x, y, z 128 | Coordinates 129 | 130 | Raises 131 | ------ 132 | anvil.OutOfBoundsCoordinates 133 | If the block (x, y, z) is not inside this region 134 | """ 135 | if not self.inside(x, y, z): 136 | raise OutOfBoundsCoordinates(f'Block ({x}, {y}, {z}) is not inside this region') 137 | cx = x // 16 138 | cz = z // 16 139 | chunk = self.get_chunk(cx, cz) 140 | if chunk is None: 141 | chunk = EmptyChunk(cx, cz) 142 | self.add_chunk(chunk) 143 | chunk.set_block(block, x % 16, y, z % 16) 144 | 145 | def set_biome(self, biome: Biome, x: int, z: int): 146 | """ 147 | Sets biome at given coordinates. 148 | New chunk is made if it doesn't exist. 149 | 150 | Parameters 151 | ---------- 152 | biome: :class:`Biome` 153 | Biome to place 154 | int x, z 155 | Coordinates 156 | 157 | Raises 158 | ------ 159 | anvil.OutOfBoundsCoordinates 160 | If the biome (x, z) is not inside this region 161 | """ 162 | if not self.inside(x, 0, z): 163 | raise OutOfBoundsCoordinates(f'Biome ({x}, {z}) is not inside this region') 164 | cx = x // 16 165 | cz = z // 16 166 | chunk = self.get_chunk(cx, cz) 167 | if chunk is None: 168 | chunk = EmptyChunk(cx, cz) 169 | self.add_chunk(chunk) 170 | chunk.set_biome(biome, x % 16, z % 16) 171 | 172 | def set_if_inside(self, block: Block, x: int, y: int, z: int): 173 | """ 174 | Helper function that only sets 175 | the block if ``self.inside(x, y, z)`` is true 176 | 177 | Parameters 178 | ---------- 179 | block: :class:`Block` 180 | Block to place 181 | int x, y, z 182 | Coordinates 183 | """ 184 | if self.inside(x, y, z): 185 | self.set_block(block, x, y, z) 186 | 187 | def set_biome_if_inside(self, biome: Biome, x: int, z: int): 188 | """ 189 | Helper function that only sets 190 | the biome if ``self.inside(x, 0, z)`` is true 191 | 192 | Parameters 193 | ---------- 194 | biome: :class:`Biome` 195 | Biome to place 196 | int x, z 197 | Coordinates 198 | """ 199 | if self.inside(x, 0, z): 200 | self.set_biome(biome, x, z) 201 | 202 | def fill(self, block: Block, x1: int, y1: int, z1: int, x2: int, y2: int, z2: int, ignore_outside: bool=False): 203 | """ 204 | Fills in blocks from 205 | ``(x1, y1, z1)`` to ``(x2, y2, z2)`` 206 | in a rectangle. 207 | 208 | Parameters 209 | ---------- 210 | block: :class:`Block` 211 | int x1, y1, z1 212 | Coordinates 213 | int x2, y2, z2 214 | Coordinates 215 | ignore_outside 216 | Whether to ignore if coordinates are outside the region 217 | 218 | Raises 219 | ------ 220 | anvil.OutOfBoundsCoordinates 221 | If any of the coordinates are outside the region 222 | """ 223 | if not ignore_outside: 224 | if not self.inside(x1, y1, z1): 225 | raise OutOfBoundsCoordinates(f'First coords ({x1}, {y1}, {z1}) is not inside this region') 226 | if not self.inside(x2, y2, z2): 227 | raise OutOfBoundsCoordinates(f'Second coords ({x}, {y}, {z}) is not inside this region') 228 | 229 | for y in from_inclusive(y1, y2): 230 | for z in from_inclusive(z1, z2): 231 | for x in from_inclusive(x1, x2): 232 | if ignore_outside: 233 | self.set_if_inside(block, x, y, z) 234 | else: 235 | self.set_block(block, x, y, z) 236 | 237 | def fill_biome(self, biome: Biome, x1: int, z1: int, x2: int, z2: int, ignore_outside: bool=False): 238 | """ 239 | Fills in biomes from 240 | ``(x1, z1)`` to ``(x2, z2)`` 241 | in a rectangle. 242 | 243 | Parameters 244 | ---------- 245 | biome: :class:`Biome` 246 | int x1, z1 247 | Coordinates 248 | int x2, z2 249 | Coordinates 250 | ignore_outside 251 | Whether to ignore if coordinates are outside the region 252 | 253 | Raises 254 | ------ 255 | anvil.OutOfBoundsCoordinates 256 | If any of the coordinates are outside the region 257 | """ 258 | if not ignore_outside: 259 | if not self.inside(x1, 0, z1): 260 | raise OutOfBoundsCoordinates(f'First coords ({x1}, {z1}) is not inside this region') 261 | if not self.inside(x2, 0, z2): 262 | raise OutOfBoundsCoordinates(f'Second coords ({x2}, {z2}) is not inside this region') 263 | 264 | for z in from_inclusive(z1, z2): 265 | for x in from_inclusive(x1, x2): 266 | if ignore_outside: 267 | self.set_biome_if_inside(biome, x, z) 268 | else: 269 | self.set_biome(biome, x, z) 270 | 271 | def save(self, file: Union[str, BinaryIO]=None) -> bytes: 272 | """ 273 | Returns the region as bytes with 274 | the anvil file format structure, 275 | aka the final ``.mca`` file. 276 | 277 | Parameters 278 | ---------- 279 | file 280 | Either a path or a file object, if given region 281 | will be saved there. 282 | """ 283 | # Store all the chunks data as zlib compressed nbt data 284 | chunks_data = [] 285 | for chunk in self.chunks: 286 | if chunk is None: 287 | chunks_data.append(None) 288 | continue 289 | chunk_data = BytesIO() 290 | if isinstance(chunk, Chunk): 291 | nbt_data = nbt.NBTFile() 292 | nbt_data.tags.append(nbt.TAG_Int(name='DataVersion', value=chunk.version)) 293 | 294 | if chunk.version >= VERSION_21w43a: 295 | for tag in chunk.data.tags: 296 | nbt_data.tags.append(tag) 297 | else: 298 | nbt_data.tags.append(chunk.data) 299 | else: 300 | nbt_data = chunk.save() 301 | nbt_data.write_file(buffer=chunk_data) 302 | chunk_data.seek(0) 303 | chunk_data = zlib.compress(chunk_data.read()) 304 | chunks_data.append(chunk_data) 305 | 306 | # This is what is added after the location and timestamp header 307 | chunks_bytes = bytes() 308 | offsets = [] 309 | for chunk in chunks_data: 310 | if chunk is None: 311 | offsets.append(None) 312 | continue 313 | # 4 bytes are for length, b'\x02' is the compression type which is 2 since its using zlib 314 | to_add = (len(chunk)+1).to_bytes(4, 'big') + b'\x02' + chunk 315 | 316 | # offset in 4KiB sectors 317 | sector_offset = len(chunks_bytes) // 4096 318 | sector_count = math.ceil(len(to_add) / 4096) 319 | offsets.append((sector_offset, sector_count)) 320 | 321 | # Padding to be a multiple of 4KiB long 322 | to_add += bytes(4096 - (len(to_add) % 4096)) 323 | chunks_bytes += to_add 324 | 325 | locations_header = bytes() 326 | for offset in offsets: 327 | # None means the chunk is not an actual chunk in the region 328 | # and will be 4 null bytes, which represents non-generated chunks to minecraft 329 | if offset is None: 330 | locations_header += bytes(4) 331 | else: 332 | # offset is (sector offset, sector count) 333 | locations_header += (offset[0] + 2).to_bytes(3, 'big') + offset[1].to_bytes(1, 'big') 334 | 335 | # Set them all as 0 336 | timestamps_header = bytes(4096) 337 | 338 | final = locations_header + timestamps_header + chunks_bytes 339 | 340 | # Pad file to be a multiple of 4KiB in size 341 | # as Minecraft only accepts region files that are like that 342 | final += bytes(4096 - (len(final) % 4096)) 343 | assert len(final) % 4096 == 0 # just in case 344 | 345 | # Save to a file if it was given 346 | if file: 347 | if isinstance(file, str): 348 | with open(file, 'wb') as f: 349 | f.write(final) 350 | else: 351 | file.write(final) 352 | return final 353 | -------------------------------------------------------------------------------- /anvil/empty_section.py: -------------------------------------------------------------------------------- 1 | from typing import List, Tuple 2 | from . import Block 3 | from .errors import OutOfBoundsCoordinates 4 | from nbt import nbt 5 | from struct import Struct 6 | import array 7 | 8 | # dirty mixin to change q to Q 9 | def _update_fmt(self, length): 10 | self.fmt = Struct(f'>{length}Q') 11 | nbt.TAG_Long_Array.update_fmt = _update_fmt 12 | 13 | def bin_append(a, b, length=None): 14 | length = length or b.bit_length() 15 | return (a << length) | b 16 | 17 | class EmptySection: 18 | """ 19 | Used for making own sections. 20 | 21 | This is where the blocks are actually stored, in a 16³ sized array. 22 | To save up some space, ``None`` is used instead of the air block object, 23 | and will be replaced with ``self.air`` when needed 24 | 25 | Attributes 26 | ---------- 27 | y: :class:`int` 28 | Section's Y index 29 | blocks: List[:class:`Block`] 30 | 1D list of blocks 31 | air: :class:`Block` 32 | An air block 33 | """ 34 | __slots__ = ('y', 'blocks', 'air') 35 | def __init__(self, y: int): 36 | self.y = y 37 | # None is the same as an air block 38 | self.blocks: List[Block] = [None] * 4096 39 | # Block that will be used when None 40 | self.air = Block('minecraft', 'air') 41 | 42 | @staticmethod 43 | def inside(x: int, y: int, z: int) -> bool: 44 | """ 45 | Check if X Y and Z are in range of 0-15 46 | 47 | Parameters 48 | ---------- 49 | int x, y, z 50 | Coordinates 51 | """ 52 | return x in range(16) and y in range(16) and z in range(16) 53 | 54 | def set_block(self, block: Block, x: int, y: int, z: int): 55 | """ 56 | Sets the block at given coordinates 57 | 58 | Parameters 59 | ---------- 60 | block 61 | Block to set 62 | int x, y, z 63 | Coordinates 64 | 65 | Raises 66 | ------ 67 | anvil.OutOfBoundsCoordinates 68 | If coordinates are not in range of 0-15 69 | """ 70 | if not self.inside(x, y, z): 71 | raise OutOfBoundsCoordinates('X Y and Z must be in range of 0-15') 72 | index = y * 256 + z * 16 + x 73 | self.blocks[index] = block 74 | 75 | def get_block(self, x: int, y: int, z: int) -> Block: 76 | """ 77 | Gets the block at given coordinates. 78 | 79 | Parameters 80 | ---------- 81 | int x, y, z 82 | Coordinates 83 | 84 | Raises 85 | ------ 86 | anvil.OutOfBoundsCoordinates 87 | If coordinates are not in range of 0-15 88 | """ 89 | if not self.inside(x, y, z): 90 | raise OutOfBoundsCoordinates('X Y and Z must be in range of 0-15') 91 | index = y * 256 + z * 16 + x 92 | return self.blocks[index] or self.air 93 | 94 | def palette(self) -> Tuple[Block]: 95 | """ 96 | Generates and returns a tuple of all the different blocks in the section 97 | The order can change as it uses sets, but should be fine when saving since 98 | it's only called once. 99 | """ 100 | palette = set(self.blocks) 101 | if None in palette: 102 | palette.remove(None) 103 | palette.add(self.air) 104 | return tuple(palette) 105 | 106 | def blockstates(self, palette: Tuple[Block]=None) -> array.array: 107 | """ 108 | Returns a list of each block's index in the palette. 109 | 110 | This is used in the BlockStates tag of the section. 111 | 112 | Parameters 113 | ---------- 114 | palette 115 | Section's palette. If not given will generate one. 116 | """ 117 | palette = palette or self.palette() 118 | bits = max((len(palette) - 1).bit_length(), 4) 119 | states = array.array('Q') 120 | current = 0 121 | current_len = 0 122 | for block in self.blocks: 123 | if block is None: 124 | index = palette.index(self.air) 125 | else: 126 | index = palette.index(block) 127 | # If it's more than 64 bits then add to list and start over 128 | # with the remaining bits from last one 129 | if current_len + bits > 64: 130 | leftover = 64 - current_len 131 | states.append(bin_append(index & ((1 << leftover) - 1), current, length=current_len)) 132 | current = index >> leftover 133 | current_len = bits - leftover 134 | else: 135 | current = bin_append(index, current, length=current_len) 136 | current_len += bits 137 | states.append(current) 138 | return states 139 | 140 | def save(self) -> nbt.TAG_Compound: 141 | """ 142 | Saves the section to a TAG_Compound and is used inside the chunk tag 143 | This is missing the SkyLight tag, but minecraft still accepts it anyway 144 | """ 145 | root = nbt.TAG_Compound() 146 | root.tags.append(nbt.TAG_Byte(name='Y', value=self.y)) 147 | 148 | palette = self.palette() 149 | nbt_pal = nbt.TAG_List(name='Palette', type=nbt.TAG_Compound) 150 | for block in palette: 151 | tag = nbt.TAG_Compound() 152 | tag.tags.append(nbt.TAG_String(name='Name', value=block.name())) 153 | if block.properties: 154 | properties = nbt.TAG_Compound() 155 | properties.name = 'Properties' 156 | for key, value in block.properties.items(): 157 | if isinstance(value, str): 158 | properties.tags.append(nbt.TAG_String(name=key, value=value)) 159 | elif isinstance(value, bool): 160 | # booleans are a string saved as either 'true' or 'false' 161 | properties.tags.append(nbt.TAG_String(name=key, value=str(value).lower())) 162 | elif isinstance(value, int): 163 | # ints also seem to be saved as a string 164 | properties.tags.append(nbt.TAG_String(name=key, value=str(value))) 165 | else: 166 | # assume its a nbt tag and just append it 167 | properties.tags.append(value) 168 | tag.tags.append(properties) 169 | nbt_pal.tags.append(tag) 170 | root.tags.append(nbt_pal) 171 | 172 | states = self.blockstates(palette=palette) 173 | bstates = nbt.TAG_Long_Array(name='BlockStates') 174 | bstates.value = states 175 | root.tags.append(bstates) 176 | 177 | return root 178 | -------------------------------------------------------------------------------- /anvil/errors.py: -------------------------------------------------------------------------------- 1 | class OutOfBoundsCoordinates(ValueError): 2 | """Exception used for when coordinates are out of bounds""" 3 | 4 | class ChunkNotFound(Exception): 5 | """Exception used for when a chunk was not found""" 6 | 7 | class EmptySectionAlreadyExists(Exception): 8 | """ 9 | Exception used for when trying to add an `EmptySection` to an `EmptyChunk` 10 | and the chunk already has a section with the same Y 11 | """ 12 | 13 | class GZipChunkData(Exception): 14 | """Exception used when trying to get chunk data compressed in gzip""" -------------------------------------------------------------------------------- /anvil/legacy.py: -------------------------------------------------------------------------------- 1 | import json 2 | import os 3 | 4 | with open(os.path.join(os.path.dirname(__file__), 'legacy_blocks.json'), 'r') as file: 5 | LEGACY_ID_MAP = json.load(file) 6 | 7 | with open(os.path.join(os.path.dirname(__file__), 'legacy_biomes.json'), 'r') as file: 8 | LEGACY_BIOMES_ID_MAP = {int(k):v for k, v in json.load(file).items()} -------------------------------------------------------------------------------- /anvil/legacy_biomes.json: -------------------------------------------------------------------------------- 1 | { 2 | "0": "ocean", 3 | "4": "forest", 4 | "7": "river", 5 | "10": "frozen_ocean", 6 | "11": "frozen_river", 7 | "16": "beach", 8 | "24": "deep_ocean", 9 | "25": "stone_shore", 10 | "26": "snowy_beach", 11 | "44": "warm_ocean", 12 | "45": "lukewarm_ocean", 13 | "46": "cold_ocean", 14 | "47": "deep_warm_ocean", 15 | "48": "deep_lukewarm_ocean", 16 | "49": "deep_cold_ocean", 17 | "50": "deep_frozen_ocean", 18 | "18": "wooded_hills", 19 | "132": "flower_forest", 20 | "27": "birch_forest", 21 | "28": "birch_forest_hills", 22 | "155": "tall_birch_forest", 23 | "156": "tall_birch_hills", 24 | "29": "dark_forest", 25 | "157": "dark_forest_hills", 26 | "21": "jungle", 27 | "22": "jungle_hills", 28 | "149": "modified_jungle", 29 | "23": "jungle_edge", 30 | "151": "modified_jungle_edge", 31 | "168": "bamboo_jungle", 32 | "169": "bamboo_jungle_hills", 33 | "5": "taiga", 34 | "19": "taiga_hills", 35 | "133": "taiga_mountains", 36 | "30": "snowy_taiga", 37 | "31": "snowy_taiga_hills", 38 | "158": "snowy_taiga_mountains", 39 | "32": "giant_tree_taiga", 40 | "33": "giant_tree_taiga_hills", 41 | "160": "giant_spruce_taiga", 42 | "161": "giant_spruce_taiga_hills", 43 | "14": "mushroom_fields", 44 | "15": "mushroom_field_shore", 45 | "6": "swamp", 46 | "134": "swamp_hills", 47 | "35": "savanna", 48 | "36": "savanna_plateau", 49 | "163": "shattered_savanna", 50 | "164": "shattered_savanna_plateau", 51 | "1": "plains", 52 | "129": "sunflower_plains", 53 | "2": "desert", 54 | "17": "desert_hills", 55 | "130": "desert_lakes", 56 | "12": "snowy_tundra", 57 | "13": "snowy_mountains", 58 | "140": "ice_spikes", 59 | "3": "mountains", 60 | "34": "wooded_mountains", 61 | "131": "gravelly_mountains", 62 | "162": "modified_gravelly_mountains", 63 | "20": "mountain_edge", 64 | "37": "badlands", 65 | "39": "badlands_plateau", 66 | "167": "modified_badlands_plateau", 67 | "38": "wooded_badlands_plateau", 68 | "166": "modified_wooded_badlands_plateau", 69 | "165": "eroded_badlands", 70 | "8": "nether", 71 | "9": "the_end", 72 | "40": "small_end_islands", 73 | "41": "end_midlands", 74 | "42": "end_highlands", 75 | "43": "end_barrens", 76 | "170": "soul_sand_valley", 77 | "171": "crimson_forest", 78 | "172": "warped_forest", 79 | "127": "the_void", 80 | "173": "basalt_deltas" 81 | } -------------------------------------------------------------------------------- /anvil/legacy_blocks.json: -------------------------------------------------------------------------------- 1 | { 2 | "0:0": ["air", null], 3 | "1:0": ["stone", null], 4 | "1:1": ["granite", null], 5 | "1:2": ["polished_granite", null], 6 | "1:3": ["diorite", null], 7 | "1:4": ["polished_diorite", null], 8 | "1:5": ["andesite", null], 9 | "1:6": ["polished_andesite", null], 10 | "2:0": ["grass_block", null], 11 | "3:0": ["dirt", null], 12 | "3:1": ["coarse_dirt", null], 13 | "3:2": ["podzol", null], 14 | "4:0": ["cobblestone", null], 15 | "5:0": ["oak_planks", null], 16 | "5:1": ["spruce_planks", null], 17 | "5:2": ["birch_planks", null], 18 | "5:3": ["jungle_planks", null], 19 | "5:4": ["acacia_planks", null], 20 | "5:5": ["dark_oak_planks", null], 21 | "6:0": ["oak_sapling", null], 22 | "6:1": ["spruce_sapling", null], 23 | "6:2": ["birch_sapling", null], 24 | "6:3": ["jungle_sapling", null], 25 | "6:4": ["acacia_sapling", null], 26 | "6:5": ["dark_oak_sapling", null], 27 | "7:0": ["bedrock", null], 28 | 29 | "8:0": ["flowing_water", {"level": 0, "falling": false}], 30 | "8:1": ["flowing_water", {"level": 1, "falling": false}], 31 | "8:2": ["flowing_water", {"level": 2, "falling": false}], 32 | "8:3": ["flowing_water", {"level": 3, "falling": false}], 33 | "8:4": ["flowing_water", {"level": 4, "falling": false}], 34 | "8:5": ["flowing_water", {"level": 5, "falling": false}], 35 | "8:6": ["flowing_water", {"level": 6, "falling": false}], 36 | "8:7": ["flowing_water", {"level": 7, "falling": false}], 37 | "8:8": ["flowing_water", {"level": 0, "falling": true}], 38 | "8:9": ["flowing_water", {"level": 1, "falling": true}], 39 | "8:10": ["flowing_water", {"level": 2, "falling": true}], 40 | "8:11": ["flowing_water", {"level": 3, "falling": true}], 41 | "8:12": ["flowing_water", {"level": 4, "falling": true}], 42 | "8:13": ["flowing_water", {"level": 5, "falling": true}], 43 | "8:14": ["flowing_water", {"level": 6, "falling": true}], 44 | "8:15": ["flowing_water", {"level": 7, "falling": true}], 45 | 46 | "9:0": ["water", {"level": 0}], 47 | "9:1": ["water", {"level": 1}], 48 | "9:2": ["water", {"level": 2}], 49 | "9:3": ["water", {"level": 3}], 50 | "9:4": ["water", {"level": 4}], 51 | "9:5": ["water", {"level": 5}], 52 | "9:6": ["water", {"level": 6}], 53 | "9:7": ["water", {"level": 7}], 54 | "9:8": ["water", {"level": 8}], 55 | "9:9": ["water", {"level": 9}], 56 | "9:10": ["water", {"level": 10}], 57 | "9:11": ["water", {"level": 11}], 58 | "9:12": ["water", {"level": 12}], 59 | "9:13": ["water", {"level": 13}], 60 | "9:14": ["water", {"level": 14}], 61 | "9:15": ["water", {"level": 15}], 62 | 63 | "10:0": ["flowing_lava", {"level": 0, "falling": false}], 64 | "10:1": ["flowing_lava", {"level": 1, "falling": false}], 65 | "10:2": ["flowing_lava", {"level": 2, "falling": false}], 66 | "10:3": ["flowing_lava", {"level": 3, "falling": false}], 67 | "10:4": ["flowing_lava", {"level": 4, "falling": false}], 68 | "10:5": ["flowing_lava", {"level": 5, "falling": false}], 69 | "10:6": ["flowing_lava", {"level": 6, "falling": false}], 70 | "10:7": ["flowing_lava", {"level": 7, "falling": false}], 71 | "10:8": ["flowing_lava", {"level": 0, "falling": true}], 72 | "10:9": ["flowing_lava", {"level": 1, "falling": true}], 73 | "10:10": ["flowing_lava", {"level": 2, "falling": true}], 74 | "10:11": ["flowing_lava", {"level": 3, "falling": true}], 75 | "10:12": ["flowing_lava", {"level": 4, "falling": true}], 76 | "10:13": ["flowing_lava", {"level": 5, "falling": true}], 77 | "10:14": ["flowing_lava", {"level": 6, "falling": true}], 78 | "10:15": ["flowing_lava", {"level": 7, "falling": true}], 79 | 80 | "11:0": ["lava", {"level": 0}], 81 | "11:1": ["lava", {"level": 1}], 82 | "11:2": ["lava", {"level": 2}], 83 | "11:3": ["lava", {"level": 3}], 84 | "11:4": ["lava", {"level": 4}], 85 | "11:5": ["lava", {"level": 5}], 86 | "11:6": ["lava", {"level": 6}], 87 | "11:7": ["lava", {"level": 7}], 88 | "11:8": ["lava", {"level": 8}], 89 | "11:9": ["lava", {"level": 9}], 90 | "11:10": ["lava", {"level": 10}], 91 | "11:11": ["lava", {"level": 11}], 92 | "11:12": ["lava", {"level": 12}], 93 | "11:13": ["lava", {"level": 13}], 94 | "11:14": ["lava", {"level": 14}], 95 | "11:15": ["lava", {"level": 15}], 96 | 97 | "12:0": ["sand", null], 98 | "12:1": ["red_sand", null], 99 | "13:0": ["gravel", null], 100 | "14:0": ["gold_ore", null], 101 | "15:0": ["iron_ore", null], 102 | "16:0": ["coal_ore", null], 103 | 104 | "17:0": ["oak_log", {"axis": "y"}], 105 | "17:1": ["spruce_log", {"axis": "y"}], 106 | "17:2": ["birch_log", {"axis": "y"}], 107 | "17:3": ["jungle_log", {"axis": "y"}], 108 | "17:4": ["oak_log", {"axis": "x"}], 109 | "17:5": ["spruce_log", {"axis": "x"}], 110 | "17:6": ["birch_log", {"axis": "x"}], 111 | "17:7": ["jungle_log", {"axis": "x"}], 112 | "17:8": ["oak_log", {"axis": "z"}], 113 | "17:9": ["spruce_log", {"axis": "z"}], 114 | "17:10": ["birch_log", {"axis": "z"}], 115 | "17:11": ["jungle_log", {"axis": "z"}], 116 | "17:12": ["oak_log", null], 117 | "17:13": ["spruce_log", null], 118 | "17:14": ["birch_log", null], 119 | "17:15": ["jungle_log", null], 120 | 121 | "18:0": ["oak_leaves", {"persistent": false}], 122 | "18:1": ["spruce_leaves", {"persistent": false}], 123 | "18:2": ["birch_leaves", {"persistent": false}], 124 | "18:3": ["jungle_leaves", {"persistent": false}], 125 | "18:4": ["oak_leaves", {"persistent": true}], 126 | "18:5": ["spruce_leaves", {"persistent": true}], 127 | "18:6": ["birch_leaves", {"persistent": true}], 128 | "18:7": ["jungle_leaves", {"persistent": true}], 129 | "18:8": ["oak_leaves", {"persistent": false}], 130 | "18:9": ["spruce_leaves", {"persistent": false}], 131 | "18:10": ["birch_leaves", {"persistent": false}], 132 | "18:11": ["jungle_leaves", {"persistent": false}], 133 | "18:12": ["oak_leaves", {"persistent": true}], 134 | "18:13": ["spruce_leaves", {"persistent": true}], 135 | "18:14": ["birch_leaves", {"persistent": true}], 136 | "18:15": ["jungle_leaves", {"persistent": true}], 137 | 138 | "19:0": ["sponge", null], 139 | "19:1": ["wet_sponge", null], 140 | "20:0": ["glass", null], 141 | "21:0": ["lapis_ore", null], 142 | "22:0": ["lapis_block", null], 143 | 144 | "23:0": ["dispenser", null], 145 | "23:0": ["dispenser", {"facing": "down", "triggered": false}], 146 | "23:1": ["dispenser", {"facing": "up", "triggered": false}], 147 | "23:2": ["dispenser", {"facing": "north", "triggered": false}], 148 | "23:3": ["dispenser", {"facing": "south", "triggered": false}], 149 | "23:4": ["dispenser", {"facing": "west", "triggered": false}], 150 | "23:5": ["dispenser", {"facing": "east", "triggered": false}], 151 | "23:8": ["dispenser", {"facing": "down", "triggered": true}], 152 | "23:9": ["dispenser", {"facing": "up", "triggered": true}], 153 | "23:10": ["dispenser", {"facing": "north", "triggered": true}], 154 | "23:11": ["dispenser", {"facing": "south", "triggered": true}], 155 | "23:12": ["dispenser", {"facing": "west", "triggered": true}], 156 | "23:13": ["dispenser", {"facing": "east", "triggered": true}], 157 | 158 | "24:0": ["sandstone", null], 159 | "24:1": ["chiseled_sandstone", null], 160 | "24:2": ["cut_sandstone", null], 161 | "25:0": ["note_block", null], 162 | 163 | "26:0": ["bed", {"facing": "south", "occupied": false, "part": "foot"}], 164 | "26:1": ["bed", {"facing": "west", "occupied": false, "part": "foot"}], 165 | "26:2": ["bed", {"facing": "north", "occupied": false, "part": "foot"}], 166 | "26:3": ["bed", {"facing": "east", "occupied": false, "part": "foot"}], 167 | "26:4": ["bed", {"facing": "south", "occupied": true, "part": "foot"}], 168 | "26:5": ["bed", {"facing": "west", "occupied": true, "part": "foot"}], 169 | "26:6": ["bed", {"facing": "north", "occupied": true, "part": "foot"}], 170 | "26:7": ["bed", {"facing": "east", "occupied": true, "part": "foot"}], 171 | "26:8": ["bed", {"facing": "south", "occupied": false, "part": "head"}], 172 | "26:9": ["bed", {"facing": "west", "occupied": false, "part": "head"}], 173 | "26:10": ["bed", {"facing": "north", "occupied": false, "part": "head"}], 174 | "26:11": ["bed", {"facing": "east", "occupied": false, "part": "head"}], 175 | "26:12": ["bed", {"facing": "south", "occupied": true, "part": "head"}], 176 | "26:13": ["bed", {"facing": "west", "occupied": true, "part": "head"}], 177 | "26:14": ["bed", {"facing": "north", "occupied": true, "part": "head"}], 178 | "26:15": ["bed", {"facing": "east", "occupied": true, "part": "head"}], 179 | 180 | "27:0": ["powered_rail", {"shape": "north_south", "powered": false}], 181 | "27:1": ["powered_rail", {"shape": "east_west", "powered": false}], 182 | "27:2": ["powered_rail", {"shape": "ascending_east", "powered": false}], 183 | "27:3": ["powered_rail", {"shape": "ascending_west", "powered": false}], 184 | "27:4": ["powered_rail", {"shape": "ascending_north", "powered": false}], 185 | "27:5": ["powered_rail", {"shape": "ascending_south", "powered": false}], 186 | "27:8": ["powered_rail", {"shape": "north_south", "powered": true}], 187 | "27:9": ["powered_rail", {"shape": "east_west", "powered": true}], 188 | "27:10": ["powered_rail", {"shape": "ascending_east", "powered": true}], 189 | "27:11": ["powered_rail", {"shape": "ascending_west", "powered": true}], 190 | "27:12": ["powered_rail", {"shape": "ascending_north", "powered": true}], 191 | "27:13": ["powered_rail", {"shape": "ascending_south", "powered": true}], 192 | 193 | "28:0": ["detector_rail", {"shape": "north_south", "powered": false}], 194 | "28:1": ["detector_rail", {"shape": "east_west", "powered": false}], 195 | "28:2": ["detector_rail", {"shape": "ascending_east", "powered": false}], 196 | "28:3": ["detector_rail", {"shape": "ascending_west", "powered": false}], 197 | "28:4": ["detector_rail", {"shape": "ascending_north", "powered": false}], 198 | "28:5": ["detector_rail", {"shape": "ascending_south", "powered": false}], 199 | "28:8": ["detector_rail", {"shape": "north_south", "powered": true}], 200 | "28:9": ["detector_rail", {"shape": "east_west", "powered": true}], 201 | "28:10": ["detector_rail", {"shape": "ascending_east", "powered": true}], 202 | "28:11": ["detector_rail", {"shape": "ascending_west", "powered": true}], 203 | "28:12": ["detector_rail", {"shape": "ascending_north", "powered": true}], 204 | "28:13": ["detector_rail", {"shape": "ascending_south", "powered": true}], 205 | 206 | "29:0": ["sticky_piston", {"facing": "down", "extended": false}], 207 | "29:1": ["sticky_piston", {"facing": "up", "extended": false}], 208 | "29:2": ["sticky_piston", {"facing": "north", "extended": false}], 209 | "29:3": ["sticky_piston", {"facing": "south", "extended": false}], 210 | "29:4": ["sticky_piston", {"facing": "west", "extended": false}], 211 | "29:5": ["sticky_piston", {"facing": "east", "extended": false}], 212 | "29:8": ["sticky_piston", {"facing": "down", "extended": true}], 213 | "29:9": ["sticky_piston", {"facing": "up", "extended": true}], 214 | "29:10": ["sticky_piston", {"facing": "north", "extended": true}], 215 | "29:11": ["sticky_piston", {"facing": "south", "extended": true}], 216 | "29:12": ["sticky_piston", {"facing": "west", "extended": true}], 217 | "29:13": ["sticky_piston", {"facing": "east", "extended": true}], 218 | 219 | "30:0": ["cobweb", null], 220 | "31:0": ["dead_shrub", null], 221 | "31:1": ["grass", null], 222 | "31:2": ["fern", null], 223 | "32:0": ["dead_bush", null], 224 | 225 | "33:0": ["piston", {"facing": "down", "extended": false}], 226 | "33:1": ["piston", {"facing": "up", "extended": false}], 227 | "33:2": ["piston", {"facing": "north", "extended": false}], 228 | "33:3": ["piston", {"facing": "south", "extended": false}], 229 | "33:4": ["piston", {"facing": "west", "extended": false}], 230 | "33:5": ["piston", {"facing": "east", "extended": false}], 231 | "33:8": ["piston", {"facing": "down", "extended": true}], 232 | "33:9": ["piston", {"facing": "up", "extended": true}], 233 | "33:10": ["piston", {"facing": "north", "extended": true}], 234 | "33:11": ["piston", {"facing": "south", "extended": true}], 235 | "33:12": ["piston", {"facing": "west", "extended": true}], 236 | "33:13": ["piston", {"facing": "east", "extended": true}], 237 | 238 | "34:0": ["piston_head", {"facing": "down", "type": "normal"}], 239 | "34:1": ["piston_head", {"facing": "up", "type": "normal"}], 240 | "34:2": ["piston_head", {"facing": "north", "type": "normal"}], 241 | "34:3": ["piston_head", {"facing": "south", "type": "normal"}], 242 | "34:4": ["piston_head", {"facing": "west", "type": "normal"}], 243 | "34:5": ["piston_head", {"facing": "east", "type": "normal"}], 244 | "34:8": ["piston_head", {"facing": "down", "type": "sticky"}], 245 | "34:9": ["piston_head", {"facing": "up", "type": "sticky"}], 246 | "34:10": ["piston_head", {"facing": "north", "type": "sticky"}], 247 | "34:11": ["piston_head", {"facing": "south", "type": "sticky"}], 248 | "34:12": ["piston_head", {"facing": "west", "type": "sticky"}], 249 | "34:13": ["piston_head", {"facing": "east", "type": "sticky"}], 250 | 251 | "35:0": ["white_wool", null], 252 | "35:1": ["orange_wool", null], 253 | "35:2": ["magenta_wool", null], 254 | "35:3": ["light_blue_wool", null], 255 | "35:4": ["yellow_wool", null], 256 | "35:5": ["lime_wool", null], 257 | "35:6": ["pink_wool", null], 258 | "35:7": ["gray_wool", null], 259 | "35:8": ["light_gray_wool", null], 260 | "35:9": ["cyan_wool", null], 261 | "35:10": ["purple_wool", null], 262 | "35:11": ["blue_wool", null], 263 | "35:12": ["brown_wool", null], 264 | "35:13": ["green_wool", null], 265 | "35:14": ["red_wool", null], 266 | "35:15": ["black_wool", null], 267 | "37:0": ["dandelion", null], 268 | "38:0": ["poppy", null], 269 | "38:1": ["blue_orchid", null], 270 | "38:2": ["allium", null], 271 | "38:3": ["azure_bluet", null], 272 | "38:4": ["red_tulip", null], 273 | "38:5": ["orange_tulip", null], 274 | "38:6": ["white_tulip", null], 275 | "38:7": ["pink_tulip", null], 276 | "38:8": ["oxeye_daisy", null], 277 | "39:0": ["brown_mushroom", null], 278 | "40:0": ["red_mushroom", null], 279 | "41:0": ["gold_block", null], 280 | "42:0": ["iron_block", null], 281 | 282 | "43:0": ["smooth_stone_slab", {"type": "double"}], 283 | "43:1": ["sandstone_slab", {"type": "double"}], 284 | "43:2": ["petrified_oak_slab", {"type": "double"}], 285 | "43:3": ["cobblestone_slab", {"type": "double"}], 286 | "43:4": ["brick_slab", {"type": "double"}], 287 | "43:5": ["stone_brick_slab", {"type": "double"}], 288 | "43:6": ["nether_brick_slab", {"type": "double"}], 289 | "43:7": ["quartz_slab", {"type": "double"}], 290 | "43:8": ["smooth_stone", null], 291 | "43:9": ["smooth_sandstone", null], 292 | "43:10": ["petrified_oak_slab", {"type": "double"}], 293 | "43:11": ["cobblestone_slab", {"type": "double"}], 294 | "43:12": ["brick_slab", {"type": "double"}], 295 | "43:13": ["stone_brick_slab", {"type": "double"}], 296 | "43:14": ["nether_brick_slab", {"type": "double"}], 297 | "43:15": ["smooth_quartz", null], 298 | 299 | "44:0": ["smooth_stone_slab", {"type": "bottom"}], 300 | "44:1": ["sandstone_slab", {"type": "bottom"}], 301 | "44:2": ["wooden_slab", {"type": "bottom"}], 302 | "44:3": ["cobblestone_slab", {"type": "bottom"}], 303 | "44:4": ["brick_slab", {"type": "bottom"}], 304 | "44:5": ["stone_brick_slab", {"type": "bottom"}], 305 | "44:6": ["nether_brick_slab", {"type": "bottom"}], 306 | "44:7": ["quartz_slab", {"type": "bottom"}], 307 | "44:8": ["smooth_stone_slab", {"type": "top"}], 308 | "44:9": ["sandstone_slab", {"type": "top"}], 309 | "44:10": ["wooden_slab", {"type": "top"}], 310 | "44:11": ["cobblestone_slab", {"type": "top"}], 311 | "44:12": ["brick_slab", {"type": "top"}], 312 | "44:13": ["stone_brick_slab", {"type": "top"}], 313 | "44:14": ["nether_brick_slab", {"type": "top"}], 314 | "44:15": ["quartz_slab", {"type": "top"}], 315 | 316 | "45:0": ["bricks", null], 317 | "46:0": ["tnt", null], 318 | "47:0": ["bookshelf", null], 319 | "48:0": ["mossy_cobblestone", null], 320 | "49:0": ["obsidian", null], 321 | 322 | "50:0": ["torch", null], 323 | "50:1": ["wall_torch", {"facing": "east"}], 324 | "50:2": ["wall_torch", {"facing": "west"}], 325 | "50:3": ["wall_torch", {"facing": "south"}], 326 | "50:4": ["wall_torch", {"facing": "north"}], 327 | "50:5": ["torch", null], 328 | 329 | "51:0": ["fire", null], 330 | "51:1": ["fire", null], 331 | "51:2": ["fire", null], 332 | "51:3": ["fire", null], 333 | "51:4": ["fire", null], 334 | "51:5": ["fire", null], 335 | "51:6": ["fire", null], 336 | "51:7": ["fire", null], 337 | "51:8": ["fire", null], 338 | "51:9": ["fire", null], 339 | "51:10": ["fire", null], 340 | "51:11": ["fire", null], 341 | "51:12": ["fire", null], 342 | "51:13": ["fire", null], 343 | "51:14": ["fire", null], 344 | "51:15": ["fire", null], 345 | 346 | "52:0": ["spawner", null], 347 | 348 | "53:0": ["oak_stairs", {"facing": "east", "half": "bottom"}], 349 | "53:1": ["oak_stairs", {"facing": "west", "half": "bottom"}], 350 | "53:2": ["oak_stairs", {"facing": "south", "half": "bottom"}], 351 | "53:3": ["oak_stairs", {"facing": "north", "half": "bottom"}], 352 | "53:4": ["oak_stairs", {"facing": "east", "half": "top"}], 353 | "53:5": ["oak_stairs", {"facing": "west", "half": "top"}], 354 | "53:6": ["oak_stairs", {"facing": "south", "half": "top"}], 355 | "53:7": ["oak_stairs", {"facing": "north", "half": "top"}], 356 | 357 | "54:0": ["chest", {"facing": "north"}], 358 | "54:1": ["chest", {"facing": "north"}], 359 | "54:2": ["chest", {"facing": "north"}], 360 | "54:3": ["chest", {"facing": "south"}], 361 | "54:4": ["chest", {"facing": "west"}], 362 | "54:5": ["chest", {"facing": "east"}], 363 | 364 | 365 | "55:0": ["redstone_wire", {"power": 0}], 366 | "55:1": ["redstone_wire", {"power": 1}], 367 | "55:2": ["redstone_wire", {"power": 2}], 368 | "55:3": ["redstone_wire", {"power": 3}], 369 | "55:4": ["redstone_wire", {"power": 4}], 370 | "55:5": ["redstone_wire", {"power": 5}], 371 | "55:6": ["redstone_wire", {"power": 6}], 372 | "55:7": ["redstone_wire", {"power": 7}], 373 | "55:8": ["redstone_wire", {"power": 8}], 374 | "55:9": ["redstone_wire", {"power": 9}], 375 | "55:10": ["redstone_wire", {"power": 10}], 376 | "55:11": ["redstone_wire", {"power": 11}], 377 | "55:12": ["redstone_wire", {"power": 12}], 378 | "55:13": ["redstone_wire", {"power": 13}], 379 | "55:14": ["redstone_wire", {"power": 14}], 380 | "55:15": ["redstone_wire", {"power": 15}], 381 | 382 | 383 | "56:0": ["diamond_ore", null], 384 | "57:0": ["diamond_block", null], 385 | "58:0": ["crafting_table", null], 386 | 387 | "59:0": ["wheat", {"age": 0}], 388 | "59:1": ["wheat", {"age": 1}], 389 | "59:2": ["wheat", {"age": 2}], 390 | "59:3": ["wheat", {"age": 3}], 391 | "59:4": ["wheat", {"age": 4}], 392 | "59:5": ["wheat", {"age": 5}], 393 | "59:6": ["wheat", {"age": 6}], 394 | "59:7": ["wheat", {"age": 7}], 395 | 396 | "60:0": ["farmland", {"moisture": 0}], 397 | "60:1": ["farmland", {"moisture": 1}], 398 | "60:2": ["farmland", {"moisture": 2}], 399 | "60:3": ["farmland", {"moisture": 3}], 400 | "60:4": ["farmland", {"moisture": 4}], 401 | "60:5": ["farmland", {"moisture": 5}], 402 | "60:6": ["farmland", {"moisture": 6}], 403 | "60:7": ["farmland", {"moisture": 7}], 404 | 405 | "61:0": ["furnace", {"lit": false, "facing": "north"}], 406 | "61:1": ["furnace", {"lit": false, "facing": "north"}], 407 | "61:2": ["furnace", {"lit": false, "facing": "north"}], 408 | "61:3": ["furnace", {"lit": false, "facing": "south"}], 409 | "61:4": ["furnace", {"lit": false, "facing": "west"}], 410 | "61:5": ["furnace", {"lit": false, "facing": "east"}], 411 | 412 | "62:0": ["furnace", {"lit": true, "facing": "north"}], 413 | "61:1": ["furnace", {"lit": false, "facing": "north"}], 414 | "62:2": ["furnace", {"lit": true, "facing": "north"}], 415 | "62:3": ["furnace", {"lit": true, "facing": "south"}], 416 | "62:4": ["furnace", {"lit": true, "facing": "west"}], 417 | "62:5": ["furnace", {"lit": true, "facing": "east"}], 418 | 419 | "63:0": ["oak_sign", {"rotation": 0}], 420 | "63:1": ["oak_sign", {"rotation": 1}], 421 | "63:2": ["oak_sign", {"rotation": 2}], 422 | "63:3": ["oak_sign", {"rotation": 3}], 423 | "63:4": ["oak_sign", {"rotation": 4}], 424 | "63:5": ["oak_sign", {"rotation": 5}], 425 | "63:6": ["oak_sign", {"rotation": 6}], 426 | "63:7": ["oak_sign", {"rotation": 7}], 427 | "63:8": ["oak_sign", {"rotation": 8}], 428 | "63:9": ["oak_sign", {"rotation": 9}], 429 | "63:10": ["oak_sign", {"rotation": 10}], 430 | "63:11": ["oak_sign", {"rotation": 11}], 431 | "63:12": ["oak_sign", {"rotation": 12}], 432 | "63:13": ["oak_sign", {"rotation": 13}], 433 | "63:14": ["oak_sign", {"rotation": 14}], 434 | "63:15": ["oak_sign", {"rotation": 15}], 435 | 436 | 437 | "64:0": ["oak_door", {"half": "lower", "facing": "east", "open": false}], 438 | "64:1": ["oak_door", {"half": "lower", "facing": "south", "open": false}], 439 | "64:2": ["oak_door", {"half": "lower", "facing": "west", "open": false}], 440 | "64:3": ["oak_door", {"half": "lower", "facing": "north", "open": false}], 441 | "64:4": ["oak_door", {"half": "lower", "facing": "east", "open": true}], 442 | "64:5": ["oak_door", {"half": "lower", "facing": "south", "open": true}], 443 | "64:6": ["oak_door", {"half": "lower", "facing": "west", "open": true}], 444 | "64:7": ["oak_door", {"half": "lower", "facing": "north", "open": true}], 445 | 446 | "64:8": ["oak_door", {"half": "upper", "hinge": "left", "powered": false}], 447 | "64:9": ["oak_door", {"half": "upper", "hinge": "right", "powered": false}], 448 | "64:10": ["oak_door", {"half": "upper", "hinge": "left", "powered": true}], 449 | "64:11": ["oak_door", {"half": "upper", "hinge": "right", "powered": true}], 450 | 451 | "65:0": ["ladder", {"facing": "north"}], 452 | "65:1": ["ladder", {"facing": "north"}], 453 | "65:2": ["ladder", {"facing": "north"}], 454 | "65:3": ["ladder", {"facing": "south"}], 455 | "65:4": ["ladder", {"facing": "west"}], 456 | "65:5": ["ladder", {"facing": "east"}], 457 | 458 | "66:0": ["rail", {"shape": "north_south"}], 459 | "66:1": ["rail", {"shape": "east_west"}], 460 | "66:2": ["rail", {"shape": "ascending_east"}], 461 | "66:3": ["rail", {"shape": "ascending_west"}], 462 | "66:4": ["rail", {"shape": "ascending_north"}], 463 | "66:5": ["rail", {"shape": "ascending_south"}], 464 | "66:6": ["rail", {"shape": "south_east"}], 465 | "66:7": ["rail", {"shape": "south_west"}], 466 | "66:8": ["rail", {"shape": "north_west"}], 467 | "66:9": ["rail", {"shape": "north_east"}], 468 | 469 | "67:0": ["cobblestone_stairs", {"facing": "east", "half": "bottom"}], 470 | "67:1": ["cobblestone_stairs", {"facing": "west", "half": "bottom"}], 471 | "67:2": ["cobblestone_stairs", {"facing": "south", "half": "bottom"}], 472 | "67:3": ["cobblestone_stairs", {"facing": "north", "half": "bottom"}], 473 | "67:4": ["cobblestone_stairs", {"facing": "east", "half": "top"}], 474 | "67:5": ["cobblestone_stairs", {"facing": "west", "half": "top"}], 475 | "67:6": ["cobblestone_stairs", {"facing": "south", "half": "top"}], 476 | "67:7": ["cobblestone_stairs", {"facing": "north", "half": "top"}], 477 | 478 | "68:0": ["oak_wall_sign", {"facing": "north"}], 479 | "68:1": ["oak_wall_sign", {"facing": "north"}], 480 | "68:2": ["oak_wall_sign", {"facing": "north"}], 481 | "68:3": ["oak_wall_sign", {"facing": "south"}], 482 | "68:4": ["oak_wall_sign", {"facing": "west"}], 483 | "68:5": ["oak_wall_sign", {"facing": "east"}], 484 | 485 | "69:0": ["lever", {"face": "ceiling", "facing": "west", "powered": false}], 486 | 487 | "69:1": ["lever", {"face": "wall", "facing": "east", "powered": false}], 488 | "69:2": ["lever", {"face": "wall", "facing": "west", "powered": false}], 489 | "69:3": ["lever", {"face": "wall", "facing": "south", "powered": false}], 490 | "69:4": ["lever", {"face": "wall", "facing": "north", "powered": false}], 491 | 492 | "69:5": ["lever", {"face": "floor", "facing": "north", "powered": false}], 493 | "69:6": ["lever", {"face": "floor", "facing": "west", "powered": false}], 494 | "69:7": ["lever", {"face": "ceiling", "facing": "north", "powered": false}], 495 | "69:8": ["lever", {"face": "ceiling", "facing": "west", "powered": true}], 496 | 497 | "69:9": ["lever", {"face": "wall", "facing": "east", "powered": true}], 498 | "69:10": ["lever", {"face": "wall", "facing": "west", "powered": true}], 499 | "69:11": ["lever", {"face": "wall", "facing": "south", "powered": true}], 500 | "69:12": ["lever", {"face": "wall", "facing": "north", "powered": true}], 501 | 502 | "69:13": ["lever", {"face": "floor", "facing": "north", "powered": true}], 503 | "69:14": ["lever", {"face": "floor", "facing": "west", "powered": true}], 504 | "69:15": ["lever", {"face": "ceiling", "facing": "north", "powered": true}], 505 | 506 | "70:0": ["stone_pressure_plate", {"powered": false}], 507 | "70:1": ["stone_pressure_plate", {"powered": true}], 508 | 509 | "71:0": ["iron_door", {"half": "lower", "facing": "east", "open": false}], 510 | "71:1": ["iron_door", {"half": "lower", "facing": "south", "open": false}], 511 | "71:2": ["iron_door", {"half": "lower", "facing": "west", "open": false}], 512 | "71:3": ["iron_door", {"half": "lower", "facing": "north", "open": false}], 513 | "71:4": ["iron_door", {"half": "lower", "facing": "east", "open": true}], 514 | "71:5": ["iron_door", {"half": "lower", "facing": "south", "open": true}], 515 | "71:6": ["iron_door", {"half": "lower", "facing": "west", "open": true}], 516 | "71:7": ["iron_door", {"half": "lower", "facing": "north", "open": true}], 517 | 518 | "71:8": ["iron_door", {"half": "upper", "hinge": "left", "powered": false}], 519 | "71:9": ["iron_door", {"half": "upper", "hinge": "right", "powered": false}], 520 | "71:10": ["iron_door", {"half": "upper", "hinge": "left", "powered": true}], 521 | "71:11": ["iron_door", {"half": "upper", "hinge": "right", "powered": true}], 522 | 523 | "72:0": ["oak_pressure_plate", {"powered": false}], 524 | "72:1": ["oak_pressure_plate", {"powered": true}], 525 | 526 | "73:0": ["redstone_ore", {"lit": false}], 527 | "74:0": ["redstone_ore", {"lit": true}], 528 | 529 | "75:0": ["redstone_torch", {"lit": false}], 530 | "75:1": ["redstone_wall_torch", {"facing": "east", "lit": false}], 531 | "75:2": ["redstone_wall_torch", {"facing": "west", "lit": false}], 532 | "75:3": ["redstone_wall_torch", {"facing": "south", "lit": false}], 533 | "75:4": ["redstone_wall_torch", {"facing": "north", "lit": false}], 534 | "75:5": ["redstone_torch", {"lit": false}], 535 | 536 | "76:0": ["redstone_torch", {"lit": true}], 537 | "76:1": ["redstone_wall_torch", {"facing": "east", "lit": true}], 538 | "76:2": ["redstone_wall_torch", {"facing": "west", "lit": true}], 539 | "76:3": ["redstone_wall_torch", {"facing": "south", "lit": true}], 540 | "76:4": ["redstone_wall_torch", {"facing": "north", "lit": true}], 541 | "76:5": ["redstone_torch", {"lit": true}], 542 | 543 | "77:0": ["stone_button", {"face": "ceiling", "powered": false}], 544 | "77:1": ["stone_button", {"face": "wall", "facing": "east", "powered": false}], 545 | "77:2": ["stone_button", {"face": "wall", "facing": "west", "powered": false}], 546 | "77:3": ["stone_button", {"face": "wall", "facing": "south", "powered": false}], 547 | "77:4": ["stone_button", {"face": "wall", "facing": "north", "powered": false}], 548 | "77:5": ["stone_button", {"face": "floor", "powered": false}], 549 | "77:8": ["stone_button", {"face": "ceiling", "powered": true}], 550 | "77:9": ["stone_button", {"face": "wall", "facing": "east", "powered": true}], 551 | "77:10": ["stone_button", {"face": "wall", "facing": "west", "powered": true}], 552 | "77:11": ["stone_button", {"face": "wall", "facing": "south", "powered": true}], 553 | "77:12": ["stone_button", {"face": "wall", "facing": "north", "powered": true}], 554 | "77:13": ["stone_button", {"face": "floor", "powered": true}], 555 | 556 | "78:0": ["snow", {"layers": 1}], 557 | "78:1": ["snow", {"layers": 2}], 558 | "78:2": ["snow", {"layers": 3}], 559 | "78:3": ["snow", {"layers": 4}], 560 | "78:4": ["snow", {"layers": 5}], 561 | "78:5": ["snow", {"layers": 6}], 562 | "78:6": ["snow", {"layers": 7}], 563 | "78:7": ["snow", {"layers": 8}], 564 | 565 | "79:0": ["ice", null], 566 | "80:0": ["snow_block", null], 567 | 568 | "81:0": ["cactus", {"age": 0}], 569 | "81:1": ["cactus", {"age": 1}], 570 | "81:2": ["cactus", {"age": 2}], 571 | "81:3": ["cactus", {"age": 3}], 572 | "81:4": ["cactus", {"age": 4}], 573 | "81:5": ["cactus", {"age": 5}], 574 | "81:6": ["cactus", {"age": 6}], 575 | "81:7": ["cactus", {"age": 7}], 576 | "81:8": ["cactus", {"age": 8}], 577 | "81:9": ["cactus", {"age": 9}], 578 | "81:10": ["cactus", {"age": 10}], 579 | "81:11": ["cactus", {"age": 11}], 580 | "81:12": ["cactus", {"age": 12}], 581 | "81:13": ["cactus", {"age": 13}], 582 | "81:14": ["cactus", {"age": 14}], 583 | "81:15": ["cactus", {"age": 15}], 584 | 585 | "82:0": ["clay", null], 586 | 587 | "83:0": ["sugar_cane", {"age": 0}], 588 | "83:1": ["sugar_cane", {"age": 1}], 589 | "83:2": ["sugar_cane", {"age": 2}], 590 | "83:3": ["sugar_cane", {"age": 3}], 591 | "83:4": ["sugar_cane", {"age": 4}], 592 | "83:5": ["sugar_cane", {"age": 5}], 593 | "83:6": ["sugar_cane", {"age": 6}], 594 | "83:7": ["sugar_cane", {"age": 7}], 595 | "83:8": ["sugar_cane", {"age": 8}], 596 | "83:9": ["sugar_cane", {"age": 9}], 597 | "83:10": ["sugar_cane", {"age": 10}], 598 | "83:11": ["sugar_cane", {"age": 11}], 599 | "83:12": ["sugar_cane", {"age": 12}], 600 | "83:13": ["sugar_cane", {"age": 13}], 601 | "83:14": ["sugar_cane", {"age": 14}], 602 | "83:15": ["sugar_cane", {"age": 15}], 603 | 604 | "84:0": ["jukebox", {"has_record": false}], 605 | "84:1": ["jukebox", {"has_record": true}], 606 | 607 | "85:0": ["oak_fence", null], 608 | 609 | "86:0": ["carved_pumpkin", {"facing": "south"}], 610 | "86:1": ["carved_pumpkin", {"facing": "west"}], 611 | "86:2": ["carved_pumpkin", {"facing": "north"}], 612 | "86:3": ["carved_pumpkin", {"facing": "east"}], 613 | 614 | "87:0": ["netherrack", null], 615 | "88:0": ["soul_sand", null], 616 | "89:0": ["glowstone", null], 617 | 618 | "90:0": ["nether_portal", null], 619 | "90:1": ["nether_portal", {"axis": "z"}], 620 | "90:2": ["nether_portal", {"axis": "x"}], 621 | 622 | "91:0": ["jack_o_lantern", {"facing": "south"}], 623 | "91:1": ["jack_o_lantern", {"facing": "west"}], 624 | "91:2": ["jack_o_lantern", {"facing": "north"}], 625 | "91:3": ["jack_o_lantern", {"facing": "east"}], 626 | 627 | "92:0": ["cake", {"bites": 0}], 628 | "92:1": ["cake", {"bites": 1}], 629 | "92:2": ["cake", {"bites": 2}], 630 | "92:3": ["cake", {"bites": 3}], 631 | "92:4": ["cake", {"bites": 4}], 632 | "92:5": ["cake", {"bites": 5}], 633 | "92:6": ["cake", {"bites": 6}], 634 | 635 | "93:0": ["repeater", {"facing": "south", "delay": 1, "powered": false}], 636 | "93:1": ["repeater", {"facing": "west", "delay": 1, "powered": false}], 637 | "93:2": ["repeater", {"facing": "north", "delay": 1, "powered": false}], 638 | "93:3": ["repeater", {"facing": "east", "delay": 1, "powered": false}], 639 | "93:4": ["repeater", {"facing": "south", "delay": 2, "powered": false}], 640 | "93:5": ["repeater", {"facing": "west", "delay": 2, "powered": false}], 641 | "93:6": ["repeater", {"facing": "north", "delay": 2, "powered": false}], 642 | "93:7": ["repeater", {"facing": "east", "delay": 2, "powered": false}], 643 | "93:8": ["repeater", {"facing": "south", "delay": 3, "powered": false}], 644 | "93:9": ["repeater", {"facing": "west", "delay": 3, "powered": false}], 645 | "93:10": ["repeater", {"facing": "north", "delay": 3, "powered": false}], 646 | "93:11": ["repeater", {"facing": "east", "delay": 3, "powered": false}], 647 | "93:12": ["repeater", {"facing": "south", "delay": 4, "powered": false}], 648 | "93:13": ["repeater", {"facing": "west", "delay": 4, "powered": false}], 649 | "93:14": ["repeater", {"facing": "north", "delay": 4, "powered": false}], 650 | "93:15": ["repeater", {"facing": "east", "delay": 4, "powered": false}], 651 | 652 | "94:0": ["repeater", {"facing": "south", "delay": 1, "powered": true}], 653 | "94:1": ["repeater", {"facing": "west", "delay": 1, "powered": true}], 654 | "94:2": ["repeater", {"facing": "north", "delay": 1, "powered": true}], 655 | "94:3": ["repeater", {"facing": "east", "delay": 1, "powered": true}], 656 | "94:4": ["repeater", {"facing": "south", "delay": 2, "powered": true}], 657 | "94:5": ["repeater", {"facing": "west", "delay": 2, "powered": true}], 658 | "94:6": ["repeater", {"facing": "north", "delay": 2, "powered": true}], 659 | "94:7": ["repeater", {"facing": "east", "delay": 2, "powered": true}], 660 | "94:8": ["repeater", {"facing": "south", "delay": 3, "powered": true}], 661 | "94:9": ["repeater", {"facing": "west", "delay": 3, "powered": true}], 662 | "94:10": ["repeater", {"facing": "north", "delay": 3, "powered": true}], 663 | "94:11": ["repeater", {"facing": "east", "delay": 3, "powered": true}], 664 | "94:12": ["repeater", {"facing": "south", "delay": 4, "powered": true}], 665 | "94:13": ["repeater", {"facing": "west", "delay": 4, "powered": true}], 666 | "94:14": ["repeater", {"facing": "north", "delay": 4, "powered": true}], 667 | "94:15": ["repeater", {"facing": "east", "delay": 4, "powered": true}], 668 | 669 | "95:0": ["white_stained_glass", null], 670 | "95:1": ["orange_stained_glass", null], 671 | "95:2": ["magenta_stained_glass", null], 672 | "95:3": ["light_blue_stained_glass", null], 673 | "95:4": ["yellow_stained_glass", null], 674 | "95:5": ["lime_stained_glass", null], 675 | "95:6": ["pink_stained_glass", null], 676 | "95:7": ["gray_stained_glass", null], 677 | "95:8": ["light_gray_stained_glass", null], 678 | "95:9": ["cyan_stained_glass", null], 679 | "95:10": ["purple_stained_glass", null], 680 | "95:11": ["blue_stained_glass", null], 681 | "95:12": ["brown_stained_glass", null], 682 | "95:13": ["green_stained_glass", null], 683 | "95:14": ["red_stained_glass", null], 684 | "95:15": ["black_stained_glass", null], 685 | 686 | "96:0": ["oak_trapdoor", {"facing": "north", "open": false, "half": "bottom"}], 687 | "96:1": ["oak_trapdoor", {"facing": "south", "open": false, "half": "bottom"}], 688 | "96:2": ["oak_trapdoor", {"facing": "west", "open": false, "half": "bottom"}], 689 | "96:3": ["oak_trapdoor", {"facing": "east", "open": false, "half": "bottom"}], 690 | "96:4": ["oak_trapdoor", {"facing": "north", "open": true, "half": "bottom"}], 691 | "96:5": ["oak_trapdoor", {"facing": "south", "open": true, "half": "bottom"}], 692 | "96:6": ["oak_trapdoor", {"facing": "west", "open": true, "half": "bottom"}], 693 | "96:7": ["oak_trapdoor", {"facing": "east", "open": true, "half": "bottom"}], 694 | "96:8": ["oak_trapdoor", {"facing": "north", "open": false, "half": "top"}], 695 | "96:9": ["oak_trapdoor", {"facing": "south", "open": false, "half": "top"}], 696 | "96:10": ["oak_trapdoor", {"facing": "west", "open": false, "half": "top"}], 697 | "96:11": ["oak_trapdoor", {"facing": "east", "open": false, "half": "top"}], 698 | "96:12": ["oak_trapdoor", {"facing": "north", "open": true, "half": "top"}], 699 | "96:13": ["oak_trapdoor", {"facing": "south", "open": true, "half": "top"}], 700 | "96:14": ["oak_trapdoor", {"facing": "west", "open": true, "half": "top"}], 701 | "96:15": ["oak_trapdoor", {"facing": "east", "open": true, "half": "top"}], 702 | 703 | 704 | "97:0": ["infested_stone", null], 705 | "97:1": ["infested_cobblestone", null], 706 | "97:2": ["infested_stone_bricks", null], 707 | "97:3": ["infested_mossy_stone_bricks", null], 708 | "97:4": ["infested_cracked_stone_bricks", null], 709 | "97:5": ["infested_chiseled_stone_bricks", null], 710 | "98:0": ["stone_bricks", null], 711 | "98:1": ["mossy_stone_bricks", null], 712 | "98:2": ["cracked_stone_bricks", null], 713 | "98:3": ["chiseled_stone_bricks", null], 714 | 715 | "99:0": ["brown_mushroom_block", null], 716 | "99:1": ["brown_mushroom_block", null], 717 | "99:2": ["brown_mushroom_block", null], 718 | "99:3": ["brown_mushroom_block", null], 719 | "99:4": ["brown_mushroom_block", null], 720 | "99:5": ["brown_mushroom_block", null], 721 | "99:6": ["brown_mushroom_block", null], 722 | "99:7": ["brown_mushroom_block", null], 723 | "99:8": ["brown_mushroom_block", null], 724 | "99:9": ["brown_mushroom_block", null], 725 | "99:10": ["brown_mushroom_block", null], 726 | "99:11": ["brown_mushroom_block", null], 727 | "99:12": ["brown_mushroom_block", null], 728 | "99:13": ["brown_mushroom_block", null], 729 | "99:14": ["brown_mushroom_block", null], 730 | "99:15": ["brown_mushroom_block", null], 731 | 732 | "100:0": ["red_mushroom_block", null], 733 | "100:1": ["red_mushroom_block", null], 734 | "100:2": ["red_mushroom_block", null], 735 | "100:3": ["red_mushroom_block", null], 736 | "100:4": ["red_mushroom_block", null], 737 | "100:5": ["red_mushroom_block", null], 738 | "100:6": ["red_mushroom_block", null], 739 | "100:7": ["red_mushroom_block", null], 740 | "100:8": ["red_mushroom_block", null], 741 | "100:9": ["red_mushroom_block", null], 742 | "100:10": ["red_mushroom_block", null], 743 | "100:11": ["red_mushroom_block", null], 744 | "100:12": ["red_mushroom_block", null], 745 | "100:13": ["red_mushroom_block", null], 746 | "100:14": ["red_mushroom_block", null], 747 | "100:15": ["red_mushroom_block", null], 748 | 749 | 750 | "101:0": ["iron_bars", null], 751 | "102:0": ["glass_pane", null], 752 | "103:0": ["melon", null], 753 | 754 | "104:0": ["pumpkin_stem", {"age": 0}], 755 | "104:1": ["pumpkin_stem", {"age": 1}], 756 | "104:2": ["pumpkin_stem", {"age": 2}], 757 | "104:3": ["pumpkin_stem", {"age": 3}], 758 | "104:4": ["pumpkin_stem", {"age": 4}], 759 | "104:5": ["pumpkin_stem", {"age": 5}], 760 | "104:6": ["pumpkin_stem", {"age": 6}], 761 | "104:7": ["pumpkin_stem", {"age": 7}], 762 | 763 | "105:0": ["melon_stem", {"age": 0}], 764 | "105:1": ["melon_stem", {"age": 1}], 765 | "105:2": ["melon_stem", {"age": 2}], 766 | "105:3": ["melon_stem", {"age": 3}], 767 | "105:4": ["melon_stem", {"age": 4}], 768 | "105:5": ["melon_stem", {"age": 5}], 769 | "105:6": ["melon_stem", {"age": 6}], 770 | "105:7": ["melon_stem", {"age": 7}], 771 | 772 | "106:0": ["vine", {"south": false, "west": false, "north": false, "east": false}], 773 | "106:1": ["vine", {"south": true, "west": false, "north": false, "east": false}], 774 | "106:2": ["vine", {"south": false, "west": true, "north": false, "east": false}], 775 | "106:3": ["vine", {"south": true, "west": true, "north": false, "east": false}], 776 | "106:4": ["vine", {"south": false, "west": false, "north": true, "east": false}], 777 | "106:5": ["vine", {"south": true, "west": false, "north": true, "east": false}], 778 | "106:6": ["vine", {"south": false, "west": true, "north": true, "east": false}], 779 | "106:7": ["vine", {"south": true, "west": true, "north": true, "east": false}], 780 | "106:8": ["vine", {"south": false, "west": false, "north": false, "east": true}], 781 | "106:9": ["vine", {"south": true, "west": false, "north": false, "east": true}], 782 | "106:10": ["vine", {"south": false, "west": true, "north": false, "east": true}], 783 | "106:11": ["vine", {"south": true, "west": true, "north": false, "east": true}], 784 | "106:12": ["vine", {"south": false, "west": false, "north": true, "east": true}], 785 | "106:13": ["vine", {"south": true, "west": false, "north": true, "east": true}], 786 | "106:14": ["vine", {"south": false, "west": true, "north": true, "east": true}], 787 | "106:15": ["vine", {"south": true, "west": true, "north": true, "east": true}], 788 | 789 | "107:0": ["oak_fence_gate", {"facing": "south", "open": false}], 790 | "107:1": ["oak_fence_gate", {"facing": "west", "open": false}], 791 | "107:2": ["oak_fence_gate", {"facing": "north", "open": false}], 792 | "107:3": ["oak_fence_gate", {"facing": "east", "open": false}], 793 | "107:4": ["oak_fence_gate", {"facing": "south", "open": true}], 794 | "107:5": ["oak_fence_gate", {"facing": "west", "open": true}], 795 | "107:6": ["oak_fence_gate", {"facing": "north", "open": true}], 796 | "107:7": ["oak_fence_gate", {"facing": "east", "open": true}], 797 | 798 | "108:0": ["brick_stairs", {"facing": "east", "half": "bottom"}], 799 | "108:1": ["brick_stairs", {"facing": "west", "half": "bottom"}], 800 | "108:2": ["brick_stairs", {"facing": "south", "half": "bottom"}], 801 | "108:3": ["brick_stairs", {"facing": "north", "half": "bottom"}], 802 | "108:4": ["brick_stairs", {"facing": "east", "half": "top"}], 803 | "108:5": ["brick_stairs", {"facing": "west", "half": "top"}], 804 | "108:6": ["brick_stairs", {"facing": "south", "half": "top"}], 805 | "108:7": ["brick_stairs", {"facing": "north", "half": "top"}], 806 | 807 | "109:0": ["stone_brick_stairs", {"facing": "east", "half": "bottom"}], 808 | "109:1": ["stone_brick_stairs", {"facing": "west", "half": "bottom"}], 809 | "109:2": ["stone_brick_stairs", {"facing": "south", "half": "bottom"}], 810 | "109:3": ["stone_brick_stairs", {"facing": "north", "half": "bottom"}], 811 | "109:4": ["stone_brick_stairs", {"facing": "east", "half": "top"}], 812 | "109:5": ["stone_brick_stairs", {"facing": "west", "half": "top"}], 813 | "109:6": ["stone_brick_stairs", {"facing": "south", "half": "top"}], 814 | "109:7": ["stone_brick_stairs", {"facing": "north", "half": "top"}], 815 | 816 | "110:0": ["mycelium", null], 817 | "111:0": ["lily_pad", null], 818 | "112:0": ["nether_bricks", null], 819 | "113:0": ["nether_brick_fence", null], 820 | 821 | "114:0": ["nether_brick_stairs", {"facing": "east", "half": "bottom"}], 822 | "114:1": ["nether_brick_stairs", {"facing": "west", "half": "bottom"}], 823 | "114:2": ["nether_brick_stairs", {"facing": "south", "half": "bottom"}], 824 | "114:3": ["nether_brick_stairs", {"facing": "north", "half": "bottom"}], 825 | "114:4": ["nether_brick_stairs", {"facing": "east", "half": "top"}], 826 | "114:5": ["nether_brick_stairs", {"facing": "west", "half": "top"}], 827 | "114:6": ["nether_brick_stairs", {"facing": "south", "half": "top"}], 828 | "114:7": ["nether_brick_stairs", {"facing": "north", "half": "top"}], 829 | 830 | "115:0": ["nether_wart", {"age": 0}], 831 | "115:1": ["nether_wart", {"age": 1}], 832 | "115:2": ["nether_wart", {"age": 2}], 833 | "115:3": ["nether_wart", {"age": 3}], 834 | 835 | "116:0": ["enchanting_table", null], 836 | 837 | "117:0": ["brewing_stand", {"has_bottle_0": false, "has_bottle_1": false, "has_bottle_2": false}], 838 | "117:1": ["brewing_stand", {"has_bottle_0": true, "has_bottle_1": false, "has_bottle_2": false}], 839 | "117:2": ["brewing_stand", {"has_bottle_0": false, "has_bottle_1": true, "has_bottle_2": false}], 840 | "117:3": ["brewing_stand", {"has_bottle_0": true, "has_bottle_1": true, "has_bottle_2": false}], 841 | "117:4": ["brewing_stand", {"has_bottle_0": false, "has_bottle_1": false, "has_bottle_2": true}], 842 | "117:5": ["brewing_stand", {"has_bottle_0": true, "has_bottle_1": false, "has_bottle_2": true}], 843 | "117:6": ["brewing_stand", {"has_bottle_0": false, "has_bottle_1": true, "has_bottle_2": true}], 844 | "117:7": ["brewing_stand", {"has_bottle_0": true, "has_bottle_1": true, "has_bottle_2": true}], 845 | 846 | 847 | "118:0": ["cauldron", {"level": 0}], 848 | "118:1": ["cauldron", {"level": 1}], 849 | "118:2": ["cauldron", {"level": 2}], 850 | "118:3": ["cauldron", {"level": 3}], 851 | 852 | "119:0": ["end_portal", null], 853 | 854 | "120:0": ["end_portal_frame", {"facing": "south", "eye": false}], 855 | "120:1": ["end_portal_frame", {"facing": "west", "eye": false}], 856 | "120:2": ["end_portal_frame", {"facing": "north", "eye": false}], 857 | "120:3": ["end_portal_frame", {"facing": "east", "eye": false}], 858 | "120:4": ["end_portal_frame", {"facing": "south", "eye": true}], 859 | "120:5": ["end_portal_frame", {"facing": "west", "eye": true}], 860 | "120:6": ["end_portal_frame", {"facing": "north", "eye": true}], 861 | "120:7": ["end_portal_frame", {"facing": "east", "eye": true}], 862 | 863 | "121:0": ["end_stone", null], 864 | "122:0": ["dragon_egg", null], 865 | "123:0": ["redstone_lamp", {"lit": false}], 866 | "124:0": ["redstone_lamp", {"lit": true}], 867 | 868 | "125:0": ["oak_slab", {"type": "double"}], 869 | "125:1": ["spruce_slab", {"type": "double"}], 870 | "125:2": ["birch_slab", {"type": "double"}], 871 | "125:3": ["jungle_slab", {"type": "double"}], 872 | "125:4": ["acacia_slab", {"type": "double"}], 873 | "125:5": ["dark_oak_slab", {"type": "double"}], 874 | 875 | "126:0": ["oak_slab", {"type": "bottom"}], 876 | "126:1": ["spruce_slab", {"type": "bottom"}], 877 | "126:2": ["birch_slab", {"type": "bottom"}], 878 | "126:3": ["jungle_slab", {"type": "bottom"}], 879 | "126:4": ["acacia_slab", {"type": "bottom"}], 880 | "126:5": ["dark_oak_slab", {"type": "bottom"}], 881 | "126:8": ["oak_slab", {"type": "top"}], 882 | "126:9": ["spruce_slab", {"type": "top"}], 883 | "126:10": ["birch_slab", {"type": "top"}], 884 | "126:11": ["jungle_slab", {"type": "top"}], 885 | "126:12": ["acacia_slab", {"type": "top"}], 886 | "126:13": ["dark_oak_slab", {"type": "top"}], 887 | 888 | "127:0": ["cocoa", {"facing": "north", "age": 0}], 889 | "127:1": ["cocoa", {"facing": "east", "age": 0}], 890 | "127:2": ["cocoa", {"facing": "south", "age": 0}], 891 | "127:3": ["cocoa", {"facing": "west", "age": 0}], 892 | "127:4": ["cocoa", {"facing": "north", "age": 1}], 893 | "127:5": ["cocoa", {"facing": "east", "age": 1}], 894 | "127:6": ["cocoa", {"facing": "south", "age": 1}], 895 | "127:7": ["cocoa", {"facing": "west", "age": 1}], 896 | "127:8": ["cocoa", {"facing": "north", "age": 2}], 897 | "127:9": ["cocoa", {"facing": "east", "age": 2}], 898 | "127:10": ["cocoa", {"facing": "south", "age": 2}], 899 | "127:11": ["cocoa", {"facing": "west", "age": 2}], 900 | "127:12": ["cocoa", {"facing": "north", "age": 3}], 901 | "127:13": ["cocoa", {"facing": "east", "age": 3}], 902 | "127:14": ["cocoa", {"facing": "south", "age": 3}], 903 | "127:15": ["cocoa", {"facing": "west", "age": 3}], 904 | 905 | "128:0": ["sandstone_stairs", {"facing": "east", "half": "bottom"}], 906 | "128:1": ["sandstone_stairs", {"facing": "west", "half": "bottom"}], 907 | "128:2": ["sandstone_stairs", {"facing": "south", "half": "bottom"}], 908 | "128:3": ["sandstone_stairs", {"facing": "north", "half": "bottom"}], 909 | "128:4": ["sandstone_stairs", {"facing": "east", "half": "top"}], 910 | "128:5": ["sandstone_stairs", {"facing": "west", "half": "top"}], 911 | "128:6": ["sandstone_stairs", {"facing": "south", "half": "top"}], 912 | "128:7": ["sandstone_stairs", {"facing": "north", "half": "top"}], 913 | 914 | "129:0": ["emerald_ore", null], 915 | 916 | "130:0": ["ender_chest", {"facing": "north"}], 917 | "130:1": ["ender_chest", {"facing": "north"}], 918 | "130:2": ["ender_chest", {"facing": "north"}], 919 | "130:3": ["ender_chest", {"facing": "south"}], 920 | "130:4": ["ender_chest", {"facing": "west"}], 921 | "130:5": ["ender_chest", {"facing": "east"}], 922 | 923 | "131:0": ["tripwire_hook", {"facing": "south", "attached": false, "powered": false}], 924 | "131:1": ["tripwire_hook", {"facing": "west", "attached": false, "powered": false}], 925 | "131:2": ["tripwire_hook", {"facing": "north", "attached": false, "powered": false}], 926 | "131:3": ["tripwire_hook", {"facing": "east", "attached": false, "powered": false}], 927 | "131:4": ["tripwire_hook", {"facing": "south", "attached": true, "powered": false}], 928 | "131:5": ["tripwire_hook", {"facing": "west", "attached": true, "powered": false}], 929 | "131:6": ["tripwire_hook", {"facing": "north", "attached": true, "powered": false}], 930 | "131:7": ["tripwire_hook", {"facing": "east", "attached": true, "powered": false}], 931 | "131:8": ["tripwire_hook", {"facing": "south", "attached": false, "powered": true}], 932 | "131:9": ["tripwire_hook", {"facing": "west", "attached": false, "powered": true}], 933 | "131:10": ["tripwire_hook", {"facing": "north", "attached": false, "powered": true}], 934 | "131:11": ["tripwire_hook", {"facing": "east", "attached": false, "powered": true}], 935 | "131:12": ["tripwire_hook", {"facing": "south", "attached": true, "powered": true}], 936 | "131:13": ["tripwire_hook", {"facing": "west", "attached": true, "powered": true}], 937 | "131:14": ["tripwire_hook", {"facing": "north", "attached": true, "powered": true}], 938 | "131:15": ["tripwire_hook", {"facing": "east", "attached": true, "powered": true}], 939 | 940 | "132:0": ["tripwire", {"powered": false, "attached": false, "disarmed": false}], 941 | "132:1": ["tripwire", {"powered": true, "attached": false, "disarmed": false}], 942 | "132:4": ["tripwire", {"powered": false, "attached": true, "disarmed": false}], 943 | "132:5": ["tripwire", {"powered": true, "attached": true, "disarmed": false}], 944 | "132:8": ["tripwire", {"powered": false, "attached": false, "disarmed": true}], 945 | "132:9": ["tripwire", {"powered": true, "attached": false, "disarmed": true}], 946 | "132:12": ["tripwire", {"powered": false, "attached": true, "disarmed": true}], 947 | "132:13": ["tripwire", {"powered": true, "attached": true, "disarmed": true}], 948 | 949 | "133:0": ["emerald_block", null], 950 | 951 | "134:0": ["spruce_stairs", {"facing": "east", "half": "bottom"}], 952 | "134:1": ["spruce_stairs", {"facing": "west", "half": "bottom"}], 953 | "134:2": ["spruce_stairs", {"facing": "south", "half": "bottom"}], 954 | "134:3": ["spruce_stairs", {"facing": "north", "half": "bottom"}], 955 | "134:4": ["spruce_stairs", {"facing": "east", "half": "top"}], 956 | "134:5": ["spruce_stairs", {"facing": "west", "half": "top"}], 957 | "134:6": ["spruce_stairs", {"facing": "south", "half": "top"}], 958 | "134:7": ["spruce_stairs", {"facing": "north", "half": "top"}], 959 | 960 | "135:0": ["birch_stairs", {"facing": "east", "half": "bottom"}], 961 | "135:1": ["birch_stairs", {"facing": "west", "half": "bottom"}], 962 | "135:2": ["birch_stairs", {"facing": "south", "half": "bottom"}], 963 | "135:3": ["birch_stairs", {"facing": "north", "half": "bottom"}], 964 | "135:4": ["birch_stairs", {"facing": "east", "half": "top"}], 965 | "135:5": ["birch_stairs", {"facing": "west", "half": "top"}], 966 | "135:6": ["birch_stairs", {"facing": "south", "half": "top"}], 967 | "135:7": ["birch_stairs", {"facing": "north", "half": "top"}], 968 | 969 | "136:0": ["jungle_stairs", {"facing": "east", "half": "bottom"}], 970 | "136:1": ["jungle_stairs", {"facing": "west", "half": "bottom"}], 971 | "136:2": ["jungle_stairs", {"facing": "south", "half": "bottom"}], 972 | "136:3": ["jungle_stairs", {"facing": "north", "half": "bottom"}], 973 | "136:4": ["jungle_stairs", {"facing": "east", "half": "top"}], 974 | "136:5": ["jungle_stairs", {"facing": "west", "half": "top"}], 975 | "136:6": ["jungle_stairs", {"facing": "south", "half": "top"}], 976 | "136:7": ["jungle_stairs", {"facing": "north", "half": "top"}], 977 | 978 | "137:0": ["command_block", null], 979 | "138:0": ["beacon", null], 980 | 981 | "139:0": ["cobblestone_wall", null], 982 | 983 | "139:1": ["mossy_cobblestone_wall", null], 984 | 985 | "140:0": ["flower_pot", null], 986 | "140:1": ["potted_poppy", null], 987 | "140:2": ["potted_dandelion", null], 988 | "140:3": ["potted_oak_sapling", null], 989 | "140:4": ["potted_spruce_sapling", null], 990 | "140:5": ["potted_birch_sapling", null], 991 | "140:6": ["potted_jungle_sapling", null], 992 | "140:7": ["potted_red_mushroom", null], 993 | "140:8": ["potted_brown_mushroom", null], 994 | "140:9": ["potted_cactus", null], 995 | "140:10": ["potted_dead_bush", null], 996 | "140:11": ["potted_fern", null], 997 | "140:12": ["potted_acacia_sapling", null], 998 | "140:13": ["potted_dark_oak_sapling", null], 999 | "140:14": ["flower_pot", null], 1000 | "140:15": ["flower_pot", null], 1001 | 1002 | "141:0": ["carrots", {"age": 0}], 1003 | "141:1": ["carrots", {"age": 1}], 1004 | "141:2": ["carrots", {"age": 2}], 1005 | "141:3": ["carrots", {"age": 3}], 1006 | "141:4": ["carrots", {"age": 4}], 1007 | "141:5": ["carrots", {"age": 5}], 1008 | "141:6": ["carrots", {"age": 6}], 1009 | "141:7": ["carrots", {"age": 7}], 1010 | 1011 | "142:0": ["potatoes", {"age": 0}], 1012 | "142:1": ["potatoes", {"age": 1}], 1013 | "142:2": ["potatoes", {"age": 2}], 1014 | "142:3": ["potatoes", {"age": 3}], 1015 | "142:4": ["potatoes", {"age": 4}], 1016 | "142:5": ["potatoes", {"age": 5}], 1017 | "142:6": ["potatoes", {"age": 6}], 1018 | "142:7": ["potatoes", {"age": 7}], 1019 | 1020 | "143:0": ["oak_button", {"face": "ceiling", "powered": false}], 1021 | "143:1": ["oak_button", {"face": "wall", "facing": "east", "powered": false}], 1022 | "143:2": ["oak_button", {"face": "wall", "facing": "west", "powered": false}], 1023 | "143:3": ["oak_button", {"face": "wall", "facing": "south", "powered": false}], 1024 | "143:4": ["oak_button", {"face": "wall", "facing": "north", "powered": false}], 1025 | "143:5": ["oak_button", {"face": "floor", "powered": false}], 1026 | "143:8": ["oak_button", {"face": "ceiling", "powered": true}], 1027 | "143:9": ["oak_button", {"face": "wall", "facing": "east", "powered": true}], 1028 | "143:10": ["oak_button", {"face": "wall", "facing": "west", "powered": true}], 1029 | "143:11": ["oak_button", {"face": "wall", "facing": "south", "powered": true}], 1030 | "143:12": ["oak_button", {"face": "wall", "facing": "north", "powered": true}], 1031 | "143:13": ["oak_button", {"face": "floor", "powered": true}], 1032 | 1033 | "144:0": ["skull", null], 1034 | "144:1": ["skull", null], 1035 | "144:2": ["wall_skull", null], 1036 | "144:3": ["wall_skull", null], 1037 | "144:4": ["wall_skull", null], 1038 | "144:4": ["wall_skull", null], 1039 | 1040 | "145:0": ["anvil", {"facing": "south"}], 1041 | "145:1": ["anvil", {"facing": "west"}], 1042 | "145:2": ["anvil", {"facing": "north"}], 1043 | "145:3": ["anvil", {"facing": "east"}], 1044 | "145:4": ["chipped_anvil", {"facing": "south"}], 1045 | "145:5": ["chipped_anvil", {"facing": "west"}], 1046 | "145:6": ["chipped_anvil", {"facing": "north"}], 1047 | "145:7": ["chipped_anvil", {"facing": "east"}], 1048 | "145:8": ["damaged_anvil", {"facing": "south"}], 1049 | "145:9": ["damaged_anvil", {"facing": "west"}], 1050 | "145:10": ["damaged_anvil", {"facing": "north"}], 1051 | "145:11": ["damaged_anvil", {"facing": "east"}], 1052 | 1053 | "146:0": ["trapped_chest", {"facing": "north"}], 1054 | "146:1": ["trapped_chest", {"facing": "north"}], 1055 | "146:2": ["trapped_chest", {"facing": "north"}], 1056 | "146:3": ["trapped_chest", {"facing": "south"}], 1057 | "146:4": ["trapped_chest", {"facing": "west"}], 1058 | "146:5": ["trapped_chest", {"facing": "east"}], 1059 | 1060 | "147:0": ["light_weighted_pressure_plate", {"power": 0}], 1061 | "147:1": ["light_weighted_pressure_plate", {"power": 1}], 1062 | "147:2": ["light_weighted_pressure_plate", {"power": 2}], 1063 | "147:3": ["light_weighted_pressure_plate", {"power": 3}], 1064 | "147:4": ["light_weighted_pressure_plate", {"power": 4}], 1065 | "147:5": ["light_weighted_pressure_plate", {"power": 5}], 1066 | "147:6": ["light_weighted_pressure_plate", {"power": 6}], 1067 | "147:7": ["light_weighted_pressure_plate", {"power": 7}], 1068 | "147:8": ["light_weighted_pressure_plate", {"power": 8}], 1069 | "147:9": ["light_weighted_pressure_plate", {"power": 9}], 1070 | "147:10": ["light_weighted_pressure_plate", {"power": 10}], 1071 | "147:11": ["light_weighted_pressure_plate", {"power": 11}], 1072 | "147:12": ["light_weighted_pressure_plate", {"power": 12}], 1073 | "147:13": ["light_weighted_pressure_plate", {"power": 13}], 1074 | "147:14": ["light_weighted_pressure_plate", {"power": 14}], 1075 | "147:15": ["light_weighted_pressure_plate", {"power": 15}], 1076 | 1077 | "148:0": ["heavy_weighted_pressure_plate", {"power": 0}], 1078 | "148:1": ["heavy_weighted_pressure_plate", {"power": 1}], 1079 | "148:2": ["heavy_weighted_pressure_plate", {"power": 2}], 1080 | "148:3": ["heavy_weighted_pressure_plate", {"power": 3}], 1081 | "148:4": ["heavy_weighted_pressure_plate", {"power": 4}], 1082 | "148:5": ["heavy_weighted_pressure_plate", {"power": 5}], 1083 | "148:6": ["heavy_weighted_pressure_plate", {"power": 6}], 1084 | "148:7": ["heavy_weighted_pressure_plate", {"power": 7}], 1085 | "148:8": ["heavy_weighted_pressure_plate", {"power": 8}], 1086 | "148:9": ["heavy_weighted_pressure_plate", {"power": 9}], 1087 | "148:10": ["heavy_weighted_pressure_plate", {"power": 10}], 1088 | "148:11": ["heavy_weighted_pressure_plate", {"power": 11}], 1089 | "148:12": ["heavy_weighted_pressure_plate", {"power": 12}], 1090 | "148:13": ["heavy_weighted_pressure_plate", {"power": 13}], 1091 | "148:14": ["heavy_weighted_pressure_plate", {"power": 14}], 1092 | "148:15": ["heavy_weighted_pressure_plate", {"power": 15}], 1093 | 1094 | "149:0": ["comparator", {"facing": "south", "mode": "compare", "powered": false}], 1095 | "149:1": ["comparator", {"facing": "west", "mode": "compare", "powered": false}], 1096 | "149:2": ["comparator", {"facing": "north", "mode": "compare", "powered": false}], 1097 | "149:3": ["comparator", {"facing": "east", "mode": "compare", "powered": false}], 1098 | "149:4": ["comparator", {"facing": "south", "mode": "subtract", "powered": false}], 1099 | "149:5": ["comparator", {"facing": "west", "mode": "subtract", "powered": false}], 1100 | "149:6": ["comparator", {"facing": "north", "mode": "subtract", "powered": false}], 1101 | "149:7": ["comparator", {"facing": "east", "mode": "subtract", "powered": false}], 1102 | 1103 | "149:8": ["comparator", {"facing": "south", "mode": "compare", "powered": true}], 1104 | "149:9": ["comparator", {"facing": "west", "mode": "compare", "powered": true}], 1105 | "149:10": ["comparator", {"facing": "north", "mode": "compare", "powered": true}], 1106 | "149:11": ["comparator", {"facing": "east", "mode": "compare", "powered": true}], 1107 | "149:12": ["comparator", {"facing": "south", "mode": "subtract", "powered": true}], 1108 | "149:13": ["comparator", {"facing": "west", "mode": "subtract", "powered": true}], 1109 | "149:14": ["comparator", {"facing": "north", "mode": "subtract", "powered": true}], 1110 | "149:15": ["comparator", {"facing": "east", "mode": "subtract", "powered": true}], 1111 | 1112 | "150:0": ["comparator", {"facing": "south", "mode": "compare", "powered": true}], 1113 | "150:1": ["comparator", {"facing": "west", "mode": "compare", "powered": true}], 1114 | "150:2": ["comparator", {"facing": "north", "mode": "compare", "powered": true}], 1115 | "150:3": ["comparator", {"facing": "east", "mode": "compare", "powered": true}], 1116 | "150:4": ["comparator", {"facing": "south", "mode": "subtract", "powered": true}], 1117 | "150:5": ["comparator", {"facing": "west", "mode": "subtract", "powered": true}], 1118 | "150:6": ["comparator", {"facing": "north", "mode": "subtract", "powered": true}], 1119 | "150:7": ["comparator", {"facing": "east", "mode": "subtract", "powered": true}], 1120 | 1121 | "151:0": ["daylight_detector", {"power": 0, "inverted": false}], 1122 | "151:1": ["daylight_detector", {"power": 1, "inverted": false}], 1123 | "151:2": ["daylight_detector", {"power": 2, "inverted": false}], 1124 | "151:3": ["daylight_detector", {"power": 3, "inverted": false}], 1125 | "151:4": ["daylight_detector", {"power": 4, "inverted": false}], 1126 | "151:5": ["daylight_detector", {"power": 5, "inverted": false}], 1127 | "151:6": ["daylight_detector", {"power": 6, "inverted": false}], 1128 | "151:7": ["daylight_detector", {"power": 7, "inverted": false}], 1129 | "151:8": ["daylight_detector", {"power": 8, "inverted": false}], 1130 | "151:9": ["daylight_detector", {"power": 9, "inverted": false}], 1131 | "151:10": ["daylight_detector", {"power": 10, "inverted": false}], 1132 | "151:11": ["daylight_detector", {"power": 11, "inverted": false}], 1133 | "151:12": ["daylight_detector", {"power": 12, "inverted": false}], 1134 | "151:13": ["daylight_detector", {"power": 13, "inverted": false}], 1135 | "151:14": ["daylight_detector", {"power": 14, "inverted": false}], 1136 | "151:15": ["daylight_detector", {"power": 15, "inverted": false}], 1137 | 1138 | 1139 | "152:0": ["redstone_block", null], 1140 | "153:0": ["nether_quartz_ore", null], 1141 | 1142 | "154:0": ["hopper", {"facing": "down", "enabled": true}], 1143 | "154:2": ["hopper", {"facing": "north", "enabled": true}], 1144 | "154:3": ["hopper", {"facing": "south", "enabled": true}], 1145 | "154:4": ["hopper", {"facing": "west", "enabled": true}], 1146 | "154:5": ["hopper", {"facing": "east", "enabled": true}], 1147 | "154:8": ["hopper", {"facing": "down", "enabled": false}], 1148 | "154:10": ["hopper", {"facing": "north", "enabled": false}], 1149 | "154:11": ["hopper", {"facing": "south", "enabled": false}], 1150 | "154:12": ["hopper", {"facing": "west", "enabled": false}], 1151 | "154:13": ["hopper", {"facing": "east", "enabled": false}], 1152 | 1153 | "155:0": ["quartz_block", null], 1154 | "155:1": ["chiseled_quartz_block", null], 1155 | "155:2": ["quartz_pillar", {"axis": "y"}], 1156 | "155:3": ["quartz_pillar", {"axis": "x"}], 1157 | "155:4": ["quartz_pillar", {"axis": "z"}], 1158 | 1159 | 1160 | 1161 | 1162 | "156:0": ["quartz_stairs", {"facing": "east", "half": "bottom"}], 1163 | "156:1": ["quartz_stairs", {"facing": "west", "half": "bottom"}], 1164 | "156:2": ["quartz_stairs", {"facing": "south", "half": "bottom"}], 1165 | "156:3": ["quartz_stairs", {"facing": "north", "half": "bottom"}], 1166 | "156:4": ["quartz_stairs", {"facing": "east", "half": "top"}], 1167 | "156:5": ["quartz_stairs", {"facing": "west", "half": "top"}], 1168 | "156:6": ["quartz_stairs", {"facing": "south", "half": "top"}], 1169 | "156:7": ["quartz_stairs", {"facing": "north", "half": "top"}], 1170 | 1171 | "157:0": ["activator_rail", {"shape": "north_south", "powered": false}], 1172 | "157:1": ["activator_rail", {"shape": "east_west", "powered": false}], 1173 | "157:2": ["activator_rail", {"shape": "ascending_east", "powered": false}], 1174 | "157:3": ["activator_rail", {"shape": "ascending_west", "powered": false}], 1175 | "157:4": ["activator_rail", {"shape": "ascending_north", "powered": false}], 1176 | "157:5": ["activator_rail", {"shape": "ascending_south", "powered": false}], 1177 | "157:8": ["activator_rail", {"shape": "north_south", "powered": true}], 1178 | "157:9": ["activator_rail", {"shape": "east_west", "powered": true}], 1179 | "157:10": ["activator_rail", {"shape": "ascending_east", "powered": true}], 1180 | "157:11": ["activator_rail", {"shape": "ascending_west", "powered": true}], 1181 | "157:12": ["activator_rail", {"shape": "ascending_north", "powered": true}], 1182 | "157:13": ["activator_rail", {"shape": "ascending_south", "powered": true}], 1183 | 1184 | "158:0": ["dropper", {"facing": "down", "triggered": false}], 1185 | "158:1": ["dropper", {"facing": "up", "triggered": false}], 1186 | "158:2": ["dropper", {"facing": "north", "triggered": false}], 1187 | "158:3": ["dropper", {"facing": "south", "triggered": false}], 1188 | "158:4": ["dropper", {"facing": "west", "triggered": false}], 1189 | "158:5": ["dropper", {"facing": "east", "triggered": false}], 1190 | "158:8": ["dropper", {"facing": "down", "triggered": true}], 1191 | "158:9": ["dropper", {"facing": "up", "triggered": true}], 1192 | "158:10": ["dropper", {"facing": "north", "triggered": true}], 1193 | "158:11": ["dropper", {"facing": "south", "triggered": true}], 1194 | "158:12": ["dropper", {"facing": "west", "triggered": true}], 1195 | "158:13": ["dropper", {"facing": "east", "triggered": true}], 1196 | 1197 | "159:0": ["white_terracotta", null], 1198 | "159:1": ["orange_terracotta", null], 1199 | "159:2": ["magenta_terracotta", null], 1200 | "159:3": ["light_blue_terracotta", null], 1201 | "159:4": ["yellow_terracotta", null], 1202 | "159:5": ["lime_terracotta", null], 1203 | "159:6": ["pink_terracotta", null], 1204 | "159:7": ["gray_terracotta", null], 1205 | "159:8": ["light_gray_terracotta", null], 1206 | "159:9": ["cyan_terracotta", null], 1207 | "159:10": ["purple_terracotta", null], 1208 | "159:11": ["blue_terracotta", null], 1209 | "159:12": ["brown_terracotta", null], 1210 | "159:13": ["green_terracotta", null], 1211 | "159:14": ["red_terracotta", null], 1212 | "159:15": ["black_terracotta", null], 1213 | 1214 | "160:0": ["white_stained_glass_pane", null], 1215 | "160:1": ["orange_stained_glass_pane", null], 1216 | "160:2": ["magenta_stained_glass_pane", null], 1217 | "160:3": ["light_blue_stained_glass_pane", null], 1218 | "160:4": ["yellow_stained_glass_pane", null], 1219 | "160:5": ["lime_stained_glass_pane", null], 1220 | "160:6": ["pink_stained_glass_pane", null], 1221 | "160:7": ["gray_stained_glass_pane", null], 1222 | "160:8": ["light_gray_stained_glass_pane", null], 1223 | "160:9": ["cyan_stained_glass_pane", null], 1224 | "160:10": ["purple_stained_glass_pane", null], 1225 | "160:11": ["blue_stained_glass_pane", null], 1226 | "160:12": ["brown_stained_glass_pane", null], 1227 | "160:13": ["green_stained_glass_pane", null], 1228 | "160:14": ["red_stained_glass_pane", null], 1229 | "160:15": ["black_stained_glass_pane", null], 1230 | 1231 | "161:0": ["acacia_leaves", {"persistent": false}], 1232 | "161:1": ["dark_oak_leaves", {"persistent": false}], 1233 | "161:4": ["acacia_leaves", {"persistent": true}], 1234 | "161:5": ["dark_oak_leaves", {"persistent": true}], 1235 | "161:8": ["acacia_leaves", {"persistent": false}], 1236 | "161:9": ["dark_oak_leaves", {"persistent": false}], 1237 | "161:12": ["acacia_leaves", {"persistent": true}], 1238 | "161:13": ["dark_oak_leaves", {"persistent": true}], 1239 | 1240 | "162:0": ["acacia_log", {"axis": "y"}], 1241 | "162:1": ["dark_oak_log", {"axis": "y"}], 1242 | "162:4": ["acacia_log", {"axis": "x"}], 1243 | "162:5": ["dark_oak_log", {"axis": "x"}], 1244 | "162:8": ["acacia_log", {"axis": "z"}], 1245 | "162:9": ["dark_oak_log", {"axis": "z"}], 1246 | "162:12": ["acacia_log", null], 1247 | "162:13": ["dark_oak_log", null], 1248 | 1249 | "163:0": ["acacia_stairs", {"facing": "east", "half": "bottom"}], 1250 | "163:1": ["acacia_stairs", {"facing": "west", "half": "bottom"}], 1251 | "163:2": ["acacia_stairs", {"facing": "south", "half": "bottom"}], 1252 | "163:3": ["acacia_stairs", {"facing": "north", "half": "bottom"}], 1253 | "163:4": ["acacia_stairs", {"facing": "east", "half": "top"}], 1254 | "163:5": ["acacia_stairs", {"facing": "west", "half": "top"}], 1255 | "163:6": ["acacia_stairs", {"facing": "south", "half": "top"}], 1256 | "163:7": ["acacia_stairs", {"facing": "north", "half": "top"}], 1257 | 1258 | "164:0": ["dark_oak_stairs", {"facing": "east", "half": "bottom"}], 1259 | "164:1": ["dark_oak_stairs", {"facing": "west", "half": "bottom"}], 1260 | "164:2": ["dark_oak_stairs", {"facing": "south", "half": "bottom"}], 1261 | "164:3": ["dark_oak_stairs", {"facing": "north", "half": "bottom"}], 1262 | "164:4": ["dark_oak_stairs", {"facing": "east", "half": "top"}], 1263 | "164:5": ["dark_oak_stairs", {"facing": "west", "half": "top"}], 1264 | "164:6": ["dark_oak_stairs", {"facing": "south", "half": "top"}], 1265 | "164:7": ["dark_oak_stairs", {"facing": "north", "half": "top"}], 1266 | 1267 | "165:0": ["slime_block", null], 1268 | "166:0": ["barrier", null], 1269 | 1270 | "167:0": ["iron_trapdoor", {"facing": "north", "open": false, "half": "bottom"}], 1271 | "167:1": ["iron_trapdoor", {"facing": "south", "open": false, "half": "bottom"}], 1272 | "167:2": ["iron_trapdoor", {"facing": "west", "open": false, "half": "bottom"}], 1273 | "167:3": ["iron_trapdoor", {"facing": "east", "open": false, "half": "bottom"}], 1274 | "167:4": ["iron_trapdoor", {"facing": "north", "open": true, "half": "bottom"}], 1275 | "167:5": ["iron_trapdoor", {"facing": "south", "open": true, "half": "bottom"}], 1276 | "167:6": ["iron_trapdoor", {"facing": "west", "open": true, "half": "bottom"}], 1277 | "167:7": ["iron_trapdoor", {"facing": "east", "open": true, "half": "bottom"}], 1278 | "167:8": ["iron_trapdoor", {"facing": "north", "open": false, "half": "top"}], 1279 | "167:9": ["iron_trapdoor", {"facing": "south", "open": false, "half": "top"}], 1280 | "167:10": ["iron_trapdoor", {"facing": "west", "open": false, "half": "top"}], 1281 | "167:11": ["iron_trapdoor", {"facing": "east", "open": false, "half": "top"}], 1282 | "167:12": ["iron_trapdoor", {"facing": "north", "open": true, "half": "top"}], 1283 | "167:13": ["iron_trapdoor", {"facing": "south", "open": true, "half": "top"}], 1284 | "167:14": ["iron_trapdoor", {"facing": "west", "open": true, "half": "top"}], 1285 | "167:15": ["iron_trapdoor", {"facing": "east", "open": true, "half": "top"}], 1286 | 1287 | "168:0": ["prismarine", null], 1288 | "168:1": ["prismarine_bricks", null], 1289 | "168:2": ["dark_prismarine", null], 1290 | "169:0": ["sea_lantern", null], 1291 | 1292 | "170:0": ["hay_block", {"axis": "y"}], 1293 | "170:4": ["hay_block", {"axis": "x"}], 1294 | "170:8": ["hay_block", {"axis": "z"}], 1295 | 1296 | "171:0": ["white_carpet", null], 1297 | "171:1": ["orange_carpet", null], 1298 | "171:2": ["magenta_carpet", null], 1299 | "171:3": ["light_blue_carpet", null], 1300 | "171:4": ["yellow_carpet", null], 1301 | "171:5": ["lime_carpet", null], 1302 | "171:6": ["pink_carpet", null], 1303 | "171:7": ["gray_carpet", null], 1304 | "171:8": ["light_gray_carpet", null], 1305 | "171:9": ["cyan_carpet", null], 1306 | "171:10": ["purple_carpet", null], 1307 | "171:11": ["blue_carpet", null], 1308 | "171:12": ["brown_carpet", null], 1309 | "171:13": ["green_carpet", null], 1310 | "171:14": ["red_carpet", null], 1311 | "171:15": ["black_carpet", null], 1312 | "172:0": ["terracotta", null], 1313 | "173:0": ["coal_block", null], 1314 | "174:0": ["packed_ice", null], 1315 | 1316 | "175:0": ["sunflower", {"half": "lower"}], 1317 | "175:1": ["lilac", {"half": "lower"}], 1318 | "175:2": ["tall_grass", {"half": "lower"}], 1319 | "175:3": ["large_fern", {"half": "lower"}], 1320 | "175:4": ["rose_bush", {"half": "lower"}], 1321 | "175:5": ["peony", {"half": "lower"}], 1322 | "175:8": ["sunflower", {"half": "upper"}], 1323 | "175:9": ["lilac", {"half": "upper"}], 1324 | "175:10": ["tall_grass", {"half": "upper"}], 1325 | "175:11": ["large_fern", {"half": "upper"}], 1326 | "175:12": ["rose_bush", {"half": "upper"}], 1327 | "175:13": ["peony", {"half": "upper"}], 1328 | 1329 | "176:0": ["banner", {"rotation": 0}], 1330 | "176:1": ["banner", {"rotation": 1}], 1331 | "176:2": ["banner", {"rotation": 2}], 1332 | "176:3": ["banner", {"rotation": 3}], 1333 | "176:4": ["banner", {"rotation": 4}], 1334 | "176:5": ["banner", {"rotation": 5}], 1335 | "176:6": ["banner", {"rotation": 6}], 1336 | "176:7": ["banner", {"rotation": 7}], 1337 | "176:8": ["banner", {"rotation": 8}], 1338 | "176:9": ["banner", {"rotation": 9}], 1339 | "176:10": ["banner", {"rotation": 10}], 1340 | "176:11": ["banner", {"rotation": 11}], 1341 | "176:12": ["banner", {"rotation": 12}], 1342 | "176:13": ["banner", {"rotation": 13}], 1343 | "176:14": ["banner", {"rotation": 14}], 1344 | "176:15": ["banner", {"rotation": 15}], 1345 | 1346 | "177:2": ["wall_banner", {"facing": "north"}], 1347 | "177:3": ["wall_banner", {"facing": "south"}], 1348 | "177:4": ["wall_banner", {"facing": "west"}], 1349 | "177:5": ["wall_banner", {"facing": "east"}], 1350 | 1351 | "178:0": ["daylight_detector", {"power": 0, "inverted": true}], 1352 | "178:1": ["daylight_detector", {"power": 1, "inverted": true}], 1353 | "178:2": ["daylight_detector", {"power": 2, "inverted": true}], 1354 | "178:3": ["daylight_detector", {"power": 3, "inverted": true}], 1355 | "178:4": ["daylight_detector", {"power": 4, "inverted": true}], 1356 | "178:5": ["daylight_detector", {"power": 5, "inverted": true}], 1357 | "178:6": ["daylight_detector", {"power": 6, "inverted": true}], 1358 | "178:7": ["daylight_detector", {"power": 7, "inverted": true}], 1359 | "178:8": ["daylight_detector", {"power": 8, "inverted": true}], 1360 | "178:9": ["daylight_detector", {"power": 9, "inverted": true}], 1361 | "178:10": ["daylight_detector", {"power": 10, "inverted": true}], 1362 | "178:11": ["daylight_detector", {"power": 11, "inverted": true}], 1363 | "178:12": ["daylight_detector", {"power": 12, "inverted": true}], 1364 | "178:13": ["daylight_detector", {"power": 13, "inverted": true}], 1365 | "178:14": ["daylight_detector", {"power": 14, "inverted": true}], 1366 | "178:15": ["daylight_detector", {"power": 15, "inverted": true}], 1367 | 1368 | "179:0": ["red_sandstone", null], 1369 | "179:1": ["chiseled_red_sandstone", null], 1370 | "179:2": ["cut_red_sandstone", null], 1371 | 1372 | "180:0": ["red_sandstone_stairs", {"facing": "east", "half": "bottom"}], 1373 | "180:1": ["red_sandstone_stairs", {"facing": "west", "half": "bottom"}], 1374 | "180:2": ["red_sandstone_stairs", {"facing": "south", "half": "bottom"}], 1375 | "180:3": ["red_sandstone_stairs", {"facing": "north", "half": "bottom"}], 1376 | "180:4": ["red_sandstone_stairs", {"facing": "east", "half": "top"}], 1377 | "180:5": ["red_sandstone_stairs", {"facing": "west", "half": "top"}], 1378 | "180:6": ["red_sandstone_stairs", {"facing": "south", "half": "top"}], 1379 | "180:7": ["red_sandstone_stairs", {"facing": "north", "half": "top"}], 1380 | 1381 | "181:0": ["red_sandstone", null], 1382 | "181:1": ["purpur_block", null], 1383 | "181:2": ["prismarine", null], 1384 | "181:3": ["prismarine_bricks", null], 1385 | "181:4": ["dark_prismarine", null], 1386 | 1387 | "182:0": ["red_sandstone_slab", {"type": "bottom"}], 1388 | "182:8": ["red_sandstone_slab", {"type": "top"}], 1389 | 1390 | "183:0": ["spruce_fence_gate", {"facing": "south", "open": false, "powered": false}], 1391 | "183:1": ["spruce_fence_gate", {"facing": "west", "open": false, "powered": false}], 1392 | "183:2": ["spruce_fence_gate", {"facing": "north", "open": false, "powered": false}], 1393 | "183:3": ["spruce_fence_gate", {"facing": "east", "open": false, "powered": false}], 1394 | "183:4": ["spruce_fence_gate", {"facing": "south", "open": true, "powered": false}], 1395 | "183:5": ["spruce_fence_gate", {"facing": "west", "open": true, "powered": false}], 1396 | "183:6": ["spruce_fence_gate", {"facing": "north", "open": true, "powered": false}], 1397 | "183:7": ["spruce_fence_gate", {"facing": "east", "open": true, "powered": false}], 1398 | "183:8": ["spruce_fence_gate", {"facing": "south", "open": false, "powered": true}], 1399 | "183:9": ["spruce_fence_gate", {"facing": "west", "open": false, "powered": true}], 1400 | "183:10": ["spruce_fence_gate", {"facing": "north", "open": false, "powered": true}], 1401 | "183:11": ["spruce_fence_gate", {"facing": "east", "open": false, "powered": true}], 1402 | "183:12": ["spruce_fence_gate", {"facing": "south", "open": true, "powered": true}], 1403 | "183:13": ["spruce_fence_gate", {"facing": "west", "open": true, "powered": true}], 1404 | "183:14": ["spruce_fence_gate", {"facing": "north", "open": true, "powered": true}], 1405 | "183:15": ["spruce_fence_gate", {"facing": "east", "open": true, "powered": true}], 1406 | 1407 | "184:0": ["birch_fence_gate", {"facing": "south", "open": false, "powered": false}], 1408 | "184:1": ["birch_fence_gate", {"facing": "west", "open": false, "powered": false}], 1409 | "184:2": ["birch_fence_gate", {"facing": "north", "open": false, "powered": false}], 1410 | "184:3": ["birch_fence_gate", {"facing": "east", "open": false, "powered": false}], 1411 | "184:4": ["birch_fence_gate", {"facing": "south", "open": true, "powered": false}], 1412 | "184:5": ["birch_fence_gate", {"facing": "west", "open": true, "powered": false}], 1413 | "184:6": ["birch_fence_gate", {"facing": "north", "open": true, "powered": false}], 1414 | "184:7": ["birch_fence_gate", {"facing": "east", "open": true, "powered": false}], 1415 | "184:8": ["birch_fence_gate", {"facing": "south", "open": false, "powered": true}], 1416 | "184:9": ["birch_fence_gate", {"facing": "west", "open": false, "powered": true}], 1417 | "184:10": ["birch_fence_gate", {"facing": "north", "open": false, "powered": true}], 1418 | "184:11": ["birch_fence_gate", {"facing": "east", "open": false, "powered": true}], 1419 | "184:12": ["birch_fence_gate", {"facing": "south", "open": true, "powered": true}], 1420 | "184:13": ["birch_fence_gate", {"facing": "west", "open": true, "powered": true}], 1421 | "184:14": ["birch_fence_gate", {"facing": "north", "open": true, "powered": true}], 1422 | "184:15": ["birch_fence_gate", {"facing": "east", "open": true, "powered": true}], 1423 | 1424 | "185:0": ["jungle_fence_gate", {"facing": "south", "open": false, "powered": false}], 1425 | "185:1": ["jungle_fence_gate", {"facing": "west", "open": false, "powered": false}], 1426 | "185:2": ["jungle_fence_gate", {"facing": "north", "open": false, "powered": false}], 1427 | "185:3": ["jungle_fence_gate", {"facing": "east", "open": false, "powered": false}], 1428 | "185:4": ["jungle_fence_gate", {"facing": "south", "open": true, "powered": false}], 1429 | "185:5": ["jungle_fence_gate", {"facing": "west", "open": true, "powered": false}], 1430 | "185:6": ["jungle_fence_gate", {"facing": "north", "open": true, "powered": false}], 1431 | "185:7": ["jungle_fence_gate", {"facing": "east", "open": true, "powered": false}], 1432 | "185:8": ["jungle_fence_gate", {"facing": "west", "open": false, "powered": true}], 1433 | "185:9": ["jungle_fence_gate", {"facing": "west", "open": false, "powered": true}], 1434 | "185:10": ["jungle_fence_gate", {"facing": "north", "open": false, "powered": true}], 1435 | "185:11": ["jungle_fence_gate", {"facing": "east", "open": false, "powered": true}], 1436 | "185:12": ["jungle_fence_gate", {"facing": "south", "open": true, "powered": true}], 1437 | "185:13": ["jungle_fence_gate", {"facing": "west", "open": true, "powered": true}], 1438 | "185:14": ["jungle_fence_gate", {"facing": "north", "open": true, "powered": true}], 1439 | "185:15": ["jungle_fence_gate", {"facing": "east", "open": true, "powered": true}], 1440 | 1441 | "186:0": ["dark_oak_fence_gate", {"facing": "south", "open": false, "powered": false}], 1442 | "186:1": ["dark_oak_fence_gate", {"facing": "west", "open": false, "powered": false}], 1443 | "186:2": ["dark_oak_fence_gate", {"facing": "north", "open": false, "powered": false}], 1444 | "186:3": ["dark_oak_fence_gate", {"facing": "east", "open": false, "powered": false}], 1445 | "186:4": ["dark_oak_fence_gate", {"facing": "south", "open": true, "powered": false}], 1446 | "186:5": ["dark_oak_fence_gate", {"facing": "west", "open": true, "powered": false}], 1447 | "186:6": ["dark_oak_fence_gate", {"facing": "north", "open": true, "powered": false}], 1448 | "186:7": ["dark_oak_fence_gate", {"facing": "east", "open": true, "powered": false}], 1449 | "186:8": ["dark_oak_fence_gate", {"facing": "south", "open": false, "powered": true}], 1450 | "186:9": ["dark_oak_fence_gate", {"facing": "west", "open": false, "powered": true}], 1451 | "186:10": ["dark_oak_fence_gate", {"facing": "north", "open": false, "powered": true}], 1452 | "186:11": ["dark_oak_fence_gate", {"facing": "east", "open": false, "powered": true}], 1453 | "186:12": ["dark_oak_fence_gate", {"facing": "south", "open": true, "powered": true}], 1454 | "186:13": ["dark_oak_fence_gate", {"facing": "west", "open": true, "powered": true}], 1455 | "186:14": ["dark_oak_fence_gate", {"facing": "north", "open": true, "powered": true}], 1456 | "186:15": ["dark_oak_fence_gate", {"facing": "east", "open": true, "powered": true}], 1457 | 1458 | "187:0": ["acacia_fence_gate", {"facing": "south", "open": false, "powered": false}], 1459 | "187:1": ["acacia_fence_gate", {"facing": "west", "open": false, "powered": false}], 1460 | "187:2": ["acacia_fence_gate", {"facing": "north", "open": false, "powered": false}], 1461 | "187:3": ["acacia_fence_gate", {"facing": "east", "open": false, "powered": false}], 1462 | "187:4": ["acacia_fence_gate", {"facing": "south", "open": true, "powered": false}], 1463 | "187:5": ["acacia_fence_gate", {"facing": "west", "open": true, "powered": false}], 1464 | "187:6": ["acacia_fence_gate", {"facing": "north", "open": true, "powered": false}], 1465 | "187:7": ["acacia_fence_gate", {"facing": "east", "open": true, "powered": false}], 1466 | "187:8": ["acacia_fence_gate", {"facing": "south", "open": false, "powered": true}], 1467 | "187:9": ["acacia_fence_gate", {"facing": "west", "open": false, "powered": true}], 1468 | "187:10": ["acacia_fence_gate", {"facing": "north", "open": false, "powered": true}], 1469 | "187:11": ["acacia_fence_gate", {"facing": "east", "open": false, "powered": true}], 1470 | "187:12": ["acacia_fence_gate", {"facing": "south", "open": true, "powered": true}], 1471 | "187:13": ["acacia_fence_gate", {"facing": "west", "open": true, "powered": true}], 1472 | "187:14": ["acacia_fence_gate", {"facing": "north", "open": true, "powered": true}], 1473 | "187:15": ["acacia_fence_gate", {"facing": "east", "open": true, "powered": true}], 1474 | 1475 | "188:0": ["spruce_fence", null], 1476 | "189:0": ["birch_fence", null], 1477 | "190:0": ["jungle_fence", null], 1478 | "191:0": ["dark_oak_fence", null], 1479 | "192:0": ["acacia_fence", null], 1480 | 1481 | "193:0": ["spruce_door", {"half": "lower", "facing": "east", "open": false}], 1482 | "193:1": ["spruce_door", {"half": "lower", "facing": "south", "open": false}], 1483 | "193:2": ["spruce_door", {"half": "lower", "facing": "west", "open": false}], 1484 | "193:3": ["spruce_door", {"half": "lower", "facing": "north", "open": false}], 1485 | "193:4": ["spruce_door", {"half": "lower", "facing": "east", "open": true}], 1486 | "193:5": ["spruce_door", {"half": "lower", "facing": "south", "open": true}], 1487 | "193:6": ["spruce_door", {"half": "lower", "facing": "west", "open": true}], 1488 | "193:7": ["spruce_door", {"half": "lower", "facing": "north", "open": true}], 1489 | 1490 | "193:8": ["spruce_door", {"half": "upper", "hinge": "left", "powered": false}], 1491 | "193:9": ["spruce_door", {"half": "upper", "hinge": "right", "powered": false}], 1492 | "193:10": ["spruce_door", {"half": "upper", "hinge": "left", "powered": true}], 1493 | "193:11": ["spruce_door", {"half": "upper", "hinge": "right", "powered": true}], 1494 | 1495 | "194:0": ["birch_door", {"half": "lower", "facing": "east", "open": false}], 1496 | "194:1": ["birch_door", {"half": "lower", "facing": "south", "open": false}], 1497 | "194:2": ["birch_door", {"half": "lower", "facing": "west", "open": false}], 1498 | "194:3": ["birch_door", {"half": "lower", "facing": "north", "open": false}], 1499 | "194:4": ["birch_door", {"half": "lower", "facing": "east", "open": true}], 1500 | "194:5": ["birch_door", {"half": "lower", "facing": "south", "open": true}], 1501 | "194:6": ["birch_door", {"half": "lower", "facing": "west", "open": true}], 1502 | "194:7": ["birch_door", {"half": "lower", "facing": "north", "open": true}], 1503 | 1504 | "194:8": ["birch_door", {"half": "upper", "hinge": "left", "powered": false}], 1505 | "194:9": ["birch_door", {"half": "upper", "hinge": "right", "powered": false}], 1506 | "194:10": ["birch_door", {"half": "upper", "hinge": "left", "powered": true}], 1507 | "194:11": ["birch_door", {"half": "upper", "hinge": "right", "powered": true}], 1508 | 1509 | "195:0": ["jungle_door", {"half": "lower", "facing": "east", "open": false}], 1510 | "195:1": ["jungle_door", {"half": "lower", "facing": "south", "open": false}], 1511 | "195:2": ["jungle_door", {"half": "lower", "facing": "west", "open": false}], 1512 | "195:3": ["jungle_door", {"half": "lower", "facing": "north", "open": false}], 1513 | "195:4": ["jungle_door", {"half": "lower", "facing": "east", "open": true}], 1514 | "195:5": ["jungle_door", {"half": "lower", "facing": "south", "open": true}], 1515 | "195:6": ["jungle_door", {"half": "lower", "facing": "west", "open": true}], 1516 | "195:7": ["jungle_door", {"half": "lower", "facing": "north", "open": true}], 1517 | 1518 | "195:8": ["jungle_door", {"half": "upper", "hinge": "left", "powered": false}], 1519 | "195:9": ["jungle_door", {"half": "upper", "hinge": "right", "powered": false}], 1520 | "195:10": ["jungle_door", {"half": "upper", "hinge": "left", "powered": true}], 1521 | "195:11": ["jungle_door", {"half": "upper", "hinge": "right", "powered": true}], 1522 | 1523 | "196:0": ["acacia_door", {"half": "lower", "facing": "east", "open": false}], 1524 | "196:1": ["acacia_door", {"half": "lower", "facing": "south", "open": false}], 1525 | "196:2": ["acacia_door", {"half": "lower", "facing": "west", "open": false}], 1526 | "196:3": ["acacia_door", {"half": "lower", "facing": "north", "open": false}], 1527 | "196:4": ["acacia_door", {"half": "lower", "facing": "east", "open": true}], 1528 | "196:5": ["acacia_door", {"half": "lower", "facing": "south", "open": true}], 1529 | "196:6": ["acacia_door", {"half": "lower", "facing": "west", "open": true}], 1530 | "196:7": ["acacia_door", {"half": "lower", "facing": "north", "open": true}], 1531 | 1532 | "196:8": ["acacia_door", {"half": "upper", "hinge": "left", "powered": false}], 1533 | "196:9": ["acacia_door", {"half": "upper", "hinge": "right", "powered": false}], 1534 | "196:10": ["acacia_door", {"half": "upper", "hinge": "left", "powered": true}], 1535 | "196:11": ["acacia_door", {"half": "upper", "hinge": "right", "powered": true}], 1536 | 1537 | "197:0": ["dark_oak_door", {"half": "lower", "facing": "east", "open": false}], 1538 | "197:1": ["dark_oak_door", {"half": "lower", "facing": "south", "open": false}], 1539 | "197:2": ["dark_oak_door", {"half": "lower", "facing": "west", "open": false}], 1540 | "197:3": ["dark_oak_door", {"half": "lower", "facing": "north", "open": false}], 1541 | "197:4": ["dark_oak_door", {"half": "lower", "facing": "east", "open": true}], 1542 | "197:5": ["dark_oak_door", {"half": "lower", "facing": "south", "open": true}], 1543 | "197:6": ["dark_oak_door", {"half": "lower", "facing": "west", "open": true}], 1544 | "197:7": ["dark_oak_door", {"half": "lower", "facing": "north", "open": true}], 1545 | 1546 | "197:8": ["dark_oak_door", {"half": "upper", "hinge": "left", "powered": false}], 1547 | "197:9": ["dark_oak_door", {"half": "upper", "hinge": "right", "powered": false}], 1548 | "197:10": ["dark_oak_door", {"half": "upper", "hinge": "left", "powered": true}], 1549 | "197:11": ["dark_oak_door", {"half": "upper", "hinge": "right", "powered": true}], 1550 | 1551 | "198:0": ["end_rod", {"facing": "down"}], 1552 | "198:1": ["end_rod", {"facing": "up"}], 1553 | "198:2": ["end_rod", {"facing": "north"}], 1554 | "198:3": ["end_rod", {"facing": "south"}], 1555 | "198:4": ["end_rod", {"facing": "west"}], 1556 | "198:5": ["end_rod", {"facing": "east"}], 1557 | 1558 | "199:0": ["chorus_plant", null], 1559 | 1560 | "200:0": ["chorus_flower", {"age": 0}], 1561 | "200:1": ["chorus_flower", {"age": 1}], 1562 | "200:2": ["chorus_flower", {"age": 2}], 1563 | "200:3": ["chorus_flower", {"age": 3}], 1564 | "200:4": ["chorus_flower", {"age": 4}], 1565 | "200:5": ["chorus_flower", {"age": 5}], 1566 | 1567 | "201:0": ["purpur_block", null], 1568 | 1569 | "202:0": ["purpur_pillar", {"axis": "y"}], 1570 | "202:4": ["purpur_pillar", {"axis": "x"}], 1571 | "202:8": ["purpur_pillar", {"axis": "z"}], 1572 | 1573 | "203:0": ["purpur_stairs", {"facing": "east", "half": "bottom"}], 1574 | "203:1": ["purpur_stairs", {"facing": "west", "half": "bottom"}], 1575 | "203:2": ["purpur_stairs", {"facing": "south", "half": "bottom"}], 1576 | "203:3": ["purpur_stairs", {"facing": "north", "half": "bottom"}], 1577 | "203:4": ["purpur_stairs", {"facing": "east", "half": "top"}], 1578 | "203:5": ["purpur_stairs", {"facing": "west", "half": "top"}], 1579 | "203:6": ["purpur_stairs", {"facing": "south", "half": "top"}], 1580 | "203:7": ["purpur_stairs", {"facing": "north", "half": "top"}], 1581 | 1582 | "204:0": ["purpur_slab", {"type": "double"}], 1583 | 1584 | "205:0": ["purpur_slab", {"type": "bottom"}], 1585 | "205:8": ["purpur_slab", {"type": "top"}], 1586 | 1587 | "206:0": ["end_stone_bricks", null], 1588 | 1589 | "207:0": ["beetroots", {"age": 0}], 1590 | "207:1": ["beetroots", {"age": 1}], 1591 | "207:2": ["beetroots", {"age": 2}], 1592 | "207:3": ["beetroots", {"age": 3}], 1593 | 1594 | "208:0": ["grass_path", null], 1595 | "209:0": ["end_gateway", null], 1596 | "210:0": ["repeating_command_block", null], 1597 | "211:0": ["chain_command_block", null], 1598 | "212:0": ["frosted_ice", null], 1599 | "213:0": ["magma_block", null], 1600 | "214:0": ["nether_wart_block", null], 1601 | 1602 | "216:0": ["bone_block", {"axis": "y"}], 1603 | "216:4": ["bone_block", {"axis": "x"}], 1604 | "216:8": ["bone_block", {"axis": "z"}], 1605 | 1606 | "215:0": ["red_nether_bricks", null], 1607 | "217:0": ["structure_void", null], 1608 | 1609 | "218:0": ["observer", {"facing": "down", "powered": false}], 1610 | "218:1": ["observer", {"facing": "up", "powered": false}], 1611 | "218:2": ["observer", {"facing": "north", "powered": false}], 1612 | "218:3": ["observer", {"facing": "south", "powered": false}], 1613 | "218:4": ["observer", {"facing": "west", "powered": false}], 1614 | "218:5": ["observer", {"facing": "east", "powered": false}], 1615 | "218:6": ["observer", {"facing": "down", "powered": true}], 1616 | "218:7": ["observer", {"facing": "up", "powered": true}], 1617 | "218:8": ["observer", {"facing": "north", "powered": true}], 1618 | "218:9": ["observer", {"facing": "south", "powered": true}], 1619 | "218:10": ["observer", {"facing": "west", "powered": true}], 1620 | "218:11": ["observer", {"facing": "east", "powered": true}], 1621 | 1622 | "219:0": ["white_shulker_box", {"facing": "down"}], 1623 | "219:1": ["white_shulker_box", {"facing": "up"}], 1624 | "219:2": ["white_shulker_box", {"facing": "north"}], 1625 | "219:3": ["white_shulker_box", {"facing": "south"}], 1626 | "219:4": ["white_shulker_box", {"facing": "west"}], 1627 | "219:5": ["white_shulker_box", {"facing": "east"}], 1628 | 1629 | "220:0": ["orange_shulker_box", {"facing": "down"}], 1630 | "220:1": ["orange_shulker_box", {"facing": "up"}], 1631 | "220:2": ["orange_shulker_box", {"facing": "north"}], 1632 | "220:3": ["orange_shulker_box", {"facing": "south"}], 1633 | "220:4": ["orange_shulker_box", {"facing": "west"}], 1634 | "220:5": ["orange_shulker_box", {"facing": "east"}], 1635 | 1636 | "221:0": ["magenta_shulker_box", {"facing": "down"}], 1637 | "221:1": ["magenta_shulker_box", {"facing": "up"}], 1638 | "221:2": ["magenta_shulker_box", {"facing": "north"}], 1639 | "221:3": ["magenta_shulker_box", {"facing": "south"}], 1640 | "221:4": ["magenta_shulker_box", {"facing": "west"}], 1641 | "221:5": ["magenta_shulker_box", {"facing": "east"}], 1642 | 1643 | "222:0": ["light_blue_shulker_box", {"facing": "down"}], 1644 | "222:1": ["light_blue_shulker_box", {"facing": "up"}], 1645 | "222:2": ["light_blue_shulker_box", {"facing": "north"}], 1646 | "222:3": ["light_blue_shulker_box", {"facing": "south"}], 1647 | "222:4": ["light_blue_shulker_box", {"facing": "west"}], 1648 | "222:5": ["light_blue_shulker_box", {"facing": "east"}], 1649 | 1650 | "223:0": ["yellow_shulker_box", {"facing": "down"}], 1651 | "223:1": ["yellow_shulker_box", {"facing": "up"}], 1652 | "223:2": ["yellow_shulker_box", {"facing": "north"}], 1653 | "223:3": ["yellow_shulker_box", {"facing": "south"}], 1654 | "223:4": ["yellow_shulker_box", {"facing": "west"}], 1655 | "223:5": ["yellow_shulker_box", {"facing": "east"}], 1656 | 1657 | "224:0": ["lime_shulker_box", {"facing": "down"}], 1658 | "224:1": ["lime_shulker_box", {"facing": "up"}], 1659 | "224:2": ["lime_shulker_box", {"facing": "north"}], 1660 | "224:3": ["lime_shulker_box", {"facing": "south"}], 1661 | "224:4": ["lime_shulker_box", {"facing": "west"}], 1662 | "224:5": ["lime_shulker_box", {"facing": "east"}], 1663 | 1664 | "225:0": ["pink_shulker_box", {"facing": "down"}], 1665 | "225:1": ["pink_shulker_box", {"facing": "up"}], 1666 | "225:2": ["pink_shulker_box", {"facing": "north"}], 1667 | "225:3": ["pink_shulker_box", {"facing": "south"}], 1668 | "225:4": ["pink_shulker_box", {"facing": "west"}], 1669 | "225:5": ["pink_shulker_box", {"facing": "east"}], 1670 | 1671 | "226:0": ["gray_shulker_box", {"facing": "down"}], 1672 | "226:1": ["gray_shulker_box", {"facing": "up"}], 1673 | "226:2": ["gray_shulker_box", {"facing": "north"}], 1674 | "226:3": ["gray_shulker_box", {"facing": "south"}], 1675 | "226:4": ["gray_shulker_box", {"facing": "west"}], 1676 | "226:5": ["gray_shulker_box", {"facing": "east"}], 1677 | 1678 | "227:0": ["light_gray_shulker_box", {"facing": "down"}], 1679 | "227:1": ["light_gray_shulker_box", {"facing": "up"}], 1680 | "227:2": ["light_gray_shulker_box", {"facing": "north"}], 1681 | "227:3": ["light_gray_shulker_box", {"facing": "south"}], 1682 | "227:4": ["light_gray_shulker_box", {"facing": "west"}], 1683 | "227:5": ["light_gray_shulker_box", {"facing": "east"}], 1684 | 1685 | "228:0": ["cyan_shulker_box", { "facing": "down"}], 1686 | "228:1": ["cyan_shulker_box", {"facing": "up"}], 1687 | "228:2": ["cyan_shulker_box", {"facing": "north"}], 1688 | "228:3": ["cyan_shulker_box", {"facing": "south"}], 1689 | "228:4": ["cyan_shulker_box", {"facing": "west"}], 1690 | "228:5": ["cyan_shulker_box", {"facing": "east"}], 1691 | 1692 | "229:0": ["purple_shulker_box", {"facing": "down"}], 1693 | "229:1": ["purple_shulker_box", {"facing": "up"}], 1694 | "229:2": ["purple_shulker_box", {"facing": "north"}], 1695 | "229:3": ["purple_shulker_box", {"facing": "south"}], 1696 | "229:4": ["purple_shulker_box", {"facing": "west"}], 1697 | "229:5": ["purple_shulker_box", {"facing": "east"}], 1698 | 1699 | "230:0": ["blue_shulker_box", {"facing": "down"}], 1700 | "230:1": ["blue_shulker_box", {"facing": "up"}], 1701 | "230:2": ["blue_shulker_box", {"facing": "north"}], 1702 | "230:3": ["blue_shulker_box", {"facing": "south"}], 1703 | "230:4": ["blue_shulker_box", {"facing": "west"}], 1704 | "230:5": ["blue_shulker_box", {"facing": "east"}], 1705 | 1706 | "231:0": ["brown_shulker_box", {"facing": "down"}], 1707 | "231:1": ["brown_shulker_box", {"facing": "up"}], 1708 | "231:2": ["brown_shulker_box", {"facing": "north"}], 1709 | "231:3": ["brown_shulker_box", {"facing": "south"}], 1710 | "231:4": ["brown_shulker_box", {"facing": "west"}], 1711 | "231:5": ["brown_shulker_box", {"facing": "east"}], 1712 | 1713 | "232:0": ["green_shulker_box", {"facing": "down"}], 1714 | "232:1": ["green_shulker_box", {"facing": "up"}], 1715 | "232:2": ["green_shulker_box", {"facing": "north"}], 1716 | "232:3": ["green_shulker_box", {"facing": "south"}], 1717 | "232:4": ["green_shulker_box", {"facing": "west"}], 1718 | "232:5": ["green_shulker_box", {"facing": "east"}], 1719 | 1720 | "233:0": ["red_shulker_box", {"facing": "down"}], 1721 | "233:1": ["red_shulker_box", {"facing": "up"}], 1722 | "233:2": ["red_shulker_box", {"facing": "north"}], 1723 | "233:3": ["red_shulker_box", {"facing": "south"}], 1724 | "233:4": ["red_shulker_box", {"facing": "west"}], 1725 | "233:5": ["red_shulker_box", {"facing": "east"}], 1726 | 1727 | "234:0": ["black_shulker_box", {"facing": "up"}], 1728 | "233:1": ["black_shulker_box", {"facing": "up"}], 1729 | "234:2": ["black_shulker_box", {"facing": "north"}], 1730 | "234:3": ["black_shulker_box", {"facing": "south"}], 1731 | "234:4": ["black_shulker_box", {"facing": "west"}], 1732 | "234:5": ["black_shulker_box", {"facing": "east"}], 1733 | 1734 | 1735 | "235:0": ["white_glazed_terracotta", {"facing": "south"}], 1736 | "235:1": ["white_glazed_terracotta", {"facing": "west"}], 1737 | "235:2": ["white_glazed_terracotta", {"facing": "north"}], 1738 | "235:3": ["white_glazed_terracotta", {"facing": "east"}], 1739 | 1740 | "236:0": ["orange_glazed_terracotta", {"facing": "south"}], 1741 | "236:1": ["orange_glazed_terracotta", {"facing": "west"}], 1742 | "236:2": ["orange_glazed_terracotta", {"facing": "north"}], 1743 | "236:3": ["orange_glazed_terracotta", {"facing": "east"}], 1744 | 1745 | "237:0": ["magenta_glazed_terracotta", {"facing": "south"}], 1746 | "237:1": ["magenta_glazed_terracotta", {"facing": "west"}], 1747 | "237:2": ["magenta_glazed_terracotta", {"facing": "north"}], 1748 | "237:3": ["magenta_glazed_terracotta", {"facing": "east"}], 1749 | 1750 | "238:0": ["light_blue_glazed_terracotta", {"facing": "south"}], 1751 | "238:1": ["light_blue_glazed_terracotta", {"facing": "west"}], 1752 | "238:2": ["light_blue_glazed_terracotta", {"facing": "north"}], 1753 | "238:3": ["light_blue_glazed_terracotta", {"facing": "east"}], 1754 | 1755 | "239:0": ["yellow_glazed_terracotta", {"facing": "south"}], 1756 | "239:1": ["yellow_glazed_terracotta", {"facing": "west"}], 1757 | "239:2": ["yellow_glazed_terracotta", {"facing": "north"}], 1758 | "239:3": ["yellow_glazed_terracotta", {"facing": "east"}], 1759 | 1760 | "240:0": ["lime_glazed_terracotta", {"facing": "south"}], 1761 | "240:1": ["lime_glazed_terracotta", {"facing": "west"}], 1762 | "240:2": ["lime_glazed_terracotta", {"facing": "north"}], 1763 | "240:3": ["lime_glazed_terracotta", {"facing": "east"}], 1764 | 1765 | "241:0": ["pink_glazed_terracotta", {"facing": "south"}], 1766 | "241:1": ["pink_glazed_terracotta", {"facing": "west"}], 1767 | "241:2": ["pink_glazed_terracotta", {"facing": "north"}], 1768 | "241:3": ["pink_glazed_terracotta", {"facing": "east"}], 1769 | 1770 | "242:0": ["gray_glazed_terracotta", {"facing": "south"}], 1771 | "242:1": ["gray_glazed_terracotta", {"facing": "west"}], 1772 | "242:2": ["gray_glazed_terracotta", {"facing": "north"}], 1773 | "242:3": ["gray_glazed_terracotta", {"facing": "east"}], 1774 | 1775 | "243:0": ["light_gray_glazed_terracotta", {"facing": "south"}], 1776 | "243:1": ["light_gray_glazed_terracotta", {"facing": "west"}], 1777 | "243:2": ["light_gray_glazed_terracotta", {"facing": "north"}], 1778 | "243:3": ["light_gray_glazed_terracotta", {"facing": "east"}], 1779 | 1780 | "244:0": ["cyan_glazed_terracotta", {"facing": "south"}], 1781 | "244:1": ["cyan_glazed_terracotta", {"facing": "west"}], 1782 | "244:2": ["cyan_glazed_terracotta", {"facing": "north"}], 1783 | "244:3": ["cyan_glazed_terracotta", {"facing": "east"}], 1784 | 1785 | "245:0": ["purple_glazed_terracotta", {"facing": "south"}], 1786 | "245:1": ["purple_glazed_terracotta", {"facing": "west"}], 1787 | "245:2": ["purple_glazed_terracotta", {"facing": "north"}], 1788 | "245:3": ["purple_glazed_terracotta", {"facing": "east"}], 1789 | 1790 | "246:0": ["blue_glazed_terracotta", {"facing": "south"}], 1791 | "246:1": ["blue_glazed_terracotta", {"facing": "west"}], 1792 | "246:2": ["blue_glazed_terracotta", {"facing": "north"}], 1793 | "246:3": ["blue_glazed_terracotta", {"facing": "east"}], 1794 | 1795 | "247:0": ["brown_glazed_terracotta", {"facing": "south"}], 1796 | "247:1": ["brown_glazed_terracotta", {"facing": "west"}], 1797 | "247:2": ["brown_glazed_terracotta", {"facing": "north"}], 1798 | "247:3": ["brown_glazed_terracotta", {"facing": "east"}], 1799 | 1800 | "248:0": ["green_glazed_terracotta", {"facing": "south"}], 1801 | "248:1": ["green_glazed_terracotta", {"facing": "west"}], 1802 | "248:2": ["green_glazed_terracotta", {"facing": "north"}], 1803 | "248:3": ["green_glazed_terracotta", {"facing": "east"}], 1804 | 1805 | "249:0": ["red_glazed_terracotta", {"facing": "south"}], 1806 | "249:1": ["red_glazed_terracotta", {"facing": "west"}], 1807 | "249:2": ["red_glazed_terracotta", {"facing": "north"}], 1808 | "249:3": ["red_glazed_terracotta", {"facing": "east"}], 1809 | 1810 | "250:0": ["black_glazed_terracotta", {"facing": "south"}], 1811 | "250:1": ["black_glazed_terracotta", {"facing": "west"}], 1812 | "250:2": ["black_glazed_terracotta", {"facing": "north"}], 1813 | "250:3": ["black_glazed_terracotta", {"facing": "east"}], 1814 | 1815 | "251:0": ["white_concrete", null], 1816 | "251:1": ["orange_concrete", null], 1817 | "251:2": ["magenta_concrete", null], 1818 | "251:3": ["light_blue_concrete", null], 1819 | "251:4": ["yellow_concrete", null], 1820 | "251:5": ["lime_concrete", null], 1821 | "251:6": ["pink_concrete", null], 1822 | "251:7": ["gray_concrete", null], 1823 | "251:8": ["light_gray_concrete", null], 1824 | "251:9": ["cyan_concrete", null], 1825 | "251:10": ["purple_concrete", null], 1826 | "251:11": ["blue_concrete", null], 1827 | "251:12": ["brown_concrete", null], 1828 | "251:13": ["green_concrete", null], 1829 | "251:14": ["red_concrete", null], 1830 | "251:15": ["black_concrete", null], 1831 | "252:0": ["white_concrete_powder", null], 1832 | "252:1": ["orange_concrete_powder", null], 1833 | "252:2": ["magenta_concrete_powder", null], 1834 | "252:3": ["light_blue_concrete_powder", null], 1835 | "252:4": ["yellow_concrete_powder", null], 1836 | "252:5": ["lime_concrete_powder", null], 1837 | "252:6": ["pink_concrete_powder", null], 1838 | "252:7": ["gray_concrete_powder", null], 1839 | "252:8": ["light_gray_concrete_powder", null], 1840 | "252:9": ["cyan_concrete_powder", null], 1841 | "252:10": ["purple_concrete_powder", null], 1842 | "252:11": ["blue_concrete_powder", null], 1843 | "252:12": ["brown_concrete_powder", null], 1844 | "252:13": ["green_concrete_powder", null], 1845 | "252:14": ["red_concrete_powder", null], 1846 | "252:15": ["black_concrete_powder", null], 1847 | 1848 | "255:0": ["structure_block", {"mode": "save"}], 1849 | "255:1": ["structure_block", {"mode": "load"}], 1850 | "255:2": ["structure_block", {"mode": "data"}], 1851 | "255:3": ["structure_block", {"mode": "corner"}] 1852 | } 1853 | -------------------------------------------------------------------------------- /anvil/raw_section.py: -------------------------------------------------------------------------------- 1 | from typing import List, Tuple, Sequence, Iterable 2 | from . import EmptySection, Block 3 | from .errors import OutOfBoundsCoordinates 4 | import array 5 | from nbt import nbt 6 | 7 | def bin_append(a, b, length=None): 8 | length = length or b.bit_length() 9 | return (a << length) | b 10 | 11 | class RawSection: 12 | """ 13 | Same as :class:`EmptySection` but you manually 14 | set the palette and the blocks array (which instead 15 | of :class:`Block`, it's indexes on the palette) 16 | 17 | Attributes 18 | ---------- 19 | y: :class:`int` 20 | Section's Y index 21 | blocks: Iterable[:class:`int`] 22 | Array of palette indexes 23 | _palette: Sequence[:class:`Block`] 24 | Section's palette 25 | """ 26 | __slots__ = ('y', '_palette', 'blocks') 27 | def __init__(self, y: int, blocks: Iterable[int], palette: Sequence[Block]): 28 | self.y = y 29 | self.blocks: Iterable[int] = blocks 30 | self._palette: Sequence[Block] = palette 31 | 32 | def palette(self) -> Sequence[Block]: 33 | """Returns ``self._palette``""" 34 | return self._palette 35 | 36 | def blockstates(self, palette: Sequence[Block]=None) -> array.array: 37 | """Refer to :class:`EmptySection.blockstates()`""" 38 | bits = max((len(self._palette) - 1).bit_length(), 4) 39 | states = array.array('Q') 40 | current = 0 41 | current_len = 0 42 | for index in self.blocks: 43 | if current_len + bits > 64: 44 | leftover = 64 - current_len 45 | states.append(bin_append(index & ((1 << leftover) - 1), current, length=current_len)) 46 | current = index >> leftover 47 | current_len = bits - leftover 48 | else: 49 | current = bin_append(index, current, length=current_len) 50 | current_len += bits 51 | states.append(current) 52 | return states 53 | 54 | def save(self) -> nbt.TAG_Compound: 55 | """Refer to :class:`EmptySection.save()`""" 56 | return EmptySection.save(self) 57 | -------------------------------------------------------------------------------- /anvil/region.py: -------------------------------------------------------------------------------- 1 | from typing import Tuple, Union, BinaryIO 2 | from nbt import nbt 3 | import zlib 4 | from io import BytesIO 5 | import anvil 6 | from .errors import GZipChunkData 7 | 8 | class Region: 9 | """ 10 | Read-only region 11 | 12 | Attributes 13 | ---------- 14 | data: :class:`bytes` 15 | Region file (``.mca``) as bytes 16 | """ 17 | __slots__ = ('data',) 18 | def __init__(self, data: bytes): 19 | """Makes a Region object from data, which is the region file content""" 20 | self.data = data 21 | 22 | @staticmethod 23 | def header_offset(chunk_x: int, chunk_z: int) -> int: 24 | """ 25 | Returns the byte offset for given chunk in the header 26 | 27 | Parameters 28 | ---------- 29 | chunk_x 30 | Chunk's X value 31 | chunk_z 32 | Chunk's Z value 33 | """ 34 | return 4 * (chunk_x % 32 + chunk_z % 32 * 32) 35 | 36 | def chunk_location(self, chunk_x: int, chunk_z: int) -> Tuple[int, int]: 37 | """ 38 | Returns the chunk offset in the 4KiB sectors from the start of the file, 39 | and the length of the chunk in sectors of 4KiB 40 | 41 | Will return ``(0, 0)`` if chunk hasn't been generated yet 42 | 43 | Parameters 44 | ---------- 45 | chunk_x 46 | Chunk's X value 47 | chunk_z 48 | Chunk's Z value 49 | """ 50 | b_off = self.header_offset(chunk_x, chunk_z) 51 | off = int.from_bytes(self.data[b_off : b_off + 3], byteorder='big') 52 | sectors = self.data[b_off + 3] 53 | return (off, sectors) 54 | 55 | def chunk_data(self, chunk_x: int, chunk_z: int) -> nbt.NBTFile: 56 | """ 57 | Returns the NBT data for a chunk 58 | 59 | Parameters 60 | ---------- 61 | chunk_x 62 | Chunk's X value 63 | chunk_z 64 | Chunk's Z value 65 | 66 | Raises 67 | ------ 68 | anvil.GZipChunkData 69 | If the chunk's compression is gzip 70 | """ 71 | off = self.chunk_location(chunk_x, chunk_z) 72 | # (0, 0) means it hasn't generated yet, aka it doesn't exist yet 73 | if off == (0, 0): 74 | return 75 | off = off[0] * 4096 76 | length = int.from_bytes(self.data[off:off + 4], byteorder='big') 77 | compression = self.data[off + 4] # 2 most of the time 78 | if compression == 1: 79 | raise GZipChunkData('GZip is not supported') 80 | compressed_data = self.data[off + 5 : off + 5 + length - 1] 81 | return nbt.NBTFile(buffer=BytesIO(zlib.decompress(compressed_data))) 82 | 83 | def get_chunk(self, chunk_x: int, chunk_z: int) -> 'anvil.Chunk': 84 | """ 85 | Returns the chunk at given coordinates, 86 | same as doing ``Chunk.from_region(region, chunk_x, chunk_z)`` 87 | 88 | Parameters 89 | ---------- 90 | chunk_x 91 | Chunk's X value 92 | chunk_z 93 | Chunk's Z value 94 | 95 | 96 | :rtype: :class:`anvil.Chunk` 97 | """ 98 | return anvil.Chunk.from_region(self, chunk_x, chunk_z) 99 | 100 | @classmethod 101 | def from_file(cls, file: Union[str, BinaryIO]): 102 | """ 103 | Creates a new region with the data from reading the given file 104 | 105 | Parameters 106 | ---------- 107 | file 108 | Either a file path or a file object 109 | """ 110 | if isinstance(file, str): 111 | with open(file, 'rb') as f: 112 | return cls(data=f.read()) 113 | else: 114 | return cls(data=file.read()) 115 | -------------------------------------------------------------------------------- /anvil/versions.py: -------------------------------------------------------------------------------- 1 | # This version removes the chunk's "Level" NBT tag and moves all contained tags to the top level 2 | # https://minecraft.wiki/w/Java_Edition_21w43a 3 | VERSION_21w43a = 2844 4 | 5 | # This version removes block state value stretching from the storage 6 | # so a block value isn't in multiple elements of the array 7 | VERSION_20w17a = 2529 8 | 9 | # This version changes how biomes are stored to allow for biomes at different heights 10 | # https://minecraft.wiki/w/Java_Edition_19w36a 11 | VERSION_19w36a = 2203 12 | 13 | # This is the version where "The Flattening" (https://minecraft.wiki/w/Java_Edition_1.13/Flattening) happened 14 | # where blocks went from numeric ids to namespaced ids (namespace:block_id) 15 | VERSION_17w47a = 1451 16 | 17 | # This represents Versions before 1.9 snapshot 15w32a, 18 | # these snapshots do not have a Data Version so we use -1 since -1 is less than any valid data version. 19 | # https://minecraft.wiki/w/Data_version 20 | VERSION_PRE_15w32a = -1 21 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = . 9 | BUILDDIR = _build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /docs/_static/custom.css: -------------------------------------------------------------------------------- 1 | /* 2 | Theme is 99.9% https://userstyles.org/styles/170804/dark-discord-py-rewrite-docs 3 | just has a few tweaks so it works on alabaster 4 | */ 5 | 6 | body { 7 | font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu; 8 | font-size: 1.0em; 9 | 10 | /* Scrolling: Firefox */ 11 | scrollbar-width: 10px; 12 | scrollbar-color: #2C2F33 #23272A; /* Thumb Track */ 13 | } 14 | 15 | h1, h2 { 16 | font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu !important; 17 | } 18 | 19 | /* Dark */ 20 | .indexwrapper, 21 | body { 22 | background-color: #23272A; /* Dark 1 */ 23 | color: #dcddde; /* Light 1 */ 24 | } 25 | 26 | div.body, 27 | .rst-versions.rst-badge .rst-current-version { 28 | background-color: #2C2F33; /* Dark 2 */ 29 | color: #dcddde; /* Light 1 */ 30 | } 31 | 32 | .active { 33 | background-color: #2C2F33; /* Dark 2 */ 34 | border-left: 5px solid #2C2F33; /* Dark 2 */ 35 | } 36 | 37 | /* Get rid of extra bgs */ 38 | tt, 39 | code, 40 | div.highlight { 41 | background-color: transparent; 42 | } 43 | 44 | /* Light font for dark bg */ 45 | div.sphinxsidebar a, 46 | div.sphinxsidebar h3 a, 47 | div.sphinxsidebar h3, 48 | div.sphinxsidebar h4, 49 | div.sphinxsidebar ul, 50 | div.body h1, 51 | div.body h2, 52 | div.body h3, 53 | div.body h4 { 54 | color: #dcddde; 55 | } 56 | 57 | /* Primary color */ 58 | a { 59 | color: #7289da; 60 | } 61 | 62 | a:hover { 63 | color: #7d96f0; 64 | } 65 | 66 | /* Dark bg, light font combo */ 67 | dl.describe > dt, 68 | dl.function > dt, 69 | dl.attribute > dt, 70 | dl.classmethod > dt, 71 | dl.method > dt, 72 | dl.class > dt, 73 | dl.exception > dt, 74 | .container.operations > dl.describe > dt, 75 | table.docutils thead, 76 | table.docutils tfoot, 77 | table.docutils thead tr th, 78 | code.sig-prename, code.sig-name { 79 | background-color: #23272A; /* Dark 1 */ 80 | color: #dcddde; /* Light 1 */ 81 | } 82 | 83 | pre { 84 | background-color: #23272A; /* Dark 1 */ 85 | color: #dcddde; /* Light 1 */ 86 | border: 1px solid rgba(32, 34, 37, .3); 87 | } 88 | 89 | /* Custom colors */ 90 | div.important, 91 | div.note, 92 | div.hint, 93 | div.tip, 94 | highlight, 95 | div.sphinxsidebar input { 96 | background-color: #23272A; /* Dark 1 */ 97 | border: 1px solid #959595; 98 | color: #839496; 99 | } 100 | 101 | div.attention, 102 | div.warning, 103 | div.caution, 104 | div.seealso { 105 | background-color: #665623; 106 | } 107 | 108 | div.helpful { 109 | background-color: #162f44; 110 | border: 1px solid #4478ac; 111 | } 112 | 113 | div.danger, 114 | div.error { 115 | background-color: #401414; 116 | border: 1px solid #f66; 117 | } 118 | 119 | .container.operations::before { 120 | color: #dcddde; /* Light 1 */ 121 | } 122 | 123 | .highlight .k, 124 | .highlight .ow, 125 | .highlight .nb, 126 | .highlight .kc, 127 | .highlight .bp { 128 | color: #00ae32; 129 | } 130 | 131 | .highlight .nf { 132 | color: #5183ff; 133 | } 134 | 135 | .highlight .hll { 136 | background-color: #0076ff30; 137 | } 138 | /* Rounding */ 139 | div.body, 140 | div.admonition, 141 | dl.describe > dt, dl.function > dt, dl.attribute > dt, dl.classmethod > dt, dl.method > dt, dl.class > dt, dl.exception > dt, 142 | .container.operations, 143 | .rst-versions.rst-badge .rst-current-version, 144 | .active, 145 | pre, 146 | img { 147 | border-radius: 5px; 148 | } 149 | 150 | div.sphinxsidebar #searchbox input[type="text"] { 151 | border-top-left-radius: 5px; 152 | border-bottom-left-radius: 5px; 153 | } 154 | 155 | div.sphinxsidebar #searchbox input[type="submit"] { 156 | border-top-right-radius: 5px; 157 | border-bottom-right-radius: 5px; 158 | } 159 | 160 | dl.describe > dt, dl.function > dt, dl.attribute > dt, dl.classmethod > dt, dl.method > dt, dl.class > dt, dl.exception > dt { 161 | padding: 2px 10px; 162 | } 163 | 164 | /* Scrolling: Chrome etc */ 165 | ::-webkit-scrollbar { 166 | width: 10px; 167 | } 168 | 169 | ::-webkit-scrollbar-track { 170 | background: #23272A; /* Dark 1 */ 171 | } 172 | 173 | ::-webkit-scrollbar-thumb { 174 | background: #2C2F33; /* Dark 2 */ 175 | border-radius: 5px; 176 | } 177 | 178 | ::-webkit-scrollbar-thumb:hover { 179 | background: #2C2F33; /* Dark 2 */ 180 | } 181 | 182 | div.sphinxsidebarwrapper { 183 | padding-right: 10px; 184 | box-sizing: border-box; 185 | } 186 | 187 | div.sphinxsidebarwrapper:hover { 188 | padding-right: 0; 189 | overflow-y: scroll; 190 | } 191 | 192 | /* My changes */ 193 | 194 | div.document { 195 | width: 1000px; 196 | min-width: 500px; 197 | max-width: 1200px; 198 | } 199 | 200 | div.body { 201 | width: 800px; 202 | min-width: 500px; 203 | max-width: 1000px; 204 | 205 | padding-top: 10px; 206 | padding-bottom: 10px; 207 | } 208 | 209 | code.xref { 210 | background: transparent; 211 | color: #7289da; 212 | font-weight: normal; 213 | text-decoration: none; 214 | border-bottom: none; 215 | } 216 | 217 | code.xref:hover > span.pre { 218 | background: transparent; 219 | text-decoration: underline; 220 | } 221 | 222 | a.reference:hover, code.xref:hover { 223 | background: transparent; 224 | } 225 | 226 | code.literal:not(.xref) > span.pre { 227 | color: #dcddde; 228 | background-color: #00000020; 229 | } 230 | 231 | li > a.reference.internal { 232 | border-bottom: none; 233 | } 234 | 235 | li > a.reference.internal:hover { 236 | text-decoration: underline; 237 | } 238 | 239 | code.xref.py.docutils.literal.notranslate { 240 | background: transparent; 241 | } -------------------------------------------------------------------------------- /docs/api.rst: -------------------------------------------------------------------------------- 1 | API Reference 2 | ============= 3 | 4 | Block 5 | ----- 6 | .. autoclass:: anvil.Block 7 | :members: 8 | 9 | .. automethod:: __init__ 10 | 11 | .. autoclass:: anvil.OldBlock 12 | :members: 13 | 14 | .. automethod:: __init__ 15 | 16 | Region 17 | ------ 18 | .. autoclass:: anvil.Region 19 | :members: 20 | 21 | Chunk 22 | ----- 23 | .. autoclass:: anvil.Chunk 24 | :members: 25 | 26 | Empty 27 | ----- 28 | 29 | Region 30 | ~~~~~~ 31 | .. autoclass:: anvil.EmptyRegion 32 | :members: 33 | 34 | Chunk 35 | ~~~~~ 36 | .. autoclass:: anvil.EmptyChunk 37 | :members: 38 | 39 | Section 40 | ~~~~~~~ 41 | .. autoclass:: anvil.EmptySection 42 | :members: 43 | 44 | .. autoclass:: anvil.RawSection 45 | :members: 46 | 47 | Errors 48 | ------ 49 | .. automodule:: anvil.errors 50 | :members: 51 | :undoc-members: 52 | :show-inheritance: 53 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | # Configuration file for the Sphinx documentation builder. 2 | # 3 | # This file only contains a selection of the most common options. For a full 4 | # list see the documentation: 5 | # https://www.sphinx-doc.org/en/master/usage/configuration.html 6 | 7 | # -- Path setup -------------------------------------------------------------- 8 | 9 | # If extensions (or modules to document with autodoc) are in another directory, 10 | # add these directories to sys.path here. If the directory is relative to the 11 | # documentation root, use os.path.abspath to make it absolute, like shown here. 12 | # 13 | import os 14 | import sys 15 | sys.path.insert(0, os.path.abspath('../')) 16 | 17 | 18 | # -- Project information ----------------------------------------------------- 19 | 20 | project = 'anvil-parser' 21 | copyright = '2020, mat' 22 | author = 'mat' 23 | 24 | # The full version, including alpha/beta/rc tags 25 | release = '0.4.0' 26 | 27 | 28 | # -- General configuration --------------------------------------------------- 29 | 30 | # Add any Sphinx extension module names here, as strings. They can be 31 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 32 | # ones. 33 | extensions = [ 34 | 'sphinx.ext.autodoc', 35 | 'sphinx.ext.napoleon', 36 | 'sphinx.ext.intersphinx', 37 | 'sphinx_autodoc_typehints', 38 | 'sphinxcontrib_trio' 39 | ] 40 | 41 | intersphinx_mapping = {'py': ('https://docs.python.org/3', None)} 42 | 43 | napoleon_google_docstring = False 44 | 45 | # Add any paths that contain templates here, relative to this directory. 46 | templates_path = [] 47 | 48 | # List of patterns, relative to source directory, that match files and 49 | # directories to ignore when looking for source files. 50 | # This pattern also affects html_static_path and html_extra_path. 51 | exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] 52 | 53 | 54 | # -- Options for HTML output ------------------------------------------------- 55 | 56 | # The theme to use for HTML and HTML Help pages. See the documentation for 57 | # a list of builtin themes. 58 | # 59 | html_theme = 'alabaster' 60 | 61 | # Add any paths that contain custom static files (such as style sheets) here, 62 | # relative to this directory. They are copied after the builtin static files, 63 | # so a file named "default.css" will overwrite the builtin "default.css". 64 | html_static_path = ['_static'] 65 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | anvil-parser 2 | ============ 3 | 4 | Simple parser for the `Minecraft anvil file format `_ 5 | 6 | .. toctree:: 7 | :maxdepth: 3 8 | 9 | api -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=. 11 | set BUILDDIR=_build 12 | 13 | if "%1" == "" goto help 14 | 15 | %SPHINXBUILD% >NUL 2>NUL 16 | if errorlevel 9009 ( 17 | echo. 18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 19 | echo.installed, then set the SPHINXBUILD environment variable to point 20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 21 | echo.may add the Sphinx directory to PATH. 22 | echo. 23 | echo.If you don't have Sphinx installed, grab it from 24 | echo.http://sphinx-doc.org/ 25 | exit /b 1 26 | ) 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | sphinx-autodoc-typehints==1.10.3 2 | sphinxcontrib-trio==1.1.0 3 | -------------------------------------------------------------------------------- /examples/_path.py: -------------------------------------------------------------------------------- 1 | """ 2 | This is an utility script to add the parent folder to the path 3 | so i can do `import anvil` in the examples 4 | Code entirely from: https://stackoverflow.com/a/33532002/9124836 5 | """ 6 | from inspect import getsourcefile 7 | import os.path 8 | import sys 9 | 10 | current_path = os.path.abspath(getsourcefile(lambda:0)) 11 | current_dir = os.path.dirname(current_path) 12 | parent_dir = current_dir[:current_dir.rfind(os.path.sep)] 13 | 14 | sys.path.insert(0, parent_dir) 15 | -------------------------------------------------------------------------------- /examples/basic_world_gen.py: -------------------------------------------------------------------------------- 1 | """ 2 | Basic terrain generation made to test out EmptyRegion and related 3 | Needs the `opensimplex` package to work 4 | 5 | Generated terrain is 128x128 blocks and in the North-West corner 6 | """ 7 | import _path 8 | import anvil 9 | from opensimplex import OpenSimplex 10 | import random 11 | import math 12 | 13 | noise = OpenSimplex() 14 | 15 | region = anvil.EmptyRegion(0, 0) 16 | grass = anvil.Block('minecraft', 'grass_block') 17 | dirt = anvil.Block('minecraft', 'dirt') 18 | glass = anvil.Block('minecraft', 'glass') 19 | oak_log_up = anvil.Block('minecraft', 'oak_log', properties={'axis': 'y'}) 20 | oak_leaves = anvil.Block('minecraft', 'oak_leaves', properties={'persistent': True}) 21 | 22 | grass_plant = anvil.Block('minecraft', 'grass') 23 | poppy = anvil.Block('minecraft', 'poppy') 24 | dandelion = anvil.Block('minecraft', 'dandelion') 25 | tall_grass_l = anvil.Block('minecraft', 'tall_grass', properties={'half': 'lower'}) 26 | tall_grass_u = anvil.Block('minecraft', 'tall_grass', properties={'half': 'upper'}) 27 | 28 | scale = 0.01 29 | plant_scale = 1 30 | xoff = region.x * 512 31 | zoff = region.z * 512 32 | random.seed(0) 33 | for z in range(128): 34 | for x in range(128): 35 | x += xoff 36 | z += zoff 37 | v = noise.noise2d(x*scale, z*scale) 38 | v = (v + 1) / 2 # now its from 0 to 1 39 | v = math.floor(v * 100) 40 | region.set_block(grass, x, v, z) 41 | if v > 0: 42 | region.set_block(dirt, x, v-1, z) 43 | n = noise.noise2d(x*plant_scale+100, z*plant_scale) 44 | if n > 0.4: 45 | # flower 46 | if random.random() > 0.95: 47 | region.set_block(random.choice((poppy, dandelion)), x, v+1, z) 48 | else: 49 | if random.random() > 0.9: 50 | region.set_block(tall_grass_l, x, v+1, z) 51 | region.set_block(tall_grass_u, x, v+2, z) 52 | else: 53 | region.set_block(grass_plant, x, v+1, z) 54 | # Tree 55 | if random.random() > 0.99: 56 | region.fill(oak_leaves, x-2, v+4, z-2, x+2, v+5, z+2, ignore_outside=True) 57 | for y in range(6): 58 | region.set_if_inside(oak_log_up, x, v+y+1, z) 59 | region.set_if_inside(oak_leaves, x, v+7, z) 60 | for y in range(2): 61 | region.set_if_inside(oak_leaves, x+1, v+6+y, z) 62 | region.set_if_inside(oak_leaves, x , v+6+y, z+1) 63 | region.set_if_inside(oak_leaves, x-1, v+6+y, z) 64 | region.set_if_inside(oak_leaves, x , v+6+y, z-1) 65 | 66 | save = region.save('r.0.0.mca') 67 | -------------------------------------------------------------------------------- /examples/cube.py: -------------------------------------------------------------------------------- 1 | import _path 2 | import anvil 3 | from random import choice 4 | 5 | # Create a new region with the `EmptyRegion` class at 0, 0 (in region coords) 6 | region = anvil.EmptyRegion(0, 0) 7 | 8 | # Create `Block` objects that are used to set blocks 9 | stone = anvil.Block('minecraft', 'stone') 10 | dirt = anvil.Block('minecraft', 'dirt') 11 | 12 | # Make a 16x16x16 cube of either stone or dirt blocks 13 | for y in range(16): 14 | for z in range(16): 15 | for x in range(16): 16 | region.set_block(choice((stone, dirt)), x, y, z) 17 | 18 | # Save to a file 19 | region.save('r.0.0.mca') 20 | -------------------------------------------------------------------------------- /examples/top_view.py: -------------------------------------------------------------------------------- 1 | """ 2 | Generates a image of the top view of a chunk 3 | Needs a textures folder with a block folder inside 4 | """ 5 | import sys 6 | if len(sys.argv) == 1: 7 | print('You must give a region file') 8 | exit() 9 | else: 10 | region = sys.argv[1] 11 | chx = int(sys.argv[2]) 12 | chz = int(sys.argv[3]) 13 | import os 14 | from PIL import Image 15 | import _path 16 | import anvil 17 | 18 | chunk = anvil.Chunk.from_region(region, chx, chz) 19 | img = Image.new('RGBA', (16*16,16*16)) 20 | grid = [[None for i in range(16)] for j in range(16)] 21 | for y in reversed(range(256)): 22 | for z in range(16): 23 | for x in range(16): 24 | b = chunk.get_block(x, y, z).id 25 | if b == 'air' or grid[z][x] is not None: 26 | continue 27 | grid[z][x] = b 28 | 29 | texturesf = os.listdir('textures/block') 30 | textures = {} 31 | for z in range(16): 32 | for x in range(16): 33 | b = grid[z][x] 34 | if b is None: 35 | continue 36 | if b not in textures: 37 | if b+'.png' not in texturesf: 38 | print(f'Skipping {b}') 39 | textures[b] = None 40 | continue 41 | textures[b] = Image.open(f'textures/block/{b}.png') 42 | if textures[b] is None: 43 | continue 44 | img.paste(textures[b], box=(x*16, z*16)) 45 | 46 | img.show() 47 | -------------------------------------------------------------------------------- /pytest.ini: -------------------------------------------------------------------------------- 1 | [pytest] 2 | log_cli = True 3 | log_cli_level = INFO 4 | log_cli_format = %(levelname)8s %(message)s 5 | # blame the nbt library 6 | filterwarnings = 7 | ignore::DeprecationWarning 8 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import setuptools 2 | 3 | with open('README.md', 'r') as file: 4 | long_description = file.read() 5 | 6 | setuptools.setup( 7 | name='anvil-parser2', 8 | version='0.10.6', 9 | author='0xTiger', 10 | description='A parser for the Minecraft anvil file format, supports all Minecraft verions', 11 | long_description=long_description, 12 | long_description_content_type='text/markdown', 13 | url='https://github.com/0xTiger/anvil-parser2', 14 | packages=setuptools.find_packages(), 15 | classifiers=[ 16 | 'Programming Language :: Python :: 3', 17 | 'License :: OSI Approved :: MIT License', 18 | 'Operating System :: OS Independent', 19 | ], 20 | install_requires=[ 21 | 'nbt', 22 | 'frozendict', 23 | ], 24 | include_package_data=True 25 | ) 26 | -------------------------------------------------------------------------------- /tests/context.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) 4 | -------------------------------------------------------------------------------- /tests/requirements.txt: -------------------------------------------------------------------------------- 1 | NBT==1.5.1 2 | frozendict==2.0.2 3 | -------------------------------------------------------------------------------- /tests/test_benchmark.py: -------------------------------------------------------------------------------- 1 | import context as _ 2 | from anvil import EmptyRegion, Block, RawSection 3 | import math 4 | import time 5 | import logging 6 | import array 7 | 8 | LOGGER = logging.getLogger(__name__) 9 | 10 | def test_benchmark(): 11 | region = EmptyRegion(0, 0) 12 | 13 | block = Block('iron_block') 14 | 15 | def func(x: int, z: int) -> int: 16 | return math.sin(x * x + z * z) * 0.5 + 0.5 17 | 18 | w = 256 19 | scale = 0.05 20 | y_scale = 15 21 | 22 | start = time.time() 23 | for x in range(w): 24 | for z in range(w): 25 | u = x - w / 2 26 | v = z - w / 2 27 | y = int(func(u * scale, v * scale) * y_scale) 28 | region.set_block(block, x, y, z) 29 | end = time.time() 30 | 31 | LOGGER.info(f'Generating took: {end - start:.3f}s') 32 | 33 | times = [] 34 | n = 3 35 | for _ in range(n): 36 | start = time.time() 37 | region.save() 38 | end = time.time() 39 | times.append(end - start) 40 | 41 | LOGGER.info(f'Saving (average of {n}) took: {sum(times) / len(times):.3f}s') 42 | 43 | def test_raw_section(): 44 | region = EmptyRegion(0, 0) 45 | 46 | block = Block('iron_block') 47 | air = Block('air') 48 | palette = (air, block) 49 | 50 | def func(x: int, z: int) -> int: 51 | return math.sin(x * x + z * z) * 0.5 + 0.5 52 | 53 | w = 256 54 | chunk_w = w // 16 55 | scale = 0.05 56 | y_scale = 15 57 | 58 | start = time.time() 59 | 60 | # from 0 to y_scale 61 | heights = array.array('B') 62 | for z in range(w): 63 | for x in range(w): 64 | u = z - w / 2 65 | v = x - w / 2 66 | height = int(func(u * scale, v * scale) * y_scale) 67 | heights.append(height) 68 | 69 | for chunk_x in range(chunk_w): 70 | for chunk_z in range(chunk_w): 71 | blocks = array.array('B') 72 | for y in range(16): 73 | for z in range(16): 74 | for x in range(16): 75 | rx = x + chunk_x * 16 76 | rz = z + chunk_z * 16 77 | i = rz * w + rx 78 | height = heights[i] 79 | if y == height: 80 | blocks.append(1) 81 | else: 82 | blocks.append(0) 83 | region.add_section(RawSection(0, blocks, palette), chunk_x, chunk_z) 84 | 85 | end = time.time() 86 | 87 | LOGGER.info(f'Generating took: {end - start:.3f}s') 88 | 89 | times = [] 90 | n = 3 91 | for _ in range(n): 92 | start = time.time() 93 | region.save() 94 | end = time.time() 95 | times.append(end - start) 96 | 97 | LOGGER.info(f'Saving (average of {n}) took: {sum(times) / len(times):.3f}s') 98 | 99 | def test_raw_section_simple(): 100 | region = EmptyRegion(0, 0) 101 | 102 | air = Block('air') 103 | palette = (air, Block('white_concrete'), Block('light_gray_concrete'), Block('gray_concrete')) 104 | 105 | blocks = array.array('B') 106 | for z in range(16): 107 | for x in range(16): 108 | d = x * x + z * z 109 | if d < 25: 110 | blocks.append(1) 111 | elif d < 100: 112 | blocks.append(2) 113 | elif d < 225: 114 | blocks.append(3) 115 | else: 116 | blocks.append(0) 117 | 118 | blocks.extend(0 for _ in range(16 * 16 * 16 - len(blocks))) 119 | 120 | assert len(blocks) == 16 * 16 * 16 121 | 122 | section = RawSection(0, blocks, palette) 123 | region.add_section(section, 0, 0) 124 | 125 | region.save() 126 | -------------------------------------------------------------------------------- /tests/test_mixed_chunk_types.py: -------------------------------------------------------------------------------- 1 | import context as _ 2 | from anvil import Chunk, EmptyChunk, EmptyRegion, Block, Region 3 | import random 4 | 5 | def test_mixed_chunk_types(): 6 | colors = ['red', 'orange', 'yellow', 'green'] 7 | 8 | region = EmptyRegion(0, 0) 9 | 10 | chunk = EmptyChunk(0, 0) 11 | empty_chunk = EmptyChunk(1, 0) 12 | for i, color in enumerate(colors): 13 | chunk.set_block(Block(color), i, 0, 0) 14 | empty_chunk.set_block(Block(color), i, 0, 0) 15 | 16 | chunk = Chunk(chunk.save()) 17 | 18 | region.add_chunk(chunk) 19 | region.add_chunk(empty_chunk) 20 | 21 | region = Region(region.save()) 22 | 23 | for i in range(2): 24 | chunk = region.get_chunk(i, 0) 25 | for i, color in enumerate(colors): 26 | assert chunk.get_block(i, 0, 0).id == color 27 | -------------------------------------------------------------------------------- /tests/test_read_region.py: -------------------------------------------------------------------------------- 1 | import context as _ 2 | from anvil import Region 3 | import io 4 | import secrets 5 | 6 | def test_from_filename(tmp_path): 7 | filename = tmp_path / "region.mca" 8 | contents = secrets.token_bytes() 9 | 10 | with open(filename, 'wb') as f: 11 | f.write(contents) 12 | 13 | region = Region.from_file(str(filename)) 14 | assert region.data == contents 15 | 16 | def test_from_filelike(): 17 | contents = secrets.token_bytes() 18 | filelike = io.BytesIO(contents) 19 | 20 | region = Region.from_file(filelike) 21 | assert region.data == contents 22 | -------------------------------------------------------------------------------- /tests/test_stream_blocks.py: -------------------------------------------------------------------------------- 1 | import context as _ 2 | from anvil import EmptyRegion, Region, Block 3 | 4 | def coord_to_index(x, y, z): 5 | return y * 16 * 16 + z * 16 + x 6 | 7 | def test_4bits(): 8 | region = EmptyRegion(0, 0) 9 | 10 | region.set_block(Block('minecraft', 'stone'), 0, 0, 0) 11 | region.set_block(Block('minecraft', 'dirt'), 1, 0, 0) 12 | region.set_block(Block('minecraft', 'oak_planks'), 2, 0, 0) 13 | region.set_block(Block('minecraft', 'sand'), 10, 7, 5) 14 | region.set_block(Block('minecraft', 'white_wool'), 8, 6, 0) 15 | region.set_block(Block('minecraft', 'bedrock'), 15, 15, 15) 16 | 17 | region = Region(region.save()) 18 | 19 | for i, block in enumerate(region.get_chunk(0, 0).stream_blocks()): 20 | if i == 0: 21 | assert block.id == 'stone' 22 | elif i == 1: 23 | assert block.id == 'dirt' 24 | elif i == 2: 25 | assert block.id == 'oak_planks' 26 | elif i == coord_to_index(10, 7, 5): 27 | assert block.id == 'sand' 28 | elif i == coord_to_index(15, 15, 15): 29 | assert block.id == 'bedrock' 30 | elif i == coord_to_index(8, 6, 0): 31 | assert block.id == 'white_wool' 32 | else: 33 | assert block.id == 'air' 34 | 35 | def test_5bits(): 36 | from random import randint 37 | region = EmptyRegion(0, 0) 38 | 39 | blocks = 'stone,dirt,oak_planks,sand,bedrock,white_wool,red_wool,green_wool,sponge,awesome,these,dont,need,to,exist,foo,bar'.split(',') 40 | positions = [(randint(0, 15), randint(0, 15), randint(0, 15)) for _ in range(len(blocks))] 41 | for block, pos in zip(blocks, positions): 42 | region.set_block(Block('minecraft', block), *pos) 43 | 44 | region = Region(region.save()) 45 | 46 | for i, block in enumerate(region.get_chunk(0, 0).stream_blocks()): 47 | if block.id in blocks: 48 | assert coord_to_index(*positions[blocks.index(block.id)]) == i 49 | else: 50 | assert block.id == 'air' 51 | 52 | def test_index(): 53 | region = EmptyRegion(0, 0) 54 | 55 | region.set_block(Block('minecraft', 'dirt'), 2, 0, 0) 56 | region.set_block(Block('minecraft', 'stone'), 3, 0, 0) 57 | blocks = 'stone,dirt,oak_planks,sand,bedrock'.split(',') 58 | for i, block in enumerate(blocks): 59 | region.set_block(Block('minecraft', block), i % 16, 0, i // 16) 60 | 61 | region = Region(region.save()) 62 | 63 | for i, block in enumerate(region.get_chunk(0, 0).stream_blocks(index=2)): 64 | i += 2 65 | if i < len(blocks): 66 | assert block.id == blocks[i] 67 | else: 68 | assert block.id == 'air' 69 | 70 | def test_index_5bits(): 71 | region = EmptyRegion(0, 0) 72 | 73 | region.set_block(Block('minecraft', 'dirt'), 2, 0, 0) 74 | region.set_block(Block('minecraft', 'stone'), 3, 0, 0) 75 | blocks = 'stone,dirt,oak_planks,sand,bedrock,white_wool,red_wool,green_wool,sponge,awesome,these,dont,need,to,exist,foo,bar'.split(',') 76 | for i, block in enumerate(blocks): 77 | region.set_block(Block('minecraft', block), i % 16, 0, i // 16) 78 | 79 | region = Region(region.save()) 80 | 81 | for i, block in enumerate(region.get_chunk(0, 0).stream_blocks(index=17)): 82 | i += 17 83 | if i < len(blocks): 84 | assert block.id == blocks[i] 85 | else: 86 | assert block.id == 'air' 87 | --------------------------------------------------------------------------------