Example #1
0
    def get_next_destroy_target(self, agent, xyzs):
        p = agent.pos
        for i, c in enumerate(sorted(xyzs, key=lambda c: manhat_dist(p, c))):
            path = astar(agent, c, approx=2)
            if path is not None:
                if i > 0:
                    logging.debug(
                        "Destroy get_next_destroy_target wasted {} astars".
                        format(i))
                return c

        # No path to any of the blocks
        return None
Example #2
0
    def find_nearby_new_item_stack(self, agent, id, meta):
        mindist = 3
        near_new_item_stack = None
        x, y, z = agent.get_player().pos
        for item_stack in agent.get_item_stacks():
            if item_stack.item.id == id and item_stack.item.meta == meta:
                dist = manhat_dist(
                    (item_stack.pos.x, item_stack.pos.y, item_stack.pos.z),
                    (x, y, z))
                if dist < mindist:
                    if not agent.memory.get_entity_by_eid(item_stack.entityId):
                        mindist = dist
                        near_new_item_stack = item_stack

        return mindist, near_new_item_stack
Example #3
0
 def find_nearby_new_mob(self, agent):
     mindist = 1000000
     near_new_mob = None
     x, y, z = self.pos
     y = y + 1
     for mob in agent.get_mobs():
         if MOBS_BY_ID[mob.mobType] == self.mobtype:
             dist = manhat_dist((mob.pos.x, mob.pos.y, mob.pos.z),
                                (x, y, z))
             # hope this doesn;t take so long mob gets away...
             if dist < mindist:
                 #                    print(MOBS_BY_ID[mob.mobType], dist)
                 if not agent.memory.get_entity_by_eid(mob.entityId):
                     mindist = dist
                     near_new_mob = mob
     return mindist, near_new_mob
Example #4
0
    def step(self):
        super().step()
        agent = self.agent
        if self.finished:
            return
        self.interrupted = False
        # replace blocks if possible
        R = self.replace.copy()
        self.replace.clear()
        for (pos, idm) in R:
            agent.set_held_item(idm)
            if agent.place_block(*pos):
                logging.debug("Move: replaced {}".format((pos, idm)))
            else:
                # try again later
                self.replace.add((pos, idm))
        if len(self.replace) > 0:
            logging.debug("Replace remaining: {}".format(self.replace))

        # check if finished
        if manhat_dist(tuple(agent.pos), self.target) <= self.approx:
            if len(self.replace) > 0:
                logging.error(
                    "Move finished with non-empty replace set: {}".format(
                        self.replace))
            self.finished = True
            return

        # get path
        if self.path is None or tuple(agent.pos) != self.path[-1]:
            self.path = astar(agent, self.target, self.approx)
            if self.path is None:
                self.handle_no_path(agent)
                return

        # take a step on the path
        assert tuple(agent.pos) == self.path.pop()
        step = tuple(self.path[-1] - agent.pos)
        step_fn = getattr(agent, self.STEP_FNS[step])
        step_fn()

        self.last_stepped_time = agent.memory.get_time()
Example #5
0
    def get_next_place_target(self, agent, current, diff):
        """Return the next block that will be targeted for placing

        In order:
        1. don't build over your own body
        2. build ground-up
        3. try failed blocks again at the end
        4. build closer blocks first

        Args:
        - current: yzxb-ordered current state of the region
        - diff: a yzx-ordered boolean mask of blocks that need addressing
        """
        relpos_yzx = (agent.pos - self.origin)[[1, 2, 0]]

        diff_yzx = list(np.argwhere(diff))
        diff_yzx.sort(key=lambda yzx: manhat_dist(yzx, relpos_yzx))  # 4
        diff_yzx.sort(key=lambda yzx: -self.attempts[tuple(yzx)])  # 3
        diff_yzx.sort(key=lambda yzx: yzx[0])  # 2
        diff_yzx.sort(key=lambda yzx: tuple(yzx) in
                      (tuple(relpos_yzx), tuple(relpos_yzx + [1, 0, 0])))  # 1
        return diff_yzx[0]
