def ints_to_block(self, block_id: int, block_data: int) -> "Block": if block_id in self._translation_manager.block_registry: ( namespace, base_name, ) = self._translation_manager.block_registry.private_to_str(block_id).split( ":", 1 ) elif block_id in self._numerical_block_map: namespace, base_name = self._numerical_block_map[block_id] else: return Block( namespace="minecraft", base_name="numerical", properties={ "block_id": amulet_nbt.TAG_Int(block_id), "block_data": amulet_nbt.TAG_Int(block_data), }, ) return Block( namespace=namespace, base_name=base_name, properties={"block_data": amulet_nbt.TAG_Int(block_data)}, )
def get_blockstates(version, namespace_str, base_name): block_specification = version.block.get_specification( namespace_str, base_name, True) properties = block_specification.get("properties", {}) if len(properties) > 0: keys, values = zip(*properties.items()) else: keys, values = (), () values = tuple([nbt.from_snbt(val) for val in prop] for prop in values) for spec_ in itertools.product(*values): spec = dict(zip(keys, spec_)) yield Block(namespace=namespace_str, base_name=base_name, properties=spec)
while True: user_input = input('type command ("n" to escape): ') if user_input == "n": break user_input = user_input.split(" ") if not len(user_input) == 7: print("command format is incorrect") continue ( input_platform, input_version, input_force_blockstate, output_platform, output_version, output_force_blockstate, blockstate, ) = user_input input_force_blockstate = input_force_blockstate.lower() == "true" output_force_blockstate = output_force_blockstate.lower() == "true" inp = get_version(input_platform, input_version) out = get_version(output_platform, output_version) block = Block(*Block.parse_blockstate_string(blockstate)) print(f"\tInput block {block}") ublock = inp.block.to_universal(block, force_blockstate=input_force_blockstate)[0] print(f"\tUniveral block {ublock}") outblock = out.block.from_universal( ublock, force_blockstate=output_force_blockstate) print(f"\tOutput block {outblock}")
def translate( object_input: Union[Block, Entity], input_spec: dict, mappings: List[dict], output_version: "Version", force_blockstate: bool, get_block_callback: Callable[ [BlockCoordinates], Tuple[Block, Union[None, BlockEntity]] ] = None, extra_input: BlockEntity = None, pre_populate_defaults: bool = True, block_location: Optional[BlockCoordinates] = None, ) -> Tuple[Union[Block, Entity], Union[BlockEntity, None], bool, bool]: """ A function to translate the object input to the output version :param object_input: the Block or Entity object to be converted :param input_spec: the specification for the object_input from the input block_format :param mappings: the mapping file for the input_object :param output_version: A way for the function to look at the specification being converted to. (used to load default properties) :param force_blockstate: True to get the blockstate format. False to get the native format (these are sometimes the same) :param get_block_callback: A callable with relative coordinates that returns a Block and optional BlockEntity :param extra_input: secondary to the object_input a block entity can be given. This should only be used in the select block tool or plugins. Not compatible with location :param pre_populate_defaults: should the nbt structure (if exists) be populated with the default values :param block_location: optional coordinate of where the block is in the world. Used in very few situations. :return: output, extra_output, extra_needed, cacheable extra_needed: a bool to specify if more data is needed beyond the object_input cacheable: a bool to specify if the result can be cached to reduce future processing Block, None, bool, bool Block, BlockEntity, bool, bool Entity, None, bool, bool """ if block_location is not None: block_location = ( # force block locations to be ints int(block_location[0]), int(block_location[1]), int(block_location[2]), ) # set up for the _translate function which does the actual conversion if isinstance(object_input, Block): block_input = object_input if ( extra_input is None and "snbt" in input_spec and get_block_callback is not None ): # if the callback function is defined then load the BlockEntity from the world extra_input = get_block_callback((0, 0, 0))[1] if extra_input is None: # if BlockEntity is still None create it based off the specification namespace, base_name = input_spec["nbt_identifier"] extra_input = BlockEntity( namespace, base_name, 0, 0, 0, NBTFile(amulet_nbt.from_snbt(input_spec["snbt"])), ) nbt_input = extra_input.nbt elif extra_input is not None: # if the BlockEntity is already defined in extra_input continue with that assert isinstance(extra_input, BlockEntity) nbt_input = extra_input.nbt else: # if callback and extra_input are both None then continue with the mapping as normal but without the BlockEntity. # The mappings will do as much as it can and will return the extra_needed flag as True telling the caller to run with callback if possible nbt_input = None elif isinstance(object_input, Entity): assert ( extra_input is None ), "When an Entity is the first input the extra input must be None" block_input = None nbt_input = object_input.nbt else: raise Exception # run the conversion output_name, output_type, new_data, extra_needed, cacheable = _translate( block_input, nbt_input, mappings, get_block_callback, block_location ) # sort out the outputs from the _translate function extra_output = None if output_type == "block": # we should have a block output # create the block object based on output_name and new['properties'] namespace, base_name = output_name.split(":", 1) spec = output_version.block.get_specification( namespace, base_name, force_blockstate ) properties = spec.get("defaults", {}) # cast to NBT properties = { prop: amulet_nbt.from_snbt(val) for prop, val in properties.items() } for key, val in new_data["properties"].items(): properties[key] = val output = Block(namespace, base_name, properties) if "snbt" in spec: namespace, base_name = spec.get("nbt_identifier", ["unknown", "unknown"]) if pre_populate_defaults: nbt = nbt_from_list( spec.get("outer_name", ""), spec.get("outer_type", "compound"), new_data["nbt"], spec.get("snbt", "{}"), ) else: nbt = nbt_from_list( spec.get("outer_name", ""), spec.get("outer_type", "compound"), new_data["nbt"], ) extra_output = BlockEntity(namespace, base_name, 0, 0, 0, nbt) # not quite sure how to handle coordinates here. # it makes sense to me to have the wrapper program set the coordinates so none are missed. elif new_data["nbt"]: log.warning( f"New nbt present but no output block entity\nin:{object_input.blockstate}\nout:{output.blockstate}" ) elif output_type == "entity": # we should have an entity output # create the entity object based on output_name and new['nbt'] namespace, base_name = output_name.split(":", 1) spec = output_version.entity.get_specification( namespace, base_name, force_blockstate ) if pre_populate_defaults: nbt = nbt_from_list( spec.get("outer_name", ""), spec.get("outer_type", "compound"), new_data["nbt"], spec.get("snbt", "{}"), ) else: nbt = nbt_from_list( spec.get("outer_name", ""), spec.get("outer_type", "compound"), new_data["nbt"], ) output = Entity(namespace, base_name, 0.0, 0.0, 0.0, nbt) else: raise Exception("No output object given.") return output, extra_output, extra_needed, cacheable
def in_and_out( platform_name: str, version_number: Any, version: PyMCTranslate.Version, input_blockstate: Block, ) -> List[str]: # blockstate to universal msg = [] try: universal_output, extra_output, extra_needed = version.block.to_universal( input_blockstate, force_blockstate=True) except: msg += [ "=" * 150, f"error to universal {platform_name} {version_number}", f"Blockstate input: {input_blockstate}", ] for e in msg: log.error(e) return msg if extra_needed or extra_output is not None: if print_extra_needed: msg.append( f"skipping {platform_name} {version_number} {input_blockstate}. Needs more data" ) log.error(msg[-1]) return msg if not universal_output.namespace.startswith("universal_"): msg += [ "=" * 150, f'Universal is not "universal_" {platform_name} {version_number}', f"Blockstate input: {input_blockstate}", f"Universal output: {universal_output}", ] if version.has_abstract_format: # universal to numerical try: numerical_output, extra_output, extra_needed = version.block.from_universal( universal_output) except: msg += [ "=" * 150, f"error from universal to numerical {platform_name} {version_number}", f"Blockstate input: {input_blockstate}", f"Universal output: {universal_output}", ] for e in msg: log.error(e) return msg if extra_needed or extra_output is not None: if print_extra_needed: msg.append( f"skipping {platform_name} {version_number} {input_blockstate}. Needs more data" ) log.error(msg[-1]) return msg # numerical to universal try: universal_output2, extra_output, extra_needed = version.block.to_universal( numerical_output) except: msg += [ "=" * 150, f"error from universal to blockstate {platform_name} {version_number}", f"Blockstate input: {input_blockstate}", f"Universal output: {universal_output}", f"Numerical output: {numerical_output}", ] for e in msg: log.error(e) return msg if extra_needed or extra_output is not None: if print_extra_needed: msg.append( f"skipping {platform_name} {version_number} {input_blockstate}. Needs more data" ) log.error(msg[-1]) return msg else: numerical_output = None universal_output2 = universal_output if not universal_output2.namespace.startswith("universal_"): msg += [ "=" * 150, f"Universal is not universal_ {platform_name} {version_number}", f"Blockstate input: {input_blockstate}", f"Universal output: {universal_output}", f"Numerical output: {numerical_output}", f"Universal output 2: {universal_output2}", ] for e in msg: log.error(e) # universal to blockstate try: back_out, extra_output, extra_needed = version.block.from_universal( universal_output2, force_blockstate=True) except: msg += [ "=" * 150, f"error from universal {platform_name} {version_number}", f"Blockstate input: {input_blockstate}", f"Universal output: {universal_output}", f"Numerical output: {numerical_output}", f"Universal output 2: {universal_output2}", ] for e in msg: log.error(e) return msg if str(input_blockstate) != str(back_out): if version.platform == "java" and version.version_number[1] >= 13: props1 = input_blockstate.properties props2 = back_out.properties if "waterlogged" in props1: del props1["waterlogged"] if "waterlogged" in props2: del props2["waterlogged"] if str( Block( namespace=input_blockstate.namespace, base_name=input_blockstate.base_name, properties=props1, )) == str( Block( namespace=back_out.namespace, base_name=back_out.base_name, properties=props2, )): return msg msg += [ "=" * 150, f"Conversion error: {input_blockstate} != {back_out} {platform_name} {version_number}", f"Universal output: {universal_output}", f"Numerical output: {numerical_output}", f"Universal output 2: {universal_output2}", f"Blockstate: {back_out}", ] for e in msg: log.error(e) return msg return msg
import PyMCTranslate from PyMCTranslate.py3.api import Block translations = PyMCTranslate.new_translation_manager() print("==== bedrock_1_7_0 ====") for data in range(16): print( translations.get_sub_version("bedrock", (1, 7, 0)).to_universal( Block("minecraft", "log", {"block_data": str(data)}))[0]) print("==== java_1_12_2 ====") for data in range(16): print( translations.get_sub_version("java", (1, 12, 2)).to_universal( Block("minecraft", "log", {"block_data": str(data)}))[0])