示例#1
0
    def identify_block_entities(aggregate, classloader, verbose):
        te = aggregate.setdefault("tileentity", {})

        superclass = aggregate["classes"]["tileentity.superclass"]
        cf = classloader[superclass]

        # First, figure out whether this is a version where the TE superclass
        # is also the TE list.
        if cf.constants.find_one(
                String, lambda c: c.string.value in
            ('daylight_detector', 'DLDetector')):
            # Yes, it is
            listclass = superclass
        else:
            # It isn't, but we can figure it out by looking at the constructor's only parameter.
            method = cf.methods.find_one(name="<init>")
            assert len(method.args) == 1
            listclass = method.args[0].name
            cf = classloader[listclass]

        aggregate["classes"]["tileentity.list"] = listclass

        method = cf.methods.find_one(name="<clinit>")

        tileentities = te.setdefault("tileentities", {})
        te_classes = te.setdefault("classes", {})
        tmp = {}
        for ins in method.code.disassemble():
            if ins in ("ldc", "ldc_w"):
                const = ins.operands[0]
                if isinstance(const, ConstantClass):
                    # Used before 1.13
                    tmp["class"] = const.name.value
                elif isinstance(const, String):
                    tmp["name"] = const.string.value
            elif ins == "invokedynamic":
                # Used after 1.13
                tmp["class"] = class_from_invokedynamic(ins, cf)
            elif ins == "invokestatic":
                if "class" in tmp and "name" in tmp:
                    tmp["blocks"] = []
                    tileentities[tmp["name"]] = tmp
                    te_classes[tmp["class"]] = tmp["name"]
                    tmp = {}
示例#2
0
    def _entities_1point13(aggregate, classloader, verbose):
        if verbose:
            print("Using 1.13 entity format")

        superclass = aggregate["classes"]["entity.list"]
        cf = classloader[superclass]

        entities = aggregate.setdefault("entities", {})
        entity = entities.setdefault("entity", {})

        method = cf.methods.find_one(name="<clinit>")

        stack = []
        numeric_id = 0
        for ins in method.code.disassemble():
            if ins.mnemonic in ("ldc", "ldc_w"):
                const = ins.operands[0]
                if isinstance(const, ConstantClass):
                    stack.append(const.name.value)
                elif isinstance(const, String):
                    stack.append(const.string.value)
            elif ins.mnemonic == "invokedynamic":
                stack.append(class_from_invokedynamic(ins, cf))
            elif ins.mnemonic == "putstatic":
                if len(stack) in (2, 3):
                    if len(stack) == 3:
                        # In 18w07a, they added a parameter for the entity class,
                        # in addition to the invokedynamic.  Make sure both are the same.
                        assert stack[1] == stack[2]

                    name = stack[0]

                    entity[name] = {
                        "id": numeric_id,
                        "name": name,
                        "class": stack[1]
                    }
                    if "minecraft." + name in aggregate["language"]["entity"]:
                        entity[name]["display_name"] = aggregate["language"][
                            "entity"]["minecraft." + name]

                    numeric_id += 1
                stack = []
示例#3
0
    def identify_block_entities(aggregate, classloader, verbose):
        te = aggregate.setdefault("tileentity", {})

        superclass = aggregate["classes"]["tileentity.superclass"]
        cf = classloader[superclass]

        # First, figure out whether this is a version where the TE superclass
        # is also the TE list.
        if cf.constants.find_one(String, lambda c: c.string.value in ('daylight_detector', 'DLDetector')):
            # Yes, it is
            listclass = superclass
        else:
            # It isn't, but we can figure it out by looking at the constructor's only parameter.
            method = cf.methods.find_one(name="<init>")
            assert len(method.args) == 1
            listclass = method.args[0].name
            cf = classloader[listclass]

        aggregate["classes"]["tileentity.list"] = listclass

        method = cf.methods.find_one(name="<clinit>")

        tileentities = te.setdefault("tileentities", {})
        te_classes = te.setdefault("classes", {})
        tmp = {}
        for ins in method.code.disassemble():
            if ins in ("ldc", "ldc_w"):
                const = ins.operands[0]
                if isinstance(const, ConstantClass):
                    # Used before 1.13
                    tmp["class"] = const.name.value
                elif isinstance(const, String):
                    tmp["name"] = const.string.value
            elif ins == "invokedynamic":
                # Used after 1.13
                tmp["class"] = class_from_invokedynamic(ins, cf)
            elif ins == "invokestatic":
                if "class" in tmp and "name" in tmp:
                    tmp["blocks"] = []
                    tileentities[tmp["name"]] = tmp
                    te_classes[tmp["class"]] = tmp["name"]
                    tmp = {}
示例#4
0
文件: entities.py 项目: mcdevs/Burger
 def on_invokedynamic(self, ins, const):
     # MC uses EntityZombie::new, similar; return the created class
     return class_from_invokedynamic(ins, cf)
