import re import time import importlib import random from itertools import count from math import hypot from minecraft.networking.types import BlockFace from protocol.managers import ChunkNotLoadedException import utils importlib.reload(utils) import path importlib.reload(path) import blocks importlib.reload(blocks) import items importlib.reload(items) import mcdata importlib.reload(mcdata) import mobs importlib.reload(mobs) class FindGappleStates: def idle(self): return None def init(self): self.state = self.go_spectator def go_spectator(self): print('Going spectator...') self.g.chat.send('/gamemode spectator') self.state = self.tp_to_coord def tp_to_coord(self): step = utils.spiral(self.count) step_scaled = utils.pmul(step, 192) self.coord = utils.padd(self.origin, step_scaled) self.coord = (self.coord[0], 50, self.coord[2]) print('count:', self.count, 'teleporting to:', self.coord) self.g.chat.send('/tp {} {} {}'.format(*self.coord)) self.g.command_lock = True self.state = self.wait_for_load def wait_for_load(self): if self.g.command_lock: return if self.g.chunks.check_loaded(self.g.pos, 169): print('chunks have been loaded') self.state = self.pick_chest def pick_chest(self): chest_list = [] for chest_id in blocks.CHEST_IDS: chest_list.extend(self.g.chunks.index.get(chest_id, [])) for chest in chest_list: if chest in self.checked_chests: # slow but simple continue if utils.phyp_king(self.coord, chest) > 96: # skip because we can't detect item drops continue self.current_chest = chest self.checked_chests.append(self.current_chest) self.state = self.break_chest break else: # for print('exhausted chest list') self.state = self.cleanup def break_chest(self): print('Breaking chest', self.current_chest) self.g.command_lock = True self.g.item_lock = True self.g.chat.send('/setblock {} {} {} air destroy'.format(*self.current_chest)) self.wait_time = 0.5 self.state = self.wait_for_items def wait_for_items(self): # wait for command to execute if self.g.command_lock: return # wait for items to drop if self.wait_time > 0: self.wait_time -= utils.TICK else: print('done waiting for items') self.state = self.pick_chest def cleanup(self): self.count += 1 self.state = self.done def done(self): # never gets ran, placeholder return None def __init__(self, global_state): self.g = global_state self.state = self.idle self.origin = utils.pint(self.g.pos) self.count = 0 self.coord = None self.current_chest = None self.checked_chests = [] self.wait_time = 0 def run(self): self.state() class GatherCropStates: def idle(self): return None def init(self): self.state = self.find_new_crop def find_new_crop(self): print('Finding new crop...') w = self.g.world p = utils.pint(self.g.pos) mature_crops = [ blocks.MATURE_WHEAT_ID, blocks.MATURE_POTATO_ID, blocks.MATURE_CARROT_ID, blocks.MATURE_BEETROOT_ID, ] for crop in w.find_blocks_3d(p, mature_crops, 50, 20): print('Found crop:', crop) if crop not in self.bad_crops: break else: # for print('No good crops left, aborting.') self.state = self.cleanup return self.crop = crop self.type_id = w.block_at(*crop) self.state = self.nav_to_crop def nav_to_crop(self): w = self.g.world p = utils.pint(self.g.pos) navpath = w.path_to_place(p, self.crop) if navpath: self.g.path = navpath self.g.look_at = utils.padd(self.crop, path.BLOCK_BELOW) self.state = self.going_to_crop else: self.bad_crops.append(self.crop) self.state = self.find_new_crop def going_to_crop(self): if utils.pint(self.g.pos) == self.crop: print('At the crop') self.state = self.break_crop def break_crop(self): self.g.game.break_block(self.crop) self.wait_time = 0.5 self.state = self.wait def wait(self): # wait for the item if self.wait_time > 0: self.wait_time -= utils.TICK else: self.state = self.select_seed def select_seed(self): p = utils.pint(self.g.pos) crop_seeds = { blocks.MATURE_WHEAT_ID: items.WHEAT_SEEDS_ID, blocks.MATURE_POTATO_ID: items.POTATO_ID, blocks.MATURE_CARROT_ID: items.CARROT_ID, blocks.MATURE_BEETROOT_ID: items.BEETROOT_SEEDS_ID, } if self.g.game.select_item([crop_seeds[self.type_id]]): self.state = self.wait_select self.wait_time = 0.5 else: print('Aborting planting, no crop') self.state = self.cleanup def wait_select(self): # wait a bit to select if self.wait_time > 0: self.wait_time -= utils.TICK else: self.state = self.place_crop def place_crop(self): p = utils.pint(self.g.pos) self.g.game.place_block(p, BlockFace.TOP) print('Placed crop') self.state = self.wait_place self.wait_time = 0.5 def wait_place(self): # wait a bit for chunk data to update if self.wait_time > 0: self.wait_time -= utils.TICK else: self.state = self.cleanup def cleanup(self): self.g.look_at = None self.state = self.done def done(self): # never gets ran, placeholder return None def __init__(self, global_state): self.g = global_state self.state = self.idle self.crop = None self.type_id = None self.bad_crops = [] self.wait_time = 0 def run(self): self.state() class GatherWartStates: def idle(self): return None def init(self): self.state = self.find_new_wart def find_new_wart(self): print('Finding new wart...') w = self.g.world p = utils.pint(self.g.pos) mature_wart = max(blocks.NETHERWART_IDS) for wart in w.find_blocks_3d(p, [mature_wart], 50, 20): print('Found wart:', wart) if wart not in self.bad_warts: break else: # for print('No good warts left, aborting.') self.state = self.cleanup return self.wart = wart self.state = self.nav_to_wart def nav_to_wart(self): w = self.g.world p = utils.pint(self.g.pos) navpath = w.path_to_place(p, self.wart) if navpath: self.g.path = navpath self.g.look_at = utils.padd(self.wart, path.BLOCK_BELOW) self.state = self.going_to_wart else: self.bad_warts.append(wart) self.state = self.find_new_wart def going_to_wart(self): if utils.pint(self.g.pos) == self.wart: print('At the wart') self.state = self.break_wart def break_wart(self): self.g.game.break_block(self.wart) self.wait_time = 0.5 self.state = self.wait def wait(self): # wait for the item if self.wait_time > 0: self.wait_time -= utils.TICK else: self.state = self.select_wart def select_wart(self): p = utils.pint(self.g.pos) if self.g.game.select_item(items.NETHERWART_ID): self.state = self.wait_select self.wait_time = 0.5 else: print('Aborting planting, no wart') self.state = self.cleanup def wait_select(self): # wait a bit to select if self.wait_time > 0: self.wait_time -= utils.TICK else: self.state = self.place_wart def place_wart(self): p = utils.pint(self.g.pos) self.g.game.place_block(p, BlockFace.TOP) print('Placed wart') self.state = self.wait_place self.wait_time = 0.5 def wait_place(self): # wait a bit for chunk data to update if self.wait_time > 0: self.wait_time -= utils.TICK else: self.state = self.cleanup def cleanup(self): self.g.look_at = None self.state = self.done def done(self): # never gets ran, placeholder return None def __init__(self, global_state): self.g = global_state self.state = self.idle self.wart = None self.bad_warts = [] self.wait_time = 0 def run(self): self.state() class GatherWoodStates: def bair(self, p): return self.g.chunks.get_block_at(*p) in blocks.NON_SOLID_IDS def blog(self, p): return self.g.chunks.get_block_at(*p) in blocks.LOG_IDS def idle(self): return None def init(self): self.g.chopped_tree = False self.state = self.select_axe def select_axe(self): self.g.game.select_item(items.AXE_IDS) self.state = self.find_new_tree def find_new_tree(self): print('Finding new tree...') w = self.g.world p = utils.pint(self.g.pos) for tree in w.find_trees(p, 100): print('Found tree:', tree) if tree not in self.bad_trees: break else: # for print('No good trees left, aborting.') self.state = self.cleanup return self.tree = tree self.type = blocks.BLOCKS[w.block_at(*tree)].replace('_log', '') print('Type:', self.type) self.state = self.find_openings def find_openings(self): w = self.g.world self.openings = w.find_tree_openings(self.tree) self.state = self.choose_opening def choose_opening(self): w = self.g.world p = utils.pint(self.g.pos) print('openings:', self.openings) if not len(self.openings): print('Unable to get to tree', self.tree) if self.tree not in self.good_trees: self.bad_trees.append(self.tree) self.state = self.cleanup return navpath = w.path_to_place(p, self.openings[0]) if navpath: self.g.path = navpath self.state = self.going_to_tree else: self.openings.pop(0) def going_to_tree(self): if utils.pint(self.g.pos) == self.openings[0]: self.g.look_at = self.tree self.state = self.clear_leaves def clear_leaves(self): if not self.g.breaking: p = utils.pint(self.g.pos) diff = utils.psub(self.tree, p) for x in utils.diffrange(diff[0]): for z in utils.diffrange(diff[2]): for y in range(2): check = utils.padd(p, (x, y, z)) if check == self.tree: break if not self.bair(check): print('Breaking leaf') self.g.game.break_block(check) return self.state = self.clear_trunk_base def clear_trunk_base(self): if not self.g.breaking: base = self.tree above = utils.padd(self.tree, path.BLOCK_ABOVE) if self.blog(base): self.g.game.break_block(base) print('breaking base') elif self.blog(above): self.g.game.break_block(above) print('breaking above') else: w = self.g.world p = utils.pint(self.g.pos) navpath = w.path_to_place(p, self.tree) if navpath: self.g.path = navpath self.state = self.going_to_trunk_base else: self.openings.pop(0) self.state = self.choose_opening def going_to_trunk_base(self): if utils.pint(self.g.pos) == self.tree: self.g.look_at = utils.padd(self.tree, path.BLOCK_ABOVE2) self.state = self.clear_trunk def clear_trunk(self): if not self.g.breaking: check = self.tree count = 0 while self.bair(check) and count < 6: check = utils.padd(check, path.BLOCK_ABOVE) count += 1 if self.blog(check): print('breaking log', check) self.g.game.break_block(check) else: print('Finished clearing tree') self.wait_time = 0.5 self.state = self.wait def wait(self): # wait for the last log to fall if self.wait_time > 0: self.wait_time -= utils.TICK else: self.g.chopped_tree = self.type self.good_trees.append(self.tree) self.state = self.check_pos def check_pos(self): # make sure we are at base of trunk # doesn't always happen, for some reason if utils.pint(self.g.pos) == self.tree: self.state = self.cleanup else: self.state = self.find_openings def cleanup(self): self.g.look_at = None self.state = self.done def done(self): # never gets ran, placeholder return None def __init__(self, global_state): self.g = global_state self.state = self.idle self.tree = None self.type = None self.openings = [] self.bad_trees = [] self.good_trees = [] self.wait_time = 0 def run(self): self.state() class GatherSandStates: def bair(self, p): return self.g.chunks.get_block_at(*p) in blocks.NON_SOLID_IDS def bsand(self, p): return self.g.chunks.get_block_at(*p) == blocks.SAND def idle(self): return None def init(self): self.state = self.select_shovel def select_shovel(self): self.g.game.select_item(items.SHOVEL_IDS) self.state = self.find_new_slice def find_new_slice(self): print('Finding new slice...') w = self.g.world print('using origin', self.origin) start = time.time() self.prev_layer, s = w.find_sand_slice(self.origin, 200, 10, self.bad_slices, self.prev_layer) print('Found slice:', s, 'in', time.time() - start, 'seconds') if s: self.slice = s self.bad_slices.append(s) self.state = self.find_new_sand else: print('No slices remaining.') self.state = self.cleanup def find_new_sand(self): print('Finding new sand...') w = self.g.world p = utils.pint(self.g.pos) head = utils.padd(p, path.BLOCK_ABOVE) for sand in w.find_sand(self.slice, 2, p): if sand not in self.bad_sand: print('Found sand:', sand) break else: # for print('No good sands left, aborting.') self.state = self.cleanup return self.sand = sand if utils.phyp(head, self.sand) < blocks.BREAK_DISTANCE: self.state = self.dig_sand else: self.state = self.nav_to_sand def nav_to_sand(self): w = self.g.world p = utils.pint(self.g.pos) c = self.g.chunks tmp = c.get_block_at(*self.sand) c.set_block_at(*self.sand, blocks.AIR) navpath = w.path_to_place(p, self.sand) c.set_block_at(*self.sand, tmp) if navpath: self.g.path = navpath[:-1] self.state = self.going_to_sand else: print('Cant get to that sand') self.bad_sand.append(self.sand) self.state = self.find_new_sand def going_to_sand(self): if not len(self.g.path): self.g.look_at = self.sand self.state = self.dig_sand def dig_sand(self): if not self.g.breaking: if self.bsand(self.sand): self.g.look_at = self.sand self.g.game.break_block(self.sand) print('digging sand') else: self.state = self.find_new_sand def cleanup(self): self.g.look_at = None self.state = self.done def done(self): # never gets ran, placeholder return None def __init__(self, global_state): self.g = global_state self.state = self.idle self.origin = utils.pint(self.g.pos) self.origin = (2019, 64, 238) self.slice = None self.bad_slices = [] self.prev_layer = 0 self.sand = None self.bad_sand = [] self.wait_time = 0 def run(self): self.state() class GrabSandStates: def idle(self): return None def init(self): self.state = self.find_sand print('Trying to grab sand') def find_sand(self): w = self.g.world p = utils.pint(self.g.pos) sand = w.find_objects([items.SAND_ID]) if not sand: print('No sand objects found, aborting') self.state = self.cleanup return sand.sort(key=lambda s: utils.phyp(p, (s.x, s.y, s.z))) for s in sand: s_pos = utils.pint((s.x, s.y, s.z)) check = utils.padd(s_pos, path.BLOCK_BELOW) if utils.phyp(p, s_pos) > 6: continue # skip if the sand is floating if self.g.chunks.get_block_at(*check) in {0}: continue if s.entity_id in self.eid_blacklist: continue self.eid_blacklist.append(s.entity_id) navpath = w.path_to_place(p, s_pos) if navpath: self.g.path = navpath self.state = self.going_to_sand self.sand = s_pos print('Going to sand', self.sand) return else: print('Cant get to sand', self.sand) print('Cant get to any more sand, aborting') self.state = self.cleanup def going_to_sand(self): if utils.pint(self.g.pos) == self.sand: self.state = self.cleanup def cleanup(self): self.g.look_at = None self.state = self.done def done(self): # never gets ran, placeholder return None def __init__(self, global_state): self.g = global_state self.state = self.idle self.sand = None self.eid_blacklist = [] def run(self): self.state() class SleepWithBedStates: def idle(self): return None def init(self): if self.g.time < 12000: print('Aborting sleep, not night') self.state = self.cleanup return if self.g.dimension != 'overworld': print('Aborting sleep, not in overworld') self.state = self.cleanup return self.state = self.select_bed def select_bed(self): if self.g.game.select_item(items.BED_IDS): self.state = self.find_bed_spot else: print('No bed, aborting.') self.state = self.cleanup def find_bed_spot(self): print('Finding a bed spot...') w = self.g.world p = utils.pint(self.g.pos) for area in w.find_bed_areas(p, 100): print('Found area:', area) if area not in self.bad_areas: break else: # for print('Unable to find area') self.state = self.cleanup return self.area = area openings = w.find_bed_openings(self.area) for o in openings: navpath = w.path_to_place(p, o) self.opening = o if navpath: break else: # for print('Unable to get to bed area', self.area) self.bad_areas.append(self.area) self.state = self.cleanup return self.g.path = navpath self.state = self.going_to_area def going_to_area(self): if utils.pint(self.g.pos) == self.opening: self.g.look_at = utils.padd(self.area, path.BLOCK_BELOW) self.state = self.place_bed def place_bed(self): self.g.game.place_block(self.area, BlockFace.TOP) self.state = self.use_bed def use_bed(self): if self.g.time > 12550: print('Sleeping') self.g.game.place_block(self.area, BlockFace.TOP) if not self.silent: self.g.chat.send('zzz') self.state = self.sleep_bed def sleep_bed(self): w = self.g.world p = utils.pint(self.g.pos) threats = w.find_threats(p, 30) if threats: print('Waking up due to threats:') print(threats) self.g.game.leave_bed() self.state = self.break_bed elif self.g.time < 100: print('Woke up time') self.state = self.break_bed def break_bed(self): self.g.game.break_block(self.area) self.state = self.collect_bed def collect_bed(self): if not self.g.breaking: self.g.path = [utils.padd(self.area, utils.spiral(n)) for n in range(9)] self.wait_time = 2 self.state = self.wait def wait(self): # wait to pick up bed if self.wait_time > 0: self.wait_time -= utils.TICK else: self.state = self.cleanup def cleanup(self): self.g.look_at = None self.state = self.done def done(self): # never gets ran, placeholder return None def __init__(self, global_state): self.g = global_state self.state = self.idle self.silent = False self.area = None self.opening = None self.bad_areas = [] self.wait_time = 0 def run(self): self.state() class CacheItemsStates: def idle(self): return None def init(self): self.skip_slots = [] self.skip_items = [] num_stacks = len([x for x in self.g.inv.values() if x.present]) print('Inventory amount:', num_stacks) if num_stacks >= self.minimum: self.state = self.find_trapped_chests else: print('Aborting caching, not full') self.state = self.cleanup def find_trapped_chests(self): print('Finding trapped chests...') w = self.g.world p = utils.pint(self.g.pos) self.trapped_chests = w.find_blocks_indexed(p, blocks.TRAPPED_CHEST_IDS) print('Found:', self.trapped_chests) self.state = self.choose_trapped_chest def choose_trapped_chest(self): print('Choosing a trapped chest...') w = self.g.world p = utils.pint(self.g.pos) c = self.g.chunks if not len(self.trapped_chests): print('No trapped chests') self.state = self.select_chest return chest = self.trapped_chests[0] tmp = c.get_block_at(*chest) c.set_block_at(*chest, blocks.AIR) navpath = w.path_to_place(p, chest) c.set_block_at(*chest, tmp) print('navpath:', navpath) if navpath: self.g.path = navpath[:-1] self.opening = self.g.path[-1] self.area = chest self.state = self.going_to_trapped_chest return else: self.trapped_chests.pop(0) def going_to_trapped_chest(self): if utils.pint(self.g.pos) == self.opening: self.g.look_at = self.area self.state = self.open_chest def select_chest(self): if self.g.game.select_item([items.CHEST_ID]): self.state = self.find_cache_spot else: print('No chest, aborting') self.state = self.cleanup def find_cache_spot(self): print('Finding a chest spot...') w = self.g.world p = utils.pint(self.g.pos) for area in w.find_cache_areas(p, 100): print('Found area:', area) if area not in self.bad_areas: break else: # for print('Unable to find area') self.state = self.cleanup return self.area = area openings = w.find_cache_openings(self.area) for o in openings: navpath = w.path_to_place(p, o) self.opening = o if navpath: break else: # for print('Unable to get to cache area', self.area) self.bad_areas.append(self.area) self.state = self.cleanup return self.g.path = navpath self.state = self.going_to_area def going_to_area(self): if utils.pint(self.g.pos) == self.opening: self.g.look_at = self.area self.state = self.place_chest def place_chest(self): self.g.game.place_block(self.area, BlockFace.TOP) self.state = self.open_chest def open_chest(self): print('Opening chest') self.g.game.open_container(self.area) self.wait_time = 1 self.state = self.wait def wait(self): # wait for server to send us chest contents if self.wait_time > 0: self.wait_time -= utils.TICK else: self.state = self.move_items def move_items(self): if self.g.item_lock: return w = self.g.window w_info = mcdata.WINDOWS[w.data.window_type] w_inventory_slots = w_info.inventory slot_list = [] for slot_num in w_inventory_slots: if slot_num not in w.contents: continue slot = w.contents[slot_num] if not slot.present: continue if slot.item_id in self.needed_items: continue if slot_num in self.skip_slots: continue slot_list.append((slot_num, slot)) slot_list.sort(key=lambda x: x[1].item_count, reverse=True) for slot_num, slot in slot_list: if slot.item_id in self.wanted_items and slot.item_id not in self.skip_items: print('skipping wanted item', slot) self.skip_slots.append(slot_num) self.skip_items.append(slot.item_id) continue print('moving', slot) self.g.item_lock = True self.g.game.click_window(slot_num, 0, 1, slot) return print('nothing left to move') self.state = self.close_chest def close_chest(self): print('closing chest') self.g.game.close_window() if not self.silent: self.g.chat.send('cache at ' + str(self.area)[1:-1]) self.state = self.cleanup def cleanup(self): self.g.look_at = None self.state = self.done def done(self): # never gets ran, placeholder return None def __init__(self, global_state): self.g = global_state self.state = self.idle self.minimum = 27 self.silent = False # keep all needed items self.needed_items = items.NEEDED_ITEMS # keep one stack of wanted items self.wanted_items = items.WANTED_ITEMS self.skip_slots = [] self.skip_items = [] self.area = None self.opening = None self.trapped_chests = [] self.bad_areas = [] self.wait_time = 0 def run(self): self.state() class GrabSuppliesStates: def idle(self): return None def init(self): if self.supplies: self.state = self.check_supplies else: print('Aborting getting supplies, none specified') self.state = self.cleanup def check_supplies(self): for items, maximum in self.supplies.items(): print('Checking items:', items) num_items = self.g.game.count_items(items) print('Have:', num_items) if num_items: print('Skipping') continue else: self.target_items = items self.maximum_items = maximum self.count = 0 self.state = self.find_barrels return print('Aborting, don\'t need any more supplies') self.state = self.cleanup def find_barrels(self): print('Finding barrels...') w = self.g.world p = utils.pint(self.g.pos) self.barrels = w.find_blocks_indexed(p, blocks.BARREL_IDS) print('Found:', self.barrels) self.state = self.choose_barrel def choose_barrel(self): print('Choosing a barrel...') w = self.g.world p = utils.pint(self.g.pos) c = self.g.chunks if not len(self.barrels): print('No barrels') self.state = self.cleanup return barrel = self.barrels[0] tmp = c.get_block_at(*barrel) c.set_block_at(*barrel, blocks.AIR) navpath = w.path_to_place(p, barrel) c.set_block_at(*barrel, tmp) print('navpath:', navpath) if navpath: self.g.path = navpath[:-1] self.opening = self.g.path[-1] self.area = barrel self.state = self.going_to_barrel return else: self.barrels.pop(0) def going_to_barrel(self): if utils.pint(self.g.pos) == self.opening: self.g.look_at = self.area self.state = self.open_barrel def open_barrel(self): print('Opening barrel') self.g.game.open_container(self.area) self.wait_time = 1 self.state = self.wait def wait(self): # wait for server to send us barrel contents if self.wait_time > 0: self.wait_time -= utils.TICK else: self.state = self.grab_items def grab_items(self): if self.g.item_lock: return w = self.g.window w_info = mcdata.WINDOWS[w.data.window_type] w_container_slots = w_info.container for slot_num in w_container_slots: if slot_num not in w.contents: continue slot = w.contents[slot_num] if not slot.present: continue if slot.item_id not in self.target_items: continue if self.maximum_items and self.count >= self.maximum_items: break self.count += 1 print('Moving', slot) self.g.item_lock = True self.g.game.click_window(slot_num, 0, 1, slot) return print('Nothing left to move') self.state = self.close_barrel def close_barrel(self): print('Closing barrel') self.g.game.close_window() self.state = self.cleanup def cleanup(self): self.g.look_at = None self.state = self.done def done(self): # never gets ran, placeholder return None def __init__(self, global_state): self.g = global_state self.state = self.idle self.supplies = {} self.target_supplies = [] self.barrels = [] self.target_items = None self.maximum_items = 0 self.count = 0 self.area = None self.opening = None self.wait_time = 0 def run(self): self.state() class PlantTreeStates: def idle(self): return None def init(self): if self.g.chopped_tree: self.state = self.check_feet else: print('Aborting planting, did not plant') self.state = self.cleanup def check_feet(self): p = utils.pint(self.g.pos) # check for air at feet if self.g.chunks.get_block_at(*p) in [0]: self.state = self.select_sapling else: print('Aborting planting, feet not air') self.state = self.cleanup def select_sapling(self): p = utils.pint(self.g.pos) sapling_type = self.g.chopped_tree + '_sapling' sapling_item = items.get_id(sapling_type) if self.g.game.select_item([sapling_item]): self.g.look_at = utils.padd(p, path.BLOCK_BELOW) self.state = self.wait_select self.wait_time = 1 else: print('Aborting planting, no', sapling_type) self.state = self.cleanup def wait_select(self): # wait a bit to look down if self.wait_time > 0: self.wait_time -= utils.TICK else: self.state = self.place_sapling def place_sapling(self): p = utils.pint(self.g.pos) self.g.game.place_block(p, BlockFace.TOP) print('Placed sapling') self.state = self.wait_place self.wait_time = 1 def wait_place(self): # wait a bit for chunk data to update if self.wait_time > 0: self.wait_time -= utils.TICK else: self.state = self.find_open_spot def find_open_spot(self): w = self.g.world p = utils.pint(self.g.pos) for opening in w.find_tree_openings(p)[::-1]: print('trying sapling opening', opening) navpath = w.path_to_place(p, opening) if navpath: self.g.path = navpath self.area = opening self.state = self.going_to_area return else: # for print('cant escape sapling') self.state = self.cleanup def going_to_area(self): if utils.pint(self.g.pos) == self.area: self.state = self.cleanup def cleanup(self): self.g.look_at = None self.state = self.done def done(self): # never gets ran, placeholder return None def __init__(self, global_state): self.g = global_state self.state = self.idle self.wait_time = 0 self.area = None def run(self): self.state() class ClearLeavesStates: def idle(self): return None def init(self): if self.g.chopped_tree: sapling_type = self.g.chopped_tree + '_sapling' sapling_item = items.get_id(sapling_type) num_saplings = self.g.game.count_items([sapling_item]) print('Have', num_saplings, sapling_type, 'in inventory') if num_saplings > 8: print('Aborting clearing leaves') self.state = self.cleanup return self.state = self.select_log print('Clearing leaves...') def select_log(self): # select a log to avoid using tools self.g.game.select_item(items.LOG_IDS) self.state = self.find_leaves def find_leaves(self): w = self.g.world p = utils.pint(self.g.pos) pos = utils.padd(p, path.BLOCK_ABOVE) for l in w.find_leaves(pos, blocks.BREAK_DISTANCE): self.leaves.append(l) self.state = self.break_leaves def break_leaves(self): if not self.g.breaking: if self.leaves: leaf = self.leaves.pop(0) self.g.look_at = leaf self.g.game.break_block(leaf) print('Breaking leaf', leaf) else: self.wait_time = 1 self.state = self.wait def wait(self): # wait for the items to drop if self.wait_time > 0: self.wait_time -= utils.TICK else: self.state = self.cleanup def cleanup(self): self.g.look_at = None self.state = self.done def done(self): # never gets ran, placeholder return None def __init__(self, global_state): self.g = global_state self.state = self.idle self.leaves = [] self.wait_time = 0 def run(self): self.state() class GrabSaplingStates: def idle(self): return None def init(self): self.state = self.find_saplings print('Trying to grab a sapling') def find_saplings(self): w = self.g.world p = utils.pint(self.g.pos) saplings = w.find_objects(items.SAPLING_IDS) if not saplings: print('No sapling objects found, aborting') self.state = self.cleanup return saplings.sort(key=lambda s: utils.phyp(p, (s.x, s.y, s.z))) for s in saplings: s_pos = utils.pint((s.x, s.y, s.z)) check = utils.padd(s_pos, path.BLOCK_BELOW) if s.entity_id in self.eid_blacklist: continue # skip if the sapling is floating if self.g.chunks.get_block_at(*check) in blocks.LEAF_IDS | {0}: continue navpath = w.path_to_place(p, s_pos) if navpath: self.g.path = navpath self.state = self.going_to_sapling self.sapling = s_pos self.eid_blacklist.append(s.entity_id) print('Going to sapling', self.sapling) return print('Cant get to any more saplings, aborting') self.state = self.cleanup def going_to_sapling(self): if utils.pint(self.g.pos) == self.sapling: self.state = self.find_saplings def cleanup(self): self.g.look_at = None self.state = self.done def done(self): # never gets ran, placeholder return None def __init__(self, global_state): self.g = global_state self.state = self.idle self.sapling = None self.eid_blacklist = [] def run(self): self.state() class CheckThreatsStates: def idle(self): return None def init(self): self.state = self.find_threats print('Checking for threats') def find_threats(self): w = self.g.world p = utils.pint(self.g.pos) threats = w.find_threats(p, 40) if threats: print('Found', len(threats), 'threats, fleeing:') print(threats) self.state = self.find_safety else: print('Aborting, no threats') self.state = self.cleanup def find_safety(self): w = self.g.world p = utils.pint(self.g.pos) safety = w.find_blocks_indexed(p, [blocks.EMERALD_BLOCK]) if not safety: print('No emerald blocks found, aborting') self.state = self.cleanup return safety.sort(key=lambda s: utils.phyp(p, s)) print('Found emerald blocks:', safety) for s in safety: s = utils.padd(s, path.BLOCK_ABOVE) navpath = w.path_to_place(p, s) if navpath: self.g.path = navpath self.state = self.going_to_safety self.safety = s print('Going to safety', self.safety) return else: print('Cant get to safety', self.safety) print('Cant get to safety, aborting') self.state = self.cleanup def going_to_safety(self): if utils.pint(self.g.pos) == self.safety: print('At safety spot, waiting to be moved') self.state = self.wait_for_move def wait_for_move(self): # wait for the server to move the bot when it's safe # ie. a piston + daylight sensor if utils.pint(self.g.pos) != self.safety: print('Moved, resuming job') self.state = self.wait self.wait_time = 3 def wait(self): # wait to land, etc if self.wait_time > 0: self.wait_time -= utils.TICK else: self.state = self.cleanup def cleanup(self): self.g.look_at = None self.state = self.done def done(self): # never gets ran, placeholder return None def __init__(self, global_state): self.g = global_state self.state = self.idle self.safety = None self.wait_time = 0 def run(self): self.state() class FillBlocksStates: def idle(self): return None def init(self): f = self.g.filling if not f: self.state = self.cleanup print('Aborting, nothing to fill') return if self.last_block: self.state = self.select_item else: self.state = self.find_last_block def find_last_block(self): w = self.g.world f = self.g.filling print('Finding last block') b1, b2 = utils.pboundingbox(f.coord1, f.coord2) box = utils.psub(b2, b1) xz_distance = hypot(box[0]+1, box[2]+1) y_start = f.coord1[1] y_end = f.coord2[1] for y in range(y_start, y_end+1): for offset in utils.search_2d(xz_distance): check = utils.padd(f.coord1, offset) check = (check[0], y, check[2]) # ensure block is within fill area if check[0] < b1[0] or check[0] > b2[0]: continue if check[2] < b1[2] or check[2] > b2[2]: continue if w.block_at(*check) == blocks.AIR: self.state = self.select_item return self.last_block = check def select_item(self): f = self.g.filling name = blocks.BLOCKS[f.block] item = items.ITEMS['minecraft:'+name]['protocol_id'] if self.g.game.select_item([item]): #self.g.look_at = utils.padd(self.area, path.BLOCK_BELOW) self.state = self.find_next_block else: print('No blocks, aborting') self.state = self.cleanup def find_next_block(self): w = self.g.world f = self.g.filling print('Finding next block, last:', self.last_block) b1, b2 = utils.pboundingbox(f.coord1, f.coord2) box = utils.psub(b2, b1) xz_distance = hypot(box[0]+1, box[2]+1) y_start = f.coord1[1] y_end = f.coord2[1] for y in range(y_start, y_end+1): if y not in self.iterators: self.iterators[y] = utils.search_2d(xz_distance) for offset in self.iterators[y]: check = utils.padd(f.coord1, offset) check = (check[0], y, check[2]) # ensure block is within fill area if check[0] < b1[0] or check[0] > b2[0]: continue if check[2] < b1[2] or check[2] > b2[2]: continue if w.block_at(*check) == blocks.AIR: print('Found next block:', check) self.next_block = check self.state = self.check_block_distance return # if there's nothing left to fill self.g.filling = None self.state = self.cleanup def check_block_distance(self): w = self.g.world p = utils.pint(self.g.pos) head = utils.padd(p, path.BLOCK_ABOVE) if utils.phyp(head, self.next_block) < 4: self.state = self.fill_block else: self.state = self.nav_to_block def nav_to_block(self): w = self.g.world p = utils.pint(self.g.pos) c = self.g.chunks tmp = c.get_block_at(*self.next_block) c.set_block_at(*self.next_block, blocks.STONE) pos = utils.padd(self.next_block, path.BLOCK_ABOVE) navpath = w.path_to_place(p, pos) c.set_block_at(*self.next_block, tmp) if navpath: self.g.path = navpath[:-1] self.state = self.going_to_block else: print('Cant get to that block') self.state = self.cleanup #self.bad_sand.append(self.sand) #self.state = self.find_new_sand def going_to_block(self): if not len(self.g.path): self.state = self.fill_block def fill_block(self): print('Filling block', self.next_block) self.g.game.place_block(self.next_block, BlockFace.TOP) self.g.look_at = self.next_block self.wait_time = 0.25 self.state = self.wait_for_block def wait_for_block(self): w = self.g.world if w.block_at(*self.next_block) != blocks.AIR: self.last_block = self.next_block self.state = self.check_obstruction elif self.wait_time > 0: self.wait_time -= utils.TICK else: print('Block didnt appear') self.state = self.check_obstruction def check_obstruction(self): p = utils.pint(self.g.pos) f = self.g.filling print('last', self.last_block) print('p', p) if self.last_block[1] >= p[1] and f.block not in blocks.NON_SOLID_IDS: print('Obstructed, going to last block') self.state = self.nav_to_last_block else: self.state = self.cleanup def nav_to_last_block(self): w = self.g.world p = utils.pint(self.g.pos) c = self.g.chunks pos = utils.padd(self.last_block, path.BLOCK_ABOVE) navpath = w.path_to_place(p, pos) if navpath: self.g.path = navpath self.state = self.going_to_last_block else: print('Cant get to that block') self.state = self.cleanup def going_to_last_block(self): if not len(self.g.path): self.state = self.cleanup def cleanup(self): self.state = self.done def done(self): # never gets ran, placeholder return None def __init__(self, global_state): self.g = global_state self.state = self.idle self.iterators = {} self.wait_time = 0 self.last_block = None self.next_block = None def run(self): self.state() class EatFoodStates: def idle(self): return None def init(self): if self.g.food < 12: print('Hungry, eating') self.state = self.select_food return if self.g.health < 20 and self.g.food < 18: print('Low health, eating') self.state = self.select_food return print('Don\'t need to eat, aborting') self.state = self.cleanup def select_food(self): if self.g.game.select_item(items.FOOD_IDS): self.state = self.eat_food else: print('No food, aborting') self.state = self.cleanup def eat_food(self): self.g.game.use_item(0) print('Eating food') self.wait_time = 3 self.state = self.wait def wait(self): if self.wait_time > 0: self.wait_time -= utils.TICK else: self.state = self.cleanup def cleanup(self): self.state = self.done def done(self): # never gets ran, placeholder return None def __init__(self, global_state): self.g = global_state self.state = self.idle self.wait_time = 0 def run(self): self.state() class JobStates: def idle(self): return [] def init_machines(self): self.gather_wood_states = GatherWoodStates(self.g) self.gather_sand_states = GatherSandStates(self.g) self.sleep_with_bed_states = SleepWithBedStates(self.g) self.cache_items_states = CacheItemsStates(self.g) self.grab_supplies_states = GrabSuppliesStates(self.g) self.find_gapple_states = FindGappleStates(self.g) self.plant_tree_states = PlantTreeStates(self.g) self.clear_leaves_states = ClearLeavesStates(self.g) self.grab_sapling_states = GrabSaplingStates(self.g) self.grab_sand_states = GrabSandStates(self.g) self.fill_blocks_states = FillBlocksStates(self.g) self.check_threats_states = CheckThreatsStates(self.g) self.gather_wart_states = GatherWartStates(self.g) self.gather_crop_states = GatherCropStates(self.g) self.eat_food_states = EatFoodStates(self.g) def run_machines(self, machines): for m in machines: if m.state == m.idle: continue if m.state != m.done: m.run() return # if we went through them all for m in machines: m.state = m.init def gather_sand(self): machines = [ self.gather_sand_states, self.grab_sand_states, self.cache_items_states, self.sleep_with_bed_states, self.eat_food_states, ] return machines def farm_sand(self): machines = [ self.grab_supplies_states, self.check_threats_states, self.gather_sand_states, self.grab_sand_states, self.cache_items_states, self.sleep_with_bed_states, self.eat_food_states, ] self.sleep_with_bed_states.silent = True self.cache_items_states.silent = True self.grab_supplies_states.supplies = { tuple(items.SHOVEL_IDS): 9 } return machines def cache_items(self): machines = [ self.cache_items_states, ] return machines def find_gapple(self): machines = [ self.find_gapple_states, ] return machines def gather_wood(self): machines = [ self.gather_wood_states, self.sleep_with_bed_states, self.eat_food_states, self.cache_items_states, ] return machines def farm_wood(self): machines = [ self.grab_supplies_states, self.gather_wood_states, self.clear_leaves_states, self.plant_tree_states, self.grab_sapling_states, self.sleep_with_bed_states, self.eat_food_states, self.cache_items_states, ] self.sleep_with_bed_states.silent = True self.cache_items_states.silent = True self.grab_supplies_states.supplies = { tuple(items.AXE_IDS): 9, } return machines def farm_wart(self): machines = [ self.gather_wart_states, self.sleep_with_bed_states, self.eat_food_states, self.cache_items_states, ] self.sleep_with_bed_states.silent = True self.cache_items_states.silent = True return machines def farm_crop(self): machines = [ self.gather_crop_states, self.sleep_with_bed_states, self.eat_food_states, self.cache_items_states, ] self.sleep_with_bed_states.silent = True self.cache_items_states.silent = True return machines def fill_blocks(self): machines = [ self.grab_supplies_states, self.fill_blocks_states, self.sleep_with_bed_states, self.eat_food_states, ] self.sleep_with_bed_states.silent = True f = self.g.filling name = blocks.BLOCKS[f.block] item = items.ITEMS['minecraft:'+name]['protocol_id'] self.grab_supplies_states.supplies = { tuple([item]): 0, } return machines def loiter(self): machines = [ self.check_threats_states, self.sleep_with_bed_states, self.eat_food_states, ] self.sleep_with_bed_states.silent = True return machines def stop(self): self.init_machines() self.state = self.idle def __init__(self, global_state): self.g = global_state self.init_machines() self.state = self.idle def tick(self): self.run_machines(self.state())