Exemplo n.º 1
0
    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)},
        )
Exemplo n.º 2
0
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)
Exemplo n.º 3
0
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}")
Exemplo n.º 4
0
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
Exemplo n.º 5
0
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
Exemplo n.º 6
0
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])