示例#5
0
    def act(aggregate, classloader, verbose=False):
        te = aggregate.setdefault("tileentity", {})

        if "tileentity.superclass" not in aggregate["classes"]:
            if verbose:
                print("Missing tileentity.superclass")
            return

        superclass = aggregate["classes"]["tileentity.superclass"]
        cf = classloader[superclass]

        # First, figure out whether this is a version where the TE superclass
        # is also the TE list.
        if cf.constants.find_one(
                String, lambda c: c.string.value in
            ('daylight_detector', 'DLDetector')):
            # Yes, it is
            listclass = superclass
            has_separate_list = - False
        else:
            # It isn't, but we can figure it out by looking at the constructor's only parameter.
            method = cf.methods.find_one(name="<init>")
            assert len(method.args) == 1
            listclass = method.args[0].name
            cf = classloader[listclass]
            has_separate_list = True

        aggregate["classes"]["tileentity.list"] = listclass

        method = cf.methods.find_one(name="<clinit>")

        tileentities = te.setdefault("tileentities", {})
        te_classes = te.setdefault("classes", {})
        tmp = {}
        for ins in method.code.disassemble():
            if ins.mnemonic in ("ldc", "ldc_w"):
                const = ins.operands[0]
                if isinstance(const, ConstantClass):
                    # Used before 1.13
                    tmp["class"] = const.name.value
                elif isinstance(const, String):
                    tmp["name"] = const.string.value
            elif ins.mnemonic == "invokedynamic":
                # Used after 1.13
                tmp["class"] = class_from_invokedynamic(ins, cf)
            elif ins.mnemonic == "invokestatic":
                if "class" in tmp and "name" in tmp:
                    tmp["blocks"] = []
                    tileentities[tmp["name"]] = tmp
                    te_classes[tmp["class"]] = tmp["name"]
                    tmp = {}

        if "tileentity.blockentitytag" in aggregate["classes"]:
            # Block entity tag matches block names to tile entities.
            tag = aggregate["classes"]["tileentity.blockentitytag"]
            tag_cf = classloader[tag]
            method = tag_cf.methods.find_one(name="<clinit>")

            stack = []

            # There may be two fields, one for old/new name and one item/name.
            # Or there may just be item/name.
            num_maps = len(list(tag_cf.fields.find(type_="Ljava/util/Map;")))
            assert num_maps in (1, 2)

            num_getstatic = 0
            for ins in method.code.disassemble():
                if ins.mnemonic == "getstatic":
                    num_getstatic += 1
                    assert num_getstatic <= num_maps
                elif ins.mnemonic in ("ldc", "ldc_w") and num_getstatic != 0:
                    const = ins.operands[0]
                    if isinstance(const, String):
                        stack.append(const.string.value)
                elif ins.mnemonic == "invokeinterface":
                    if len(stack) != 2:
                        if verbose:
                            print("Unexpected stack length for BETag:", stack)
                        stack = []
                        continue

                    entity_id = stack.pop()
                    block_id = stack.pop()
                    if entity_id.startswith("minecraft:"):
                        entity_id = entity_id[len("minecraft:"):]

                    if num_getstatic == num_maps:
                        # The last map is the block name to block entity map
                        if not entity_id in tileentities:
                            if verbose:
                                # This does currently happen in 1.9
                                print("Trying to mark %s as a block with "
                                      "tile entity %s but that tile entity "
                                      "does not exist!" %
                                      (block_id, entity_id))
                        else:
                            tileentities[entity_id]["blocks"].append(block_id)
                    else:
                        # The other map has block name to _old_ block entity
                        # name.  But we don't want that (burger currently
                        # doesn't track the old block entity name).
                        pass
        elif verbose:
            print("No block entity tag info; skipping that")

        nbt_tag_type = "L" + aggregate["classes"]["nbtcompound"] + ";"
        if "nethandler.client" in aggregate["classes"]:
            updatepacket = None
            for packet in six.itervalues(aggregate["packets"]["packet"]):
                if (packet["direction"] != "CLIENTBOUND"
                        or packet["state"] != "PLAY"):
                    continue

                packet_cf = classloader[packet["class"][:-len(
                    ".class"
                )]]  # XXX should we be including the .class sufix in the packet class if we just trim it everywhere we use it?
                # Check if the packet has the expected fields in the class file
                # for the update tile entity packet
                if (len(packet_cf.fields) >= 3 and
                        # Tile entity type int, at least (maybe also position)
                        len(list(packet_cf.fields.find(type_="I"))) >= 1 and
                        # New NBT tag
                        len(list(packet_cf.fields.find(type_=nbt_tag_type)))):
                    # There are other fields, but they vary by version.
                    updatepacket = packet
                    break

            if not updatepacket:
                if verbose:
                    print("Failed to identify update tile entity packet")
                return

            te["update_packet"] = updatepacket
            nethandler = aggregate["classes"]["nethandler.client"]
            nethandler_cf = classloader[nethandler]

            updatepacket_name = updatepacket["class"].replace(".class", "")

            method = nethandler_cf.methods.find_one(args="L" +
                                                    updatepacket_name + ";")

            value = None
            for ins in method.code.disassemble():
                if ins.mnemonic in ("bipush", "sipush"):
                    value = ins.operands[0].value
                elif ins.mnemonic == "instanceof":
                    if value is None:
                        # Ensure the command block callback is not counted
                        continue

                    const = ins.operands[0]
                    te_name = te_classes[const.name.value]
                    tileentities[te_name]["network_id"] = value
                    value = None
示例#6
0
 def on_invokedynamic(self, ins, const, args):
     # MC uses EntityZombie::new, similar; return the created class
     return class_from_invokedynamic(ins, cf)