import os import time import functools from math import ceil, floor, hypot, sqrt from itertools import count import blocks import items import custom_packets from minecraft import authentication from minecraft.exceptions import YggdrasilError from minecraft.networking.connection import Connection from minecraft.networking.packets import clientbound, serverbound from minecraft.networking.types import BlockFace from minecraft.compat import input from minecraft.managers import chunks, ChunksManager class AStarTimeout(Exception): pass class DataManager: def __init__(self): self.blocks_states = {} self.blocks_properties = {} self.registries = {} self.biomes = {} self.entity_type = {} self.blocks = {} from panda3d.core import * from astar import AStar BLOCK_ABOVE = (0, +1, 0) BLOCK_ABOVE2 = (0, +2, 0) BLOCK_ABOVE3 = (0, +3, 0) BLOCK_ABOVE4 = (0, +4, 0) BLOCK_BELOW = (0, -1, 0) BLOCK_BELOW2 = (0, -2, 0) TRAVERSE_NORTH = (0, 0, -1) TRAVERSE_SOUTH = (0, 0, +1) TRAVERSE_EAST = (+1, 0, 0) TRAVERSE_WEST = (-1, 0, 0) ASCEND_NORTH = (0, +1, -1) ASCEND_SOUTH = (0, +1, +1) ASCEND_EAST = (+1, +1, 0) ASCEND_WEST = (-1, +1, 0) DESCEND_EAST = (+1, -1, 0) DESCEND_WEST = (-1, -1, 0) DESCEND_NORTH = (0, -1, -1) DESCEND_SOUTH = (0, -1, +1) DESCEND2_EAST = (+1, -2, 0) DESCEND2_WEST = (-1, -2, 0) DESCEND2_NORTH = (0, -2, -1) DESCEND2_SOUTH = (0, -2, +1) DESCEND3_EAST = (+1, -3, 0) DESCEND3_WEST = (-1, -3, 0) DESCEND3_NORTH = (0, -3, -1) DESCEND3_SOUTH = (0, -3, +1) DIAGONAL_NORTHEAST = (+1, 0, -1) DIAGONAL_NORTHWEST = (-1, 0, -1) DIAGONAL_SOUTHEAST = (+1, 0, +1) DIAGONAL_SOUTHWEST = (-1, 0, +1) PARKOUR_NORTH = (0, 0, -2) PARKOUR_SOUTH = (0, 0, +2) PARKOUR_EAST = (+2, 0, 0) PARKOUR_WEST = (-2, 0, 0) TRAVERSE = [ TRAVERSE_NORTH, TRAVERSE_SOUTH, TRAVERSE_EAST, TRAVERSE_WEST, ] ASCEND = [ ASCEND_NORTH, ASCEND_SOUTH, ASCEND_EAST, ASCEND_WEST, ] DESCEND = [ DESCEND_EAST, DESCEND_WEST, DESCEND_NORTH, DESCEND_SOUTH, ] DESCEND2 = [ DESCEND2_EAST, DESCEND2_WEST, DESCEND2_NORTH, DESCEND2_SOUTH, ] DESCEND3 = [ DESCEND3_EAST, DESCEND3_WEST, DESCEND3_NORTH, DESCEND3_SOUTH, ] DIAGONAL = [ DIAGONAL_NORTHEAST, DIAGONAL_NORTHWEST, DIAGONAL_SOUTHEAST, DIAGONAL_SOUTHWEST, ] PARKOUR = [ PARKOUR_NORTH, PARKOUR_SOUTH, PARKOUR_EAST, PARKOUR_WEST, ] HALF_PARKOUR = { (0, 0, -2): (0, 0, -1), (0, 0, 2): (0, 0, 1), (2, 0, 0): (1, 0, 0), (-2, 0, 0): (-1, 0, 0), } HYPOT_LUT = { (0, -1): 1.0, (0, 1): 1.0, (1, 0): 1.0, (-1, 0): 1.0, (1, -1): 1.414, (-1, -1): 1.414, (1, 1): 1.414, (-1, 1): 1.414, (0, 2): 2.0, (-2, 0): 2.0, (2, 0): 2.0, (0, -2): 2.0, } def padd(p1, p2): return (p1[0] + p2[0], p1[1] + p2[1], p1[2] + p2[2]) def psub(p1, p2): return (p1[0] - p2[0], p1[1] - p2[1], p1[2] - p2[2]) def pmul(p, s): return (s*p[0], s*p[1], s*p[2]) def phyp(p1, p2): return hypot(p1[0] - p2[0], p1[1] - p2[1], p1[2] - p2[2]) def phyp_bias(p1, p2, origin): origin_distance = phyp(origin, p2) height_diff = p2[1] - p1[1] height_diff = height_diff*8 if height_diff < 0 else height_diff*0.5 return hypot(p1[0] - p2[0], height_diff, p1[2] - p2[2]) + origin_distance*1.5 def pint(p): return (floor(p[0]), floor(p[1]), floor(p[2])) # larger started being slower BLOCK_CACHE_SIZE = 2**14 class MazeSolver(AStar): def __init__(self, chunks): self.chunks = chunks self.start_time = time.time() @functools.lru_cache(maxsize=BLOCK_CACHE_SIZE) def bair(self, p): return self.chunks.get_block_at(*p) in blocks.NON_SOLID_IDS @functools.lru_cache(maxsize=BLOCK_CACHE_SIZE) def bavoid(self, p): return self.chunks.get_block_at(*p) in blocks.AVOID_IDS def check_traverse(self, node, offset): dest = padd(node, offset) if not self.bair(dest): return False if self.bair(padd(dest, BLOCK_BELOW)): return False if not self.bair(padd(dest, BLOCK_ABOVE)): return False if self.bavoid(dest): return False if self.bavoid(padd(dest, BLOCK_BELOW)): return False if self.bavoid(padd(dest, BLOCK_ABOVE)): return False return True def check_diagonal(self, node, offset): if not self.check_traverse(node, offset): return False dest = padd(node, offset) thru1 = (node[0], node[1], dest[2]) thru2 = (dest[0], node[1], node[2]) if not self.bair(thru1): return False if not self.bair(padd(thru1, BLOCK_ABOVE)): return False if self.bavoid(padd(thru1, BLOCK_BELOW)): return False if not self.bair(thru2): return False if not self.bair(padd(thru2, BLOCK_ABOVE)): return False if self.bavoid(padd(thru2, BLOCK_BELOW)): return False return True def check_ascend(self, node, offset): if not self.check_traverse(node, offset): return False dest = padd(node, offset) if not self.bair(padd(node, BLOCK_ABOVE2)): return False return True def check_descend(self, node, offset): if not self.check_traverse(node, offset): return False dest = padd(node, offset) if not self.bair(padd(dest, BLOCK_ABOVE2)): return False return True def check_descend2(self, node, offset): if not self.check_descend(node, offset): return False dest = padd(node, offset) if not self.bair(padd(dest, BLOCK_ABOVE3)): return False return True def check_descend3(self, node, offset): if not self.check_descend2(node, offset): return False dest = padd(node, offset) if not self.bair(padd(dest, BLOCK_ABOVE4)): return False return True def check_parkour(self, node, offset): dest = padd(node, offset) half_offset = HALF_PARKOUR[offset] middle = padd(node, half_offset) # dont jump if we can walk instead if not self.bair(padd(middle, BLOCK_BELOW)): return False if not self.check_ascend(node, offset): return False if not self.bair(padd(dest, BLOCK_ABOVE2)): return False if not self.bair(padd(middle, BLOCK_ABOVE)): return False if not self.bair(padd(middle, BLOCK_ABOVE2)): return False return True def neighbors(self, node): results = [] for offset in TRAVERSE: if self.check_traverse(node, offset): results.append(padd(node, offset)) for offset in DIAGONAL: if self.check_diagonal(node, offset): results.append(padd(node, offset)) for offset in ASCEND: if self.check_ascend(node, offset): results.append(padd(node, offset)) for offset in DESCEND: if self.check_descend(node, offset): results.append(padd(node, offset)) for offset in DESCEND2: if self.check_descend2(node, offset): results.append(padd(node, offset)) for offset in DESCEND3: if self.check_descend3(node, offset): results.append(padd(node, offset)) for offset in PARKOUR: if self.check_parkour(node, offset): results.append(padd(node, offset)) if not results: if time.time() - self.start_time > 2.0: raise(AStarTimeout) return results def distance_between(self, n1, n2): (x1, y1, z1) = n1 (x2, y2, z2) = n2 return HYPOT_LUT[x2 - x1, z2 - z1] def heuristic_cost_estimate(self, n1, n2): (x1, y1, z1) = n1 (x2, y2, z2) = n2 return hypot(x2 - x1, z2 - z1) def spiral(n): # return x, 0, z coords along a spiral at step n # I forget where I found this n += 1 k = ceil((sqrt(n)-1)/2) t = 2 * k + 1 m = t**2 t = t - 1 if n >= m-t: return k-(m-n), 0, -k else: m = m-t if n >= m-t: return -k, 0, -k+(m-n) else: m = m-t if n >= m-t: return -k+(m-n), 0, k else: return k, 0, k-(m-n-t) def alternate(n, amount): # return 0, y, 0 where y alternates +/- by amount # example: 0, 2, -2, 4, -4, 6, -6 for amount = 2 sign = 1 if n % 2 else -1 return (0, ceil(n/2) * sign * amount, 0) def diffrange(n): # same as range(n+1) but can go negative sign = 1 if n >= 0 else -1 return range(0, n+sign, sign) def break_block(connection, coords, time): packet = custom_packets.PlayerDiggingPacket() packet.status = 0 packet.location = coords packet.face = 1 connection.write_packet(packet) s['break_finished_packet'] = custom_packets.PlayerDiggingPacket() s['break_finished_packet'].status = 2 s['break_finished_packet'].location = coords s['break_finished_packet'].face = 1 s['break_time'] = time s['break_timeout'] = 0.25 def place_block(connection, pos, face): packet = serverbound.play.PlayerBlockPlacementPacket() packet.hand = 0 packet.location = pos packet.face = face packet.x = 0.5 packet.y = 0.5 packet.z = 0.5 packet.inside_block = False connection.write_packet(packet) def say(connection, message): packet = serverbound.play.ChatPacket() packet.message = message connection.write_packet(packet) def pick(connection, slot): packet = custom_packets.PickItemPacket() packet.slot_to_use = slot connection.write_packet(packet) def hold(connection, slot): packet = custom_packets.HeldItemChangePacket() packet.slot = slot connection.write_packet(packet) def choose_slot(connection, slot): if slot >= 36: slot -= 36 hold(connection, slot) else: pick(connection, slot) BLOCK_ABOVE = (0, +1, 0) BLOCK_BELOW = (0, -1, 0) CHECK_NORTH = (0, 0, -1) CHECK_SOUTH = (0, 0, +1) CHECK_EAST = (+1, 0, 0) CHECK_WEST = (-1, 0, 0) CHECK_DIRECTIONS = [ CHECK_NORTH, CHECK_SOUTH, CHECK_EAST, CHECK_WEST, ] class MCWorld: def __init__(self, chunks): self.chunks = chunks def block_at(self, x, y, z): return self.chunks.get_block_at(x, y, z) def find_blocks(self, center, distance, block_ids, limit=0): # search in a spiral from center to all blocks with ID result = [] for n in count(): offset = spiral(n) check = padd(center, offset) if self.block_at(*check) in block_ids: if hypot(*offset) < distance: result.append(check) if limit and len(result) == limit: return result if offset[0] > distance: return result def find_trees(self, center, distance): logs = [] for i in range(5): check = padd(center, alternate(i, 3)) logs.extend(self.find_blocks(check, distance, blocks.LOG_IDS, 50)) trees = [] for log in logs: # crawl to the bottom log while self.block_at(*padd(log, BLOCK_BELOW)) in blocks.LOG_IDS: log = padd(log, BLOCK_BELOW) # make sure we are on the ground if self.block_at(*padd(log, BLOCK_BELOW)) in blocks.NON_SOLID_IDS: continue # crawl to the top log to count log_count = 1 while self.block_at(*padd(log, BLOCK_ABOVE)) in blocks.LOG_IDS: log = padd(log, BLOCK_ABOVE) log_count += 1 # make sure it's a good tree if self.block_at(*padd(log, BLOCK_ABOVE)) in blocks.LEAF_IDS and log_count > 2: # crawl back to the bottom log while self.block_at(*padd(log, BLOCK_BELOW)) in blocks.LOG_IDS: log = padd(log, BLOCK_BELOW) trees.append(log) trees.sort(key=lambda x: phyp(center, x)) return trees def find_tree_openings(self, tree): # returns coords in a cardinal direction where we can stand by tree maze_solver = MazeSolver(self.chunks) result = [] # TODO: make sure only non-solid and leaves between # make sure traversable too for distance in range(5): for direction in CHECK_DIRECTIONS: offset = pmul(direction, distance+1) if maze_solver.check_traverse(tree, offset): result.append(padd(tree, offset)) return result def path_to_place(self, start, place): maze_solver = MazeSolver(self.chunks) try: s = maze_solver.astar(start, place) return list(s) if s else None except AStarTimeout: return None def find_bed_areas(self, center, distance): air = [] for i in range(5): check = padd(center, alternate(i, 1)) air.extend(self.find_blocks(check, distance, [0], 200)) areas = [] for a in air: # check for ground around the area if len(self.find_blocks(padd(a, BLOCK_BELOW), 2, blocks.NON_SOLID_IDS, 9)): continue # check for air around the area if len(self.find_blocks(a, 2, [0], 9)) < 9: continue # check for air above the area if len(self.find_blocks(padd(a, BLOCK_ABOVE), 2, [0], 9)) < 9: continue areas.append(a) areas.sort(key=lambda x: phyp(center, x)) return areas def sand_adjacent_safe(self, sand): for direction in CHECK_DIRECTIONS: if self.block_at(*padd(sand, direction)) in blocks.AVOID_IDS: return False return True def find_sand(self, center, distance, origin): sand = [] for i in range(10): check = padd(center, alternate(i, 1)) sand.extend(self.find_blocks(check, distance, [66], 20)) safe_sand = [] for s in sand: # make sure it has solid below if self.block_at(*padd(s, BLOCK_BELOW)) in blocks.NON_SOLID_IDS: continue # make sure it has solid two below - prevent hanging sand if self.block_at(*padd(s, BLOCK_BELOW2)) in blocks.NON_SOLID_IDS: continue # and walkable air above if self.block_at(*padd(s, BLOCK_ABOVE)) not in blocks.NON_SOLID_IDS: continue if not self.sand_adjacent_safe(s): continue safe_sand.append(s) safe_sand.sort(key=lambda x: phyp_bias(center, x, origin)) return safe_sand def find_bed_openings(self, area): # returns coords in a cardinal direction where we can stand by bed result = [] for direction in CHECK_DIRECTIONS: result.append(padd(area, direction)) return result class LumberjackStates: def bair(self, p): return self.player_info.chunks.get_block_at(*p) in blocks.NON_SOLID_IDS def blog(self, p): return self.player_info.chunks.get_block_at(*p) in blocks.LOG_IDS def idle(self): return None def init(self): self.state = self.find_new_tree def find_new_tree(self): print('Finding new tree...') w = MCWorld(self.player_info.chunks) p = pint(self.player_info.pos) trees = w.find_trees(p, 100) print('Found trees:', trees) while trees[0] in self.bad_trees: trees.pop(0) self.tree = trees[0] self.openings = w.find_tree_openings(self.tree) self.state = self.choose_opening def choose_opening(self): w = MCWorld(self.player_info.chunks) p = pint(self.player_info.pos) print('openings:', self.openings) if not len(self.openings): print('Unable to get to tree', self.tree) self.bad_trees.append(self.tree) self.state = self.cleanup return path = w.path_to_place(p, self.openings[0]) if path: s['path'] = path self.state = self.going_to_tree else: self.openings.pop(0) def going_to_tree(self): if pint(self.player_info.pos) == self.openings[0]: s['look_at'] = self.tree self.state = self.clear_leaves def clear_leaves(self): if not s['break_timeout']: p = pint(self.player_info.pos) diff = psub(self.tree, p) for x in diffrange(diff[0]): for z in diffrange(diff[2]): for y in range(2): check = padd(p, (x, y, z)) if check == self.tree: break if not self.bair(check): print('Breaking leaf') s['break'] = (check, 0.5) return self.state = self.clear_trunk_base def clear_trunk_base(self): if not s['break_timeout']: base = self.tree above = padd(self.tree, BLOCK_ABOVE) if self.blog(base): s['break'] = (base, 3) print('breaking base') elif self.blog(above): s['break'] = (above, 3) print('breaking above') else: w = MCWorld(self.player_info.chunks) p = pint(self.player_info.pos) path = w.path_to_place(p, self.tree) if path: s['path'] = path self.state = self.going_to_trunk_base else: self.openings.pop(0) self.state = self.choose_opening def going_to_trunk_base(self): if pint(self.player_info.pos) == self.tree: s['look_at'] = padd(self.tree, BLOCK_ABOVE2) self.state = self.clear_trunk def clear_trunk(self): if not s['break_timeout']: check = self.tree count = 0 while self.bair(check) and count < 6: check = padd(check, BLOCK_ABOVE) count += 1 if self.blog(check): print('breaking log', check) s['break'] = (check, 3) 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 -= TICK else: self.state = self.cleanup def cleanup(self): s['look_at'] = None self.state = self.done def done(self): # never gets ran, placeholder return None def __init__(self, player_info): self.player_info = player_info self.state = self.idle self.tree = None self.openings = [] self.bad_trees = [] self.wait_time = 0 def run(self): self.state() class GatherSandStates: def bair(self, p): return self.player_info.chunks.get_block_at(*p) in blocks.NON_SOLID_IDS def bsand(self, p): return self.player_info.chunks.get_block_at(*p) == 66 def idle(self): return None def init(self): self.state = self.find_new_sand def find_new_sand(self): print('Finding new sand...') w = MCWorld(self.player_info.chunks) p = pint(self.player_info.pos) sand = w.find_sand(p, 150, self.origin) print('Found sand:', sand) while sand[0] in self.bad_sand: sand.pop(0) self.sand = sand[0] self.state = self.nav_to_sand def nav_to_sand(self): w = MCWorld(self.player_info.chunks) p = pint(self.player_info.pos) w.chunks.set_block_at(*self.sand, 0) path = w.path_to_place(p, self.sand) w.chunks.set_block_at(*self.sand, 66) if path: s['path'] = path[:-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(s['path']): s['look_at'] = self.sand self.state = self.dig_sand def dig_sand(self): if not s['break_timeout']: if self.bsand(self.sand): s['break'] = (self.sand, 0.75) print('digging sand') else: self.state = self.get_sand def get_sand(self): w = MCWorld(self.player_info.chunks) p = pint(self.player_info.pos) path = w.path_to_place(p, self.sand) if path: s['path'] = path self.state = self.going_to_item else: self.bad_sand.append(self.sand) self.state = self.find_new_sand def going_to_item(self): if pint(self.player_info.pos) == self.sand: s['look_at'] = self.sand self.state = self.cleanup def cleanup(self): s['look_at'] = None self.state = self.done def done(self): # never gets ran, placeholder return None def __init__(self, player_info): self.player_info = player_info self.state = self.idle self.origin = pint(self.player_info.pos) self.sand = None self.bad_sand = [] self.wait_time = 0 def run(self): self.state() class SleepWithBedStates: def idle(self): return None def init(self): if s['time'] >= 12000: self.state = self.find_bed_spot else: print('Aborting sleep, not night') self.state = self.cleanup def find_bed_spot(self): print('Finding a bed spot...') w = MCWorld(self.player_info.chunks) p = pint(self.player_info.pos) areas = w.find_bed_areas(p, 100) print('Found areas:', areas) if len(areas): while areas[0] in self.bad_areas: areas.pop(0) self.area = areas[0] elif self.last_area: self.area = self.last_area else: print('Unable to find area, and no last area') self.state = self.cleanup return openings = w.find_bed_openings(self.area) for o in openings: path = w.path_to_place(p, o) self.opening = o if path: break else: # for print('Unable to get to bed area', self.area) self.bad_areas.append(self.area) self.state = self.cleanup return s['path'] = path self.state = self.going_to_area self.last_area = self.area def going_to_area(self): if pint(self.player_info.pos) == self.opening: s['look_at'] = self.area self.state = self.select_bed def select_bed(self): for slot, item in self.player_info.inv.items(): if item.item_id in items.BED_IDS: print('Found bed in slot', slot) s['look_at'] = padd(self.area, BLOCK_BELOW) choose_slot(self.connection, slot) self.state = self.place_bed break else: # for say(self.connection, 'I need a bed') self.state = self.cleanup def place_bed(self): place_block(self.connection, self.area, BlockFace.TOP) self.state = self.use_bed def use_bed(self): if s['time'] >= 12542: print('Sleeping') place_block(self.connection, self.area, BlockFace.TOP) say(self.connection, 'zzz') self.state = self.sleep_bed def sleep_bed(self): if s['time'] < 100: print('Woke up') self.state = self.break_bed def break_bed(self): s['break'] = (self.area, 0.4) self.state = self.collect_bed def collect_bed(self): if not s['break_timeout']: s['path'] = [padd(self.area, 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 -= TICK else: self.state = self.cleanup def cleanup(self): s['look_at'] = None self.state = self.done def done(self): # never gets ran, placeholder return None def __init__(self, player_info, connection): self.player_info = player_info self.connection = connection self.state = self.idle self.area = None self.opening = None self.bad_areas = [] self.last_area = None self.wait_time = 0 def run(self): self.state() class JobStates: def idle(self): return None def sleep_with_bed(self): s = self.sleep_with_bed_states if s.state == s.idle: s.state = s.init elif s.state == s.done: s.state = s.init # check time, etc if self.prev_state: print('Reverting to prev state') self.state = self.prev_state return s.run() def gather_sand(self): s = self.gather_sand_states if s.state == s.idle: s.state = s.init elif s.state == s.done: s.state = s.init # check time, etc if self.survive: self.prev_state = self.gather_sand self.state = self.sleep_with_bed return s.run() def lumberjack(self): s = self.lumberjack_states if s.state == s.idle: s.state = s.init elif s.state == s.done: s.state = s.init # check time, etc if self.survive: self.prev_state = self.lumberjack self.state = self.sleep_with_bed return s.run() def stop(self): self.lumberjack_states = LumberjackStates(self.player_info) self.gather_sand_states = GatherSandStates(self.player_info) self.sleep_with_bed_states = SleepWithBedStates(self.player_info, self.connection) self.state = self.idle def __init__(self, connection, player_info): # TODO: watch dog if it gets stuck self.connection = connection self.player_info = player_info self.state = self.idle self.prev_state = None self.lumberjack_states = LumberjackStates(self.player_info) self.gather_sand_states = GatherSandStates(self.player_info) self.sleep_with_bed_states = SleepWithBedStates(self.player_info, self.connection) self.survive = False def run(self): self.state() TICK = 0.05 last_tick = time.time() PITCH_ANGLE_DIR = LVector3f(x=0, y=1, z=0) YAW_ANGLE_DIR = LVector3f(x=0, y=0, z=-1) YAW_ANGLE_REF = LVector3f(x=0, y=1, z=0) YAW_LOOK_AHEAD = 4 running = True get_mod_time = lambda: os.path.getmtime('bot.py') last_mod_time = get_mod_time() # state dictionary s = dict() def cap(x, amount): sign = 1 if x >= 0 else -1 return sign * min(abs(x), amount) def tick(connection, player_info): target = None p = player_info.pos try: player_info.chunks.get_block_at(*pint(p)) except chunks.ChunkNotLoadedException: return s['jobstate'].run() if s['path'] and len(s['path']): target = LPoint3f(s['path'][0]) target.x += 0.5 target.z += 0.5 if target: d = p - target # jump up block if d.y < -0.9 and not s['y_v']: s['y_v'] = 8.5 s['y_a'] = -36.0 # jump gap if d.xz.length() > 1.6 and not s['y_v']: s['y_v'] = 8.5 s['y_a'] = -36.0 if d.length() > 0: if s['y_v'] < 5: p.x -= cap(d.x, 0.2) p.z -= cap(d.z, 0.2) if len(s['path']) > 1 and d.length() < 0.2: # removes some jitter in walking s['path'].pop(0) elif d.length() == 0: s['path'].pop(0) if s['y_v'] or s['y_a']: p.y += s['y_v'] * TICK s['y_v'] += s['y_a'] * TICK block_below = player_info.chunks.get_block_at(floor(p.x), ceil(p.y-1), floor(p.z)) in_air = block_below in blocks.NON_SOLID_IDS if in_air: s['y_a'] = -36.0 else: p.y = ceil(p.y) s['y_v'] = 0 s['y_a'] = 0 if s['look_at']: look_at = LPoint3f(s['look_at']) elif s['path'] and len(s['path']) > YAW_LOOK_AHEAD: look_at = LPoint3f(s['path'][YAW_LOOK_AHEAD]) elif s['path'] and len(s['path']): look_at = LPoint3f(s['path'][-1]) else: look_at = None if look_at: look_at.x += 0.5 look_at.z += 0.5 look_at_d = p - look_at if look_at_d.length() > 0.6: target_pitch = look_at_d.normalized().angleDeg(PITCH_ANGLE_DIR) target_pitch = (target_pitch - 90) * -1 target_pitch_d = target_pitch - s['pitch'] s['pitch'] += cap(target_pitch_d, 10) # remove vertical component for yaw calculation look_at_d.y = 0 target_yaw = look_at_d.normalized().signedAngleDeg(other=YAW_ANGLE_DIR, ref=YAW_ANGLE_REF) target_yaw_d = target_yaw - s['yaw'] target_yaw_d = (target_yaw_d + 180) % 360 - 180 s['yaw'] += cap(target_yaw_d, 30) else: target_pitch_d = 0 - s['pitch'] s['pitch'] += cap(target_pitch_d, 10) packet = serverbound.play.PositionAndLookPacket(x=p.x, feet_y=p.y, z=p.z, pitch=s['pitch'], yaw=s['yaw'], on_ground=(not in_air)) connection.write_packet(packet, force=True) if s['break']: break_block(connection, *s['break']) s['break'] = None if s['break_time'] > 0: packet = serverbound.play.AnimationPacket() packet.hand = packet.HAND_MAIN connection.write_packet(packet) #print(s['break_time']) s['break_time'] -= TICK elif s['break_finished_packet']: print('break finished') connection.write_packet(s['break_finished_packet']) s['break_finished_packet'] = None elif s['break_timeout'] > 0: s['break_timeout'] -= TICK if s['break_timeout'] < 0: s['break_timeout'] = 0 def init(connection, player_info): p = player_info.pos s['time'] = 0 s['path'] = [] s['look_at'] = None s['y_v'] = 0 s['y_a'] = 0 s['yaw'] = 360 s['pitch'] = 0 s['break'] = None s['break_time'] = 0 s['break_timeout'] = 0 s['break_finished_packet'] = None s['jobstate'] = JobStates(connection, player_info) s['jobstate'].run() def main(connection, player_info): def handle_join_game(join_game_packet): print('Connected.') print(join_game_packet) player_info.eid = join_game_packet connection.register_packet_listener( handle_join_game, clientbound.play.JoinGamePacket) def h_position_and_look(packet): print('pos and look:') print(packet) p = LPoint3f(x=packet.x, y=packet.y, z=packet.z) player_info.pos = p connection.register_packet_listener( h_position_and_look, clientbound.play.PlayerPositionAndLookPacket) def x(p): #print('block change:') #print(p) if p.block_state_id == 3885: try: s['goal'] = LPoint3f(x=p.location[0], y=p.location[1], z=p.location[2]) print('new waypoint:', s['goal']) start = time.time() solution = MazeSolver(player_info.chunks).astar(pint(player_info.pos), pint(s['goal'])) if solution: solution = list(solution) s['path'] = solution s['jobstate'].state = s['jobstate'].stop print(len(solution)) print(solution) print(round(time.time() - start, 3), 'seconds') else: say(connection, 'No path found') #s['y_v'] = 10.0 #s['y_a'] = -36.0 except BaseException as e: import traceback print(traceback.format_exc()) connection.register_packet_listener( x, clientbound.play.BlockChangePacket) def handle_time_update(p): s['time'] = p.time_of_day % 24000 connection.register_packet_listener( handle_time_update, custom_packets.TimeUpdatePacket) def handle_set_slot(p): print(p) if p.window_id == 0: player_info.inv[p.slot] = p.slot_data connection.register_packet_listener( handle_set_slot, custom_packets.SetSlotPacket) def print_chat(chat_packet): try: print("Message (%s): %s" % ( chat_packet.field_string('position'), chat_packet.json_data)) if '!reload' in chat_packet.json_data: global running running = False elif '!misc' in chat_packet.json_data: for i in range(9): print(i, spiral(i)) elif '!afk' in chat_packet.json_data: say(connection, '/afk') elif '!respawn' in chat_packet.json_data: packet = serverbound.play.ClientStatusPacket() packet.action_id = serverbound.play.ClientStatusPacket.RESPAWN connection.write_packet(packet) elif '!chunk' in chat_packet.json_data: print(len(player_info.chunks.chunks.keys())) print(player_info.chunks.chunks[(38, 4, 33)].__dict__) elif '!block' in chat_packet.json_data: block = player_info.chunks.get_block_at(616, 78, 496) packet = serverbound.play.ChatPacket() packet.message = str(block) connection.write_packet(packet) elif '!path' in chat_packet.json_data: s['goal'] = LPoint3f(655, 86, 341) print('new waypoint:', s['goal']) start = time.time() solution = MazeSolver(player_info.chunks).astar(pint(player_info.pos), pint(s['goal'])) solution = list(solution) s['path'] = solution print(len(solution)) print(round(time.time() - start, 3), 'seconds') elif '!tree' in chat_packet.json_data: mc_world = MCWorld(player_info.chunks) start = time.time() coords = mc_world.find_tree(pint(player_info.pos), 100) print(coords) openings = mc_world.find_tree_openings(coords) print(openings) path = mc_world.navigate_to_opening(pint(player_info.pos), openings[0]) print(path) print(round(time.time() - start, 3), 'seconds') elif '!break' in chat_packet.json_data: coords = pint(player_info.pos) coords = padd(coords, CHECK_NORTH) break_block(connection, coords, 2.5) #break_block(connection, coords, 0.35) elif '!pick' in chat_packet.json_data: packet = custom_packets.PickItemPacket() packet.slot_to_use = 1 connection.write_packet(packet) elif '!inv' in chat_packet.json_data: for i in player_info.inv.values(): if i.present: print(items.ITEM_NAMES[i.item_id], 'x', i.item_count) elif '!spot' in chat_packet.json_data: mc_world = MCWorld(player_info.chunks) start = time.time() coords = mc_world.find_bed_areas(pint(player_info.pos), 100) print(coords) print(len(coords)) print(round(time.time() - start, 3), 'seconds') elif '!echo' in chat_packet.json_data: parts = chat_packet.json_data.split('\'') say(connection, parts[1]) elif '!sleep' in chat_packet.json_data: #for i in player_info.inv.values(): # if i.item_id in items.BED_IDS: # break #else: # for # say(connection, 'I need a bed') # return s['jobstate'].state = s['jobstate'].sleep_with_bed s['jobstate'].sleep_with_bed_states.state = s['jobstate'].sleep_with_bed_states.find_bed_spot elif 'get wood and survive' in chat_packet.json_data: for i in player_info.inv.values(): print(i.item_id) if i.item_id in items.BED_IDS: break else: # for say(connection, 'I need a bed') return s['jobstate'].state = s['jobstate'].lumberjack s['jobstate'].survive = True elif 'get sand and survive' in chat_packet.json_data: for i in player_info.inv.values(): print(i.item_id) if i.item_id in items.BED_IDS: break else: # for say(connection, 'I need a bed') return s['jobstate'].state = s['jobstate'].gather_sand s['jobstate'].survive = True elif 'get wood' in chat_packet.json_data: s['jobstate'].state = s['jobstate'].lumberjack elif 'get sand' in chat_packet.json_data: s['jobstate'].state = s['jobstate'].gather_sand elif 'stop job' in chat_packet.json_data: say(connection, 'ok') s['jobstate'].state = s['jobstate'].stop elif 'where are you' in chat_packet.json_data: say(connection, str(pint(player_info.pos))[1:-1]) except BaseException as e: import traceback print(traceback.format_exc()) connection.register_packet_listener( print_chat, clientbound.play.ChatMessagePacket) if not player_info.chunks: player_info.mcdata = DataManager() player_info.chunks = ChunksManager(player_info.mcdata) player_info.chunks.register(connection) #packet = serverbound.play.ChatPacket() #packet.message = '> reloaded' #connection.write_packet(packet) print() print() print('Reloaded.') #if player_info.pos: # print('Loaded positions', player_info.pos) try: while not player_info.pos: time.sleep(TICK) print('Player loaded.') x, y, z = pint(player_info.pos) while (floor(x/16), floor(y/16), floor(z/16)) not in player_info.chunks.chunks: time.sleep(TICK) print('Chunks loaded.') init(connection, player_info) while running: tick(connection, player_info) global last_tick sleep_time = TICK + last_tick - time.time() if sleep_time < 0: sleep_time = 0 time.sleep(sleep_time) last_tick = time.time() if get_mod_time() != last_mod_time: break finally: connection.packet_listeners = [] connection.early_packet_listeners = [] connection.outgoing_packet_listeners = [] connection.early_outgoing_packet_listeners = []