import re import time import importlib import random from math import hypot from panda3d.core import LPoint3f 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 data importlib.reload(data) BREAK_DISTANCE = 5 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 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.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.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 = True 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.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.find_new_slice def find_new_slice(self): print('Finding new slice...') w = self.g.world print('using origin', self.origin) s = w.find_sand_slice(self.origin, 50, self.bad_slices) print('Found slice:', s) 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) sand = w.find_sand(self.slice, 2, p) print('Found sand:', sand) if not len(sand): self.state = self.cleanup return for check in sand: if check in self.bad_sand: continue self.sand = check break if utils.phyp(p, self.sand) > BREAK_DISTANCE: self.state = self.nav_to_sand else: self.state = self.dig_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: 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.slice = None self.bad_slices = [] 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: self.state = self.select_bed else: print('Aborting sleep, not night') self.state = self.cleanup 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 = self.area 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 >= 12542: 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): if self.g.time < 100: print('Woke up') 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 = 4 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 = True 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, 100) 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.g.look_at = utils.padd(self.area, path.BLOCK_BELOW) 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 = data.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 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) if self.g.game.select_random_item(items.SAPLING_IDS): self.g.look_at = utils.padd(p, path.BLOCK_BELOW) self.state = self.wait_select self.wait_time = 1 else: print('Aborting planting, no saplings') 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): 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): num_saplings = self.g.game.count_items(items.SAPLING_IDS) print('Have', num_saplings, 'saplings in inventory') if num_saplings < 8: self.state = self.find_leaves print('Clearing leaves...') else: print('Aborting clearing leaves') self.state = self.cleanup def find_leaves(self): w = self.g.world p = utils.pint(self.g.pos) for l in w.find_leaves(p, 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 JobStates: def idle(self): return None def cache_items(self): s1 = self.cache_items_states if s1.state == s1.idle: s1.state = s1.init elif s1.state == s1.done: self.state = self.idle s1.run() def find_gapple(self): s1 = self.find_gapple_states if s1.state == s1.idle: s1.state = s1.init elif s1.state == s1.done: s1.state = s1.tp_to_coord s1.run() def gather_sand(self): s1 = self.gather_sand_states s2 = self.grab_sand_states s3 = self.sleep_with_bed_states s4 = self.cache_items_states if s1.state == s1.idle: s1.state = s1.init s2.state = s2.init s3.state = s3.init s4.state = s4.init elif s1.state == s1.done: if s2.state != s2.done: s2.run() return if s3.state != s3.done: s3.run() return if s4.state != s4.done: s4.run() return s1.state = s1.init s2.state = s2.init s3.state = s3.init s4.state = s4.init return s1.run() def gather_wood(self): s1 = self.gather_wood_states s2 = self.sleep_with_bed_states s3 = self.cache_items_states if s1.state == s1.idle: s1.state = s1.init s2.state = s2.init s3.state = s3.init elif s1.state == s1.done: if s2.state != s2.done: s2.run() return if s3.state != s3.done: s3.run() return s1.state = s1.init s2.state = s2.init s3.state = s3.init return s1.run() def farm_wood(self): self.sleep_with_bed_states.silent = True self.cache_items_states.silent = True s1 = self.gather_wood_states s2 = self.plant_tree_states s3 = self.clear_leaves_states s4 = self.grab_sapling_states s5 = self.sleep_with_bed_states s6 = self.cache_items_states if s1.state == s1.idle: s1.state = s1.init s2.state = s2.init s3.state = s3.init s4.state = s4.init s5.state = s5.init s6.state = s6.init elif s1.state == s1.done: if s2.state != s2.done: s2.run() return if s3.state != s3.done: s3.run() return if s4.state != s4.done: s4.run() return if s5.state != s5.done: s5.run() return if s6.state != s6.done: s6.run() return s1.state = s1.init s2.state = s2.init s3.state = s3.init s4.state = s4.init s5.state = s5.init s6.state = s6.init return s1.run() def stop(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.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.state = self.idle def __init__(self, global_state): self.g = global_state self.state = self.idle self.prev_state = None 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.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) def tick(self): self.state()