Example #6
0
 def step(self):
     super().step()
     agent = self.agent
     if manhat_dist(agent.pos, self.pos) > self.PLACE_REACH:
         task = Move(agent, {
             "target": self.pos,
             "approx": self.PLACE_REACH
         })
         self.add_child_task(task)
     else:
         agent.set_held_item(self.object_idm)
         if np.equal(self.pos, agent.pos).all():
             agent.step_neg_z()
         x, y, z = self.pos
         y = y + 1
         agent.place_block(x, y, z)
         time.sleep(0.1)
         mindist, placed_mob = self.find_nearby_new_mob(agent)
         if mindist < 3:
             memid = MobNode.create(agent.memory,
                                    placed_mob,
                                    agent_placed=True)
             mobmem = agent.memory.get_mem_by_id(memid)
             agent.memory.update_recent_entities(mems=[mobmem])
             if self.memid is not None:
                 agent.memory.add_triple(subj=self.memid,
                                         pred_text="task_effect_",
                                         obj=mobmem.memid)
                 # the chat_effect_ triple was already made when the task is added if there was a chat...
                 # but it points to the task memory.  link the chat to the mob memory:
                 chat_mem_triples = agent.memory.get_triples(
                     subj=None, pred_text="chat_effect_", obj=self.memid)
                 if len(chat_mem_triples) > 0:
                     chat_memid = chat_mem_triples[0][0]
                     agent.memory.add_triple(subj=chat_memid,
                                             pred_text="chat_effect_",
                                             obj=mobmem.memid)
         self.finished = True
Example #7
0
    def step(self):
        super().step()
        agent = self.agent
        if self.finished:
            return
        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)

        # 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))

        # ignore negative blocks if there is already air there
        diff &= (self.schematic[:, :, :, 0] + current[:, :, :, 0]) >= 0

        if self.embed:
            diff &= self.schematic[:, :, :,
                                   0] != 0  # don't delete blocks if self.embed

        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 (or any that are slated to be destroyed in schematic)
        # first
        rel_yzxs = np.argwhere(remove_mask)
        xyzs = set([(x + self.origin[0], y + self.origin[1],
                     z + self.origin[2]) for (y, z, x) in rel_yzxs])
        if len(xyzs) != 0:
            logging.debug("Excavating {} blocks first".format(len(xyzs)))
            target = self.get_next_destroy_target(agent, xyzs)
            if target is None:
                logging.debug("No path from {} to {}".format(agent.pos, xyzs))
                agent.send_chat("There's no path, so I'm giving up")
                self.finished = True
                return

            if manhat_dist(agent.pos, target) <= self.DIG_REACH:
                success = agent.dig(*target)
                if success:
                    agent.memory.maybe_remove_inst_seg(target)
                    if self.is_destroy_schm:
                        agent.memory.maybe_remove_block_from_memory(
                            target, (0, 0), agent.areas_to_perceive)
                    else:
                        interesting, player_placed, agent_placed = agent.perception_modules[
                            "low_level"].mark_blocks_with_env_change(
                                target,
                                (0, 0),
                                agent.low_level_data["boring_blocks"],
                                agent_placed=True,
                            )
                        agent.memory.maybe_add_block_to_memory(
                            interesting, player_placed, agent_placed, target,
                            (0, 0))
                        self.add_tags(agent, (target, (0, 0)))
                    agent.get_changed_blocks()
            else:
                mv = Move(agent, {"target": target, "approx": self.DIG_REACH})
                self.add_child_task(mv)

            return

        # for a build task with destroy schematic,
        # it is done when all different blocks are removed
        elif self.is_destroy_schm:
            self.finish(agent)
            return

        # get next block to place
        yzx = self.get_next_place_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 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]:
                        interesting, player_placed, agent_placed = agent.perception_modules[
                            "low_level"].mark_blocks_with_env_change(
                                (x, y, z),
                                tuple(idm),
                                agent.low_level_data["boring_blocks"],
                                agent_placed=True,
                            )
                        agent.memory.maybe_add_block_to_memory(
                            interesting, player_placed, agent_placed,
                            (x, y, z), tuple(idm))
                        changed_blocks = agent.get_changed_blocks()
                        self.new_blocks.append(((x, y, z), tuple(idm)))
                        self.add_tags(agent, ((x, y, z), tuple(idm)))
                    else:
                        logging.error(
                            "failed to place block {} @ {}, but place_block returned True. \
                                Got {} instead.".format(
                                idm, target, B[0, 0, 0, :]))
                else:
                    logging.warn("failed to place block {} from {}".format(
                        target, agent.pos))
                if idm[0] == 6:  # hacky: all saplings have id 6
                    agent.set_held_item([351,
                                         15])  # use bone meal on tree saplings
                    if len(changed_blocks) > 0:
                        sapling_pos = changed_blocks[0][0]
                        x, y, z = sapling_pos
                        for _ in range(
                                6
                        ):  # use at most 6 bone meal (should be enough)
                            agent.use_item_on_block(x, y, z)
                            changed_blocks = agent.get_changed_blocks()
                            changed_block_poss = {
                                block[0]
                                for block in changed_blocks
                            }
                            # sapling has grown to a full tree, stop using bone meal
                            if (x, y, z) in changed_block_poss:
                                break

            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.add_child_task(task)