Example #1
0
 def _encode_structures(chunk: Chunk, compound: TAG_Compound):
     compound["Structures"] = chunk.misc.get(
         "structures",
         TAG_Compound({
             "References": TAG_Compound(),
             "Starts": TAG_Compound(),
         }),
     )
Example #2
0
 def _encode_block_palette(blockstates: list) -> TAG_List:
     palette = TAG_List()
     for block in blockstates:
         entry = TAG_Compound()
         entry["Name"] = TAG_String(f"{block.namespace}:{block.base_name}")
         if block.properties:
             entry["Properties"] = TAG_Compound(block.properties)
         palette.append(entry)
     return palette
Example #3
0
 def _decode_block_section(
         self,
         section: TAG_Compound) -> Optional[Tuple[numpy.ndarray, list]]:
     if "Palette" not in section:  # 1.14 makes block_palette/blocks optional.
         return None
     section_palette = self._decode_block_palette(section.pop("Palette"))
     decoded = decode_long_array(
         section.pop("BlockStates").value,
         4096,
         max(4, (len(section_palette) - 1).bit_length()),
         dense=self.LongArrayDense,
     ).astype(numpy.uint32)
     arr = numpy.transpose(decoded.reshape((16, 16, 16)), (2, 0, 1))
     return arr, section_palette
Example #4
0
    def _encode_block_section(
        self,
        chunk: Chunk,
        sections: Dict[int, TAG_Compound],
        palette: AnyNDArray,
        cy: int,
    ) -> bool:
        if cy in chunk.blocks:
            block_sub_array = palette[
                numpy.transpose(
                    chunk.blocks.get_sub_chunk(cy), (1, 2, 0)
                ).ravel()  # XYZ -> YZX
            ]

            data_sub_array = block_sub_array[:, 1]
            block_sub_array = block_sub_array[:, 0]
            # if not numpy.any(block_sub_array) and not numpy.any(data_sub_array):
            #     return False
            section = sections.setdefault(cy, TAG_Compound())
            section["Blocks"] = TAG_Byte_Array(block_sub_array.astype("uint8"))
            section["Data"] = TAG_Byte_Array(
                world_utils.to_nibble_array(data_sub_array)
            )
            return True
        return False
Example #5
0
    def _encode_block_section(
        self,
        chunk: Chunk,
        sections: Dict[int, TAG_Compound],
        palette: AnyNDArray,
        cy: int,
    ) -> bool:
        if cy in chunk.blocks:
            block_sub_array = numpy.transpose(chunk.blocks.get_sub_chunk(cy),
                                              (1, 2, 0)).ravel()

            sub_palette_, block_sub_array = numpy.unique(block_sub_array,
                                                         return_inverse=True)
            sub_palette = self._encode_block_palette(palette[sub_palette_])
            if (len(sub_palette) == 1
                    and sub_palette[0]["Name"].value == "minecraft:air"):
                return False

            section = sections.setdefault(cy, TAG_Compound())
            section["BlockStates"] = TAG_Long_Array(
                encode_long_array(block_sub_array,
                                  dense=self.LongArrayDense,
                                  min_bits_per_entry=4))
            section["Palette"] = sub_palette
            return True
        return False
Example #6
0
 def _init_encode(chunk: "Chunk"):
     """Get or create the root tag."""
     if "java_chunk_data" in chunk.misc and isinstance(
         chunk.misc["java_chunk_data"], TAG_Compound
     ):
         return chunk.misc["java_chunk_data"]
     else:
         return TAG_Compound()
Example #7
0
 def _decode_chunk(self, chunk: Chunk, root: TAG_Compound,
                   bounds: Tuple[int, int]) -> Tuple["Chunk", AnyNDArray]:
     self._decode_root(chunk, root)
     floor_cy = root.pop("yPos").value
     self._decode_level(chunk, root, bounds, floor_cy)
     sections = self._extract_sections(chunk, root)
     self._decode_sections(chunk, sections)
     palette = self._decode_blocks(chunk, sections)
     return chunk, palette
Example #8
0
 def _decode_block_palette(palette: TAG_List) -> list:
     blockstates = []
     for entry in palette:
         namespace, base_name = entry["Name"].value.split(":", 1)
         properties = entry.get("Properties", TAG_Compound({})).value
         block = Block(namespace=namespace,
                       base_name=base_name,
                       properties=properties)
         blockstates.append(block)
     return blockstates
Example #9
0
    def test_decode_encode(self):
        """Test decoding chunk data and then encoding it again to make sure it matches."""
        with WorldTemp(self.WorldPath) as world_temp:
            level = load_format(world_temp.temp_path)
            level.open()
            chunk_count = 0
            for dimension in level.dimensions:
                for cx, cz in level.all_chunk_coords(dimension):
                    raw_chunk_data_in = level._get_raw_chunk_data(cx, cz, dimension)
                    raw_chunk_data = copy.deepcopy(raw_chunk_data_in)
                    interface = level._get_interface(raw_chunk_data)

                    if (
                        world_temp.metadata["world_data"]["platform"] == "java"
                        and world_temp.metadata["world_data"]["origin"] == "vanilla"
                    ):
                        # store references to the data
                        level_tag = raw_chunk_data.get("Level", TAG_Compound())

                    # decode the raw chunk data
                    chunk, chunk_palette = level._decode(
                        interface, dimension, cx, cz, raw_chunk_data
                    )

                    # TODO: uncomment this when the last few things in the Java format are sorted
                    # if (
                    #     world_temp.metadata["world_data"]["platform"] == "java"
                    #     and world_temp.metadata["world_data"]["origin"] == "vanilla"
                    # ):
                    #     self.assertFalse(raw_chunk_data, msg=self.WorldPath)
                    #     self.assertFalse(level_tag, msg=self.WorldPath)

                    raw_chunk_data_out = level._encode(
                        interface, chunk, dimension, chunk_palette
                    )
                    if chunk_count > 100:
                        break
                    chunk_count += 1
                    # if raw_chunk_data_in != raw_chunk_data_out:
                    #     print("Difference")
                    #     print(raw_chunk_data_in.value.find_diff(raw_chunk_data_out.value))
                    # print(raw_chunk_data_in.to_snbt())
                    # print(raw_chunk_data_out.to_snbt())

                    # self.assertEqual(raw_chunk_data_in, raw_chunk_data_out)

                    raw_chunk_data2 = copy.deepcopy(raw_chunk_data_out)
                    if world_temp.metadata["world_data"]["platform"] == "bedrock":
                        raw_chunk_data2 = {
                            key: val
                            for key, val in raw_chunk_data2.items()
                            if val is not None
                        }
                    level._decode(interface, dimension, cx, cz, raw_chunk_data2)
            level.close()
Example #10
0
 def _decode_chunk(
     self, chunk: Chunk, root: TAG_Compound, bounds: Tuple[int, int]
 ) -> Tuple["Chunk", AnyNDArray]:
     self._decode_root(chunk, root)
     assert self.check_type(root, "Level", TAG_Compound)
     level = root.pop("Level")
     self._decode_level(chunk, level, bounds, bounds[0] >> 4)
     sections = self._extract_sections(chunk, level)
     self._decode_sections(chunk, sections)
     palette = self._decode_blocks(chunk, sections)
     return chunk, palette
Example #11
0
    def _encode_biome_section(
        self,
        chunk: Chunk,
        sections: Dict[int, TAG_Compound],
        cy: int,
    ) -> bool:
        chunk.biomes.convert_to_3d()
        if cy in chunk.biomes:
            biome_sub_array = numpy.transpose(chunk.biomes.get_section(cy),
                                              (1, 2, 0)).ravel()

            sub_palette_, biome_sub_array = numpy.unique(biome_sub_array,
                                                         return_inverse=True)
            sub_palette = self._encode_biome_palette(
                chunk.biome_palette[sub_palette_])
            section = sections.setdefault(cy, TAG_Compound())
            biomes = section["biomes"] = TAG_Compound({"palette": sub_palette})
            if len(sub_palette) != 1:
                biomes["data"] = TAG_Long_Array(
                    encode_long_array(biome_sub_array,
                                      dense=self.LongArrayDense))
            return True
        return False
Example #12
0
    def _encode_block_section(
        self,
        chunk: Chunk,
        sections: Dict[int, TAG_Compound],
        palette: AnyNDArray,
        cy: int,
    ):
        if cy in chunk.blocks:
            block_sub_array = numpy.transpose(chunk.blocks.get_sub_chunk(cy),
                                              (1, 2, 0)).ravel()

            sub_palette_, block_sub_array = numpy.unique(block_sub_array,
                                                         return_inverse=True)
            sub_palette = self._encode_block_palette(palette[sub_palette_])
            section = sections.setdefault(cy, TAG_Compound())
            block_states = section["block_states"] = TAG_Compound(
                {"palette": sub_palette})
            if len(sub_palette) != 1:
                block_states["data"] = TAG_Long_Array(
                    encode_long_array(block_sub_array,
                                      dense=self.LongArrayDense,
                                      min_bits_per_entry=4))
            return True
        return False
Example #13
0
 def _encode_ticks(ticks: Dict[BlockCoordinates, Tuple[str, int, int]]) -> TAG_List:
     ticks_out = TAG_List()
     if isinstance(ticks, dict):
         for k, v in ticks.items():
             try:
                 (x, y, z), (i, t, p) = k, v
                 ticks_out.append(
                     TAG_Compound(
                         {
                             "i": TAG_String(i),
                             "p": TAG_Int(p),
                             "t": TAG_Int(t),
                             "x": TAG_Int(x),
                             "y": TAG_Int(y),
                             "z": TAG_Int(x),
                         }
                     )
                 )
             except Exception:
                 amulet.log.error(f"Could not serialise tick data {k}: {v}")
     return ticks_out
Example #14
0
 def _decode_biomes(self, chunk: Chunk, compound: TAG_Compound, floor_cy: int):
     biomes = compound.pop("Biomes", None)
     if isinstance(biomes, TAG_Int_Array):
         if (len(biomes) / 16) % 4:
             log.error(
                 f"The biome array size must be 4x4x4xN but got an array of size {biomes.value.size}"
             )
         else:
             arr = numpy.transpose(
                 biomes.astype(numpy.uint32).reshape((-1, 4, 4)),
                 (2, 0, 1),
             )  # YZX -> XYZ
             chunk.biomes = {
                 sy + floor_cy: arr
                 for sy, arr in enumerate(
                     numpy.split(
                         arr,
                         arr.shape[1] // 4,
                         1,
                     )
                 )
             }
Example #15
0
 def _encode_height(
     self, chunk: Chunk, level: TAG_Compound, bounds: Tuple[int, int]
 ):
     maps = [
         "WORLD_SURFACE_WG",
         "OCEAN_FLOOR_WG",
         "MOTION_BLOCKING",
         "MOTION_BLOCKING_NO_LEAVES",
         "OCEAN_FLOOR",
     ]
     if self._features["height_map"] == "C|V1":  # 1466
         maps = ("LIQUID", "SOLID", "LIGHT", "RAIN")
     elif self._features["height_map"] == "C|V2":  # 1484
         maps.append("LIGHT_BLOCKING")
     elif self._features["height_map"] == "C|V3":  # 1503
         maps.append("LIGHT_BLOCKING")
         maps.append("WORLD_SURFACE")
     elif self._features["height_map"] == "C|V4":  # 1908
         maps.append("WORLD_SURFACE")
     else:
         raise Exception
     heightmaps_temp: Dict[str, numpy.ndarray] = chunk.misc.get("height_mapC", {})
     heightmaps = TAG_Compound()
     for heightmap in maps:
         if (
             heightmap in heightmaps_temp
             and isinstance(heightmaps_temp[heightmap], numpy.ndarray)
             and heightmaps_temp[heightmap].size == 256
         ):
             heightmaps[heightmap] = TAG_Long_Array(
                 encode_long_array(
                     heightmaps_temp[heightmap].ravel() - bounds[0],
                     (bounds[1] - bounds[0]).bit_length(),
                     self.LongArrayDense,
                 )
             )
     level["Heightmaps"] = heightmaps
Example #16
0
 def _decode_biomes(self, chunk: Chunk, compound: TAG_Compound, floor_cy: int):
     biomes = compound.pop("Biomes", None)
     if isinstance(biomes, TAG_Byte_Array) and biomes.value.size == 256:
         chunk.biomes = biomes.astype(numpy.uint32).reshape((16, 16))
Example #17
0
 def _decode_coords(chunk: Chunk, level: TAG_Compound):
     assert chunk.coordinates == (level.pop("xPos"), level.pop("zPos"))