Source code for quarry.types.registry

import json
import math
import os.path
import subprocess


class Registry(object):
    """
    Base type for registries.
    """

    #: Number of bits needed to represent the greatest block ID.
    max_bits = None


[docs] def encode(self, kind, obj): """ Encodes a thing to an integer ID. """ raise NotImplementedError
[docs] def decode(self, kind, val): """ Decodes a thing from an integer ID. """ raise NotImplementedError
[docs] def encode_block(self, obj): """ Encodes a block to an integer ID. """ raise NotImplementedError
[docs] def decode_block(self, val): """ Decodes a block from an integer ID. """ raise NotImplementedError
[docs] def is_air_block(self, obj): """ Returns true if the given object is considered air for lighting purposes. """ raise NotImplementedError
[docs]class OpaqueRegistry(Registry): """ Registry that passes IDs through unchanged. This is the default. """ def __init__(self, max_bits): self.max_bits = max_bits def encode(self, kind, obj): return obj def decode(self, kind, val): return val def encode_block(self, obj): return obj def decode_block(self, val): return val def is_air_block(self, obj): return obj == 0
[docs]class BitShiftRegistry(OpaqueRegistry): """ Registry implementing the Minecraft 1.7 - 1.12 bit-shift format for blocks. Blocks decode to a ``(block_id, metadata)`` pair. Items pass through unchanged. """ max_bits = 13 def encode_block(self, obj): return (obj[0] << 4) | obj[1] def decode_block(self, val): return val >> 4, val & 0x0F def is_air_block(self, obj): return obj[0] == 0
[docs]class LookupRegistry(Registry): """ Registry implementing a dictionary lookup, recommended for 1.13+. Blocks decode to a ``dict`` where the only guaranteed key is ``u'name'``. Items decode to a ``str`` name. Use the ``from_jar()`` or ``from_json()`` class methods to load data from the official server. """ def __init__(self, blocks, registries): self.max_bits = int(math.ceil(math.log(max(blocks.keys()), 2))) self.decode_block_map = blocks self.encode_block_map = { frozenset(value.items()): key for key, value in blocks.items()} self.decode_map = registries self.encode_map = { registry_name: {value: key for key, value in registry.items()} for registry_name, registry in registries.items()} def encode(self, registry, obj): return self.encode_map[registry][obj] def decode(self, registry, val): return self.decode_map[registry][val] def encode_block(self, obj): return self.encode_block_map[frozenset(obj.items())] def decode_block(self, val): return dict(self.decode_block_map[val]) def is_air_block(self, obj): for name in ('air', 'cave_air', 'void_air'): if obj['name'] == name: return True return False
[docs] @classmethod def from_jar(cls, jar_path): """ Create a ``LookupRegistry`` from a Minecraft server jar file. This method generates JSON files by running the Minecraft server like so:: java -cp minecraft_server.jar net.minecraft.data.Main --reports It then feeds the generated JSON files to ``from_json()``. """ root_path, jar_name = os.path.split(jar_path) reports_path = os.path.join(root_path, "generated", "reports") # Accept EULA eula_path = os.path.join(root_path, "eula.txt") if not os.path.exists(eula_path): with open(eula_path, "w") as fd: fd.write("eula=true\n") # Export reports if not os.path.exists(reports_path): subprocess.check_call( ["java", "-cp", jar_name, "net.minecraft.data.Main", "--reports"], cwd=root_path) # Load data return cls.from_json(reports_path)
[docs] @classmethod def from_json(cls, reports_path): """ Create a ``LookupRegistry`` from JSON files generated by the official server. """ blocks = {} registries_temp = {} registries = {} blocks_path = os.path.join(reports_path, "blocks.json") items_path = os.path.join(reports_path, "items.json") registries_path = os.path.join(reports_path, "registries.json") with open(blocks_path) as fd: for name, obj in json.load(fd).items(): for state in obj['states']: properties = state.get("properties", {}) properties[u'name'] = name blocks[state['id']] = properties if os.path.exists(items_path): with open(items_path) as fd: registries_temp['minecraft:item'] = {'entries': json.load(fd)} if os.path.exists(registries_path): with open(registries_path) as fd: registries_temp.update(json.load(fd)) for registry_name, registry in registries_temp.items(): registries[registry_name] = {} for name, obj in registry['entries'].items(): registries[registry_name][obj['protocol_id']] = name return cls(blocks, registries)