Beispiel #1
0
    def _load_schematics(self, load_minecraft_specs=True):
        if load_minecraft_specs:
            for premem in minecraft_specs.get_schematics():
                npy = premem["schematic"]
                memid = SchematicNode.create(self, npy_to_blocks_list(npy))
                if premem.get("name"):
                    for n in premem["name"]:
                        self.add_triple(subj=memid,
                                        pred_text="has_name",
                                        obj_text=n)
                        self.add_triple(subj=memid,
                                        pred_text="has_tag",
                                        obj_text=n)
                if premem.get("tags"):
                    for t in premem["tags"]:
                        self.add_triple(subj=memid,
                                        pred_text="has_tag",
                                        obj_text=t)

        # load single blocks as schematics
        bid_to_name = minecraft_specs.get_block_data()["bid_to_name"]
        for (d, m), name in bid_to_name.items():
            if d >= 256:
                continue
            memid = SchematicNode.create(self, [((0, 0, 0), (d, m))])
            self.add_triple(subj=memid, pred_text="has_name", obj_text=name)
            if "block" in name:
                self.add_triple(subj=memid,
                                pred_text="has_name",
                                obj_text=name.strip("block").strip())
            # tag single blocks with 'block'
            self.add_triple(subj=memid, pred_text="has_name", obj_text="block")
Beispiel #2
0
 def handle_no_path(self, agent):
     delta = self.target - agent.pos
     for vec, step_fn_name in self.STEP_FNS.items():
         if np.dot(delta, vec) > 0:
             newpos = agent.pos + vec
             x, y, z = newpos
             newpos_blocks = agent.get_blocks(x, x, y, y + 1, z, z)
             # dig if necessary
             for (bp, idm) in npy_to_blocks_list(newpos_blocks, newpos):
                 self.replace.add((bp, idm))
                 agent.dig(*bp)
             # move
             step_fn = getattr(agent, step_fn_name)
             step_fn()
             break
Beispiel #3
0
    def finish(self, agent):
        xyz, _ = npy_to_blocks_list(self.schematic, self.origin)[0]
        memid = agent.memory.get_block_object_ids_by_xyz(xyz)[0]
        if self.schematic_memid:
            logging.info(
                "tag_block_object_from_schematic {} {}".format(memid, self.schematic_memid)
            )
            agent.memory.tag_block_object_from_schematic(memid, self.schematic_memid)
        if self.schematic_tags:
            for pred, obj in self.schematic_tags:
                logging.info("add block_object triple {} {} {}".format(memid, pred, obj))
                agent.memory.add_triple(memid, pred, obj)
                if pred == "has_name":
                    agent.memory.tag(memid, obj)

        if self.verbose:
            agent.send_chat("I finished building this")
        if self.fill_message:
            agent.send_chat("I finished filling this")
        self.finished = True
Beispiel #4
0
    def _load_schematics(self, load_minecraft_specs=True):
        """Load all Minecraft schematics into agent memory"""
        if load_minecraft_specs:
            for premem in minecraft_specs.get_schematics():
                npy = premem["schematic"]

                # lazy loading, only store memid in db, ((0, 0, 0), (0, 0)) as a placeholder
                memid = SchematicNode.create(self, [((0, 0, 0), (0, 0))])
                self.schematics[memid] = npy_to_blocks_list(npy)

                if premem.get("name"):
                    for n in premem["name"]:
                        self.add_triple(subj=memid,
                                        pred_text="has_name",
                                        obj_text=n)
                        self.add_triple(subj=memid,
                                        pred_text="has_tag",
                                        obj_text=n)
                if premem.get("tags"):
                    for t in premem["tags"]:
                        self.add_triple(subj=memid,
                                        pred_text="has_tag",
                                        obj_text=t)

        # load single blocks as schematics
        bid_to_name = minecraft_specs.get_block_data()["bid_to_name"]
        for (d, m), name in bid_to_name.items():
            if d >= 256:
                continue
            memid = SchematicNode.create(self, [((0, 0, 0), (d, m))])
            self.add_triple(subj=memid, pred_text="has_name", obj_text=name)
            if "block" in name:
                self.add_triple(subj=memid,
                                pred_text="has_name",
                                obj_text=name.strip("block").strip())
            # tag single blocks with 'block'
            self.add_triple(subj=memid, pred_text="has_name", obj_text="block")
