if __name__ == '__main__': print('Run main.py instead.') exit(1) import os import time import importlib from math import floor, ceil from copy import copy USERNAME = os.environ['USERNAME'] PASSWORD = os.environ['PASSWORD'] SERVER = os.environ['SERVER'] PORT = int(os.environ.get('PORT', 25565)) import monkey_patch # must be before any possible pyCraft imports from minecraft import authentication from minecraft.exceptions import YggdrasilError from minecraft.networking.connection import Connection from minecraft.networking.packets import Packet, clientbound, serverbound from protocol.managers import DataManager, ChunksManager, ChatManager, ChunkNotLoadedException from munch import Munch from panda3d.core import LPoint3f, LVector3f import game importlib.reload(game) import blocks importlib.reload(blocks) import utils importlib.reload(utils) import path importlib.reload(path) import jobs importlib.reload(jobs) 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 def tick(global_state): g = global_state p = g.pos target = None # make sure current chunks are loaded for physics if not g.chunks.check_loaded(p, 9): packet = serverbound.play.PositionAndLookPacket(x=p.x, feet_y=p.y, z=p.z, pitch=0, yaw=0, on_ground=True) g.connection.write_packet(packet, force=True) return g.chunks.unload_chunks(p) ########## object physics ########## # note: it's possible the chunk data is out of date when this runs for eid, obj in copy(g.objects).items(): if obj.velocity_x: obj.x += obj.velocity_x / 8000 if obj.velocity_y: obj.y += obj.velocity_y / 8000 if obj.velocity_z: obj.z += obj.velocity_z / 8000 block_below = g.chunks.get_block_at(floor(obj.x), floor(obj.y-0.20), floor(obj.z)) in_air = block_below in blocks.NON_SOLID_IDS if in_air: obj.velocity_x *= 0.988 obj.velocity_y -= 390 obj.velocity_z *= 0.988 else: obj.y = int(obj.y-0.20)+1 obj.velocity_x *= 0.5 obj.velocity_y = 0 obj.velocity_z *= 0.5 # float object back up in case it clipped through multiple blocks if g.chunks.get_block_at(floor(obj.x), floor(obj.y), floor(obj.z)) not in blocks.NON_SOLID_IDS: obj.y += 0.05 if abs(obj.velocity_x) < 1: obj.velocity_x = 0 if abs(obj.velocity_z) < 1: obj.velocity_z = 0 ########## player physics ########## if g.path and len(g.path): target = LPoint3f(g.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 g.y_v: g.y_v = 8.5 g.y_a = -36.0 # jump gap if d.xz.length() > 1.6 and not g.y_v: g.y_v = 8.5 g.y_a = -36.0 if d.length() > 0: if g.y_v < 5: p.x -= utils.cap(d.x, 0.2) p.z -= utils.cap(d.z, 0.2) if len(g.path) > 1 and d.length() < 0.2: # removes some jitter in walking g.path.pop(0) elif d.length() == 0: g.path.pop(0) if g.y_v or g.y_a: p.y += g.y_v * utils.TICK g.y_v += g.y_a * utils.TICK block_below = g.chunks.get_block_at(floor(p.x), ceil(p.y-1), floor(p.z)) in_void = p.y < 0 in_air = block_below in blocks.NON_SOLID_IDS or in_void in_water = block_below in blocks.WATER_IDS if in_air: g.y_a = -36.0 elif in_water: g.y_a = -16.0 else: p.y = ceil(p.y) g.y_v = 0 g.y_a = 0 if g.look_at: look_at = LPoint3f(g.look_at) elif g.path and len(g.path) > YAW_LOOK_AHEAD: look_at = LPoint3f(g.path[YAW_LOOK_AHEAD]) elif g.path and len(g.path): look_at = LPoint3f(g.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 - g.pitch g.pitch += utils.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 - g.yaw target_yaw_d = (target_yaw_d + 180) % 360 - 180 g.yaw += utils.cap(target_yaw_d, 30) else: target_pitch_d = 0 - g.pitch g.pitch += utils.cap(target_pitch_d, 10) packet = serverbound.play.PositionAndLookPacket(x=p.x, feet_y=p.y, z=p.z, pitch=g.pitch, yaw=g.yaw, on_ground=(not in_air)) g.connection.write_packet(packet, force=True) g.game.tick() g.job.tick() def init(global_state): g = global_state g.time = 0 g.path = [] g.look_at = None g.y_v = 0 g.y_a = 0 g.yaw = 360 g.pitch = 0 g.breaking = None g.break_time = 0 g.dumping = None g.item_lock = False g.command_lock = False g.window = None g.job = jobs.JobStates(g) g.chopped_tree = False def bot(global_state): g = global_state if not g.mcdata: g.mcdata = DataManager('./mcdata') if not g.connection: auth_token = authentication.AuthenticationToken() try: auth_token.authenticate(USERNAME, PASSWORD) except YggdrasilError as e: print(e) sys.exit() print("Logged in as %s..." % auth_token.username) g.connection = Connection(SERVER, PORT, auth_token=auth_token) g.chunks = ChunksManager(g.mcdata) g.connection.connect() g.chunks.register(g.connection) g.chat = ChatManager(g) g.game = game.Game(g) g.world = game.MCWorld(g) try: while not g.pos: time.sleep(utils.TICK) print('Player loaded.') while not g.chunks.check_loaded(g.pos, 529): time.sleep(utils.TICK) print('Chunks loaded.') init(g) print('Initialized.') while g.running: tick(g) global last_tick sleep_time = utils.TICK + last_tick - time.time() if sleep_time < 0: sleep_time = 0 time.sleep(sleep_time) last_tick = time.time() finally: print('Removing listeners...') g.connection.packet_listeners = [] g.connection.early_packet_listeners = [] g.connection.outgoing_packet_listeners = [] g.connection.early_outgoing_packet_listeners = [] print('Bot module loaded.')