Beispiel #5
0
    def step(self, agent):
        self.interrupted = False

        # get blocks occupying build area
        ox, oy, oz = self.origin
        sy, sz, sx, _ = self.schematic.shape
        current = agent.get_blocks(ox, ox + sx - 1, oy, oy + sy - 1, oz, oz + sz - 1)

        # save state for undo()
        if self.old_blocks_list is None:
            self.old_blocks_list = npy_to_blocks_list(current, self.origin)
            if len(self.old_blocks_list) > 0:
                self.old_origin = np.min(util.strip_idmeta(self.old_blocks_list), axis=0)

        # are we done?
        # TODO: diff ignores block meta right now because placing stairs and
        # chests in the appropriate orientation is non-trivial
        diff = (
            (current[:, :, :, 0] != self.schematic[:, :, :, 0])
            & (self.attempts > 0)
            & np.isin(current[:, :, :, 0], BUILD_IGNORE_BLOCKS, invert=True)
        )
        if self.embed:
            diff &= self.schematic[:, :, :, 0] != 0  # don't delete blocks
        for pair in BUILD_INTERCHANGEABLE_PAIRS:
            diff &= np.isin(current[:, :, :, 0], pair, invert=True) | np.isin(
                self.schematic[:, :, :, 0], pair, invert=True
            )
        if not np.any(diff):
            self.finish(agent)
            return

        # blocks that would need to be removed
        remove_mask = diff & (current[:, :, :, 0] != 0)

        # destroy any blocks in the way first
        rel_yzxs = np.argwhere(remove_mask)
        xyzs = [
            (x + self.origin[0], y + self.origin[1], z + self.origin[2]) for (y, z, x) in rel_yzxs
        ]
        if xyzs:
            logging.info("Excavating {} blocks first".format(len(xyzs)))
            agent.memory.task_stack_push(
                Destroy(agent, {"schematic": util.fill_idmeta(agent, xyzs)}),
                parent_memid=self.memid,
            )
            return

        # get next block to place
        yzx = self.get_next_target(agent, current, diff)
        idm = self.schematic[tuple(yzx)]
        current_idm = current[tuple(yzx)]

        # try placing block
        target = yzx[[2, 0, 1]] + self.origin
        logging.debug("trying to place {} @ {}".format(idm, target))
        if tuple(target) in (tuple(agent.pos), tuple(agent.pos + [0, 1, 0])):
            # can't place block where you're standing, so step out of the way
            self.step_any_dir(agent)
            return
        if util.manhat_dist(agent.pos, target) <= self.PLACE_REACH:
            # block is within reach
            assert current_idm[0] != idm[0], "current={} idm={}".format(current_idm, idm)
            if current_idm[0] != 0:
                logging.debug(
                    "removing block {} @ {} from {}".format(current_idm, target, agent.pos)
                )
                agent.dig(*target)
            if idm[0] != 0:
                agent.set_held_item(idm)
                logging.debug("placing block {} @ {} from {}".format(idm, target, agent.pos))
                x, y, z = target
                if agent.place_block(x, y, z):
                    B = agent.get_blocks(x, x, y, y, z, z)
                    if B[0, 0, 0, 0] == idm[0]:
                        agent.memory.pending_agent_placed_blocks.add((x, y, z))
                    else:
                        logging.error(
                            "failed to place block {} @ {}, but place_block returned True. \
                                Got {} instead.".format(
                                idm, target, B[0, 0, 0, :]
                            )
                        )
                    self.new_blocks.append(((x, y, z), idm))
                else:
                    logging.warn("failed to place block {} from {}".format(target, agent.pos))
            self.attempts[tuple(yzx)] -= 1
            if self.attempts[tuple(yzx)] == 0 and not self.giving_up_message_sent:
                agent.send_chat(
                    "I'm skipping a block because I can't place it. Maybe something is in the way."
                )
                self.giving_up_message_sent = True
        else:
            # too far to place; move first
            task = Move(agent, {"target": target, "approx": self.PLACE_REACH}, self.featurizer)
            agent.memory.task_stack_push(task, parent_memid=self.memid)
Beispiel #6
0
    def __init__(self, agent, task_data):
        super(Build, self).__init__()
        self.task_data = task_data
        self.embed = task_data.get("embed", False)
        self.schematic, _ = blocks_list_to_npy(task_data["blocks_list"])
        self.origin = task_data["origin"]
        self.verbose = task_data.get("verbose", True)
        self.relations = task_data.get("relations", [])
        self.default_behavior = task_data.get("default_behavior")
        self.force = task_data.get("force", False)
        self.attempts = 3 * np.ones(self.schematic.shape[:3], dtype=np.uint8)
        self.fill_message = task_data.get("fill_message", False)
        self.schematic_memid = task_data.get("schematic_memid", None)
        self.schematic_tags = task_data.get("schematic_tags", [])
        self.giving_up_message_sent = False
        self.wait = False
        self.old_blocks_list = None
        self.old_origin = None
        self.PLACE_REACH = task_data.get("PLACE_REACH", 3)

        # negative schematic related
        self.is_destroy_schm = task_data.get("is_destroy_schm", False)
        self.dig_message = task_data.get("dig_message", False)
        self.blockobj_memid = None
        self.DIG_REACH = task_data.get("DIG_REACH", 3)
        self.last_stepped_time = agent.memory.get_time()

        if self.is_destroy_schm:
            # is it destroying a whole block object? if so, save its tags
            self.destroyed_block_object_triples = []
            xyzs = set(strip_idmeta(task_data["blocks_list"]))
            mem = agent.memory.get_block_object_by_xyz(next(iter(xyzs)))
            # TODO what if there are several objects being destroyed?
            if mem and all(xyz in xyzs for xyz in mem.blocks.keys()):
                for pred in ["has_tag", "has_name", "has_colour"]:
                    self.destroyed_block_object_triples.extend(
                        agent.memory.get_triples(subj=mem.memid,
                                                 pred_text=pred))
                logging.info("Destroying block object {} tags={}".format(
                    mem.memid, self.destroyed_block_object_triples))

        # modify the schematic to avoid placing certain blocks
        for bad, good in BUILD_BLOCK_REPLACE_MAP.items():
            self.schematic[self.schematic[:, :, :, 0] == bad] = good
        self.new_blocks = []  # a list of (xyz, idm) of newly placed blocks

        # snap origin to ground if bottom level has dirt blocks
        # NOTE(kavyasrinet): except for when we are rebuilding the old dirt blocks, we
        # don't want to change the origin then, hence the self.force check.
        if not self.force and not self.embed and np.isin(
                self.schematic[:, :, :, 0], (2, 3)).any():
            h = ground_height(agent, self.origin, 0)
            self.origin[1] = h[0, 0]

        # get blocks occupying build area and save state for undo()
        ox, oy, oz = self.origin
        sy, sz, sx, _ = self.schematic.shape
        current = agent.get_blocks(ox, ox + sx - 1, oy, oy + sy - 1, oz,
                                   oz + sz - 1)
        self.old_blocks_list = npy_to_blocks_list(current, self.origin)
        if len(self.old_blocks_list) > 0:
            self.old_origin = np.min(strip_idmeta(self.old_blocks_list),
                                     axis=0)