minecraft-bot/bot.py

281 lines
7.3 KiB
Python

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 vector import Point3D, Vector3D
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)
import mcdata
importlib.reload(mcdata)
last_tick = time.time()
PITCH_ANGLE_DIR = Vector3D((0, 1, 0))
YAW_ANGLE_DIR = Vector3D((0, 0, -1))
YAW_ANGLE_REF = Vector3D((0, 1, 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, 288):
if not g.chunks.loading:
print('Loading chunks', end='', flush=True)
g.chunks.loading = True
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
else:
if g.chunks.loading:
print()
print('Chunks loaded.')
g.chunks.loading = False
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 = Point3D(g.path[0])
target.x += 0.5
target.z += 0.5
if g.afk_timeout > 0:
target = None
g.afk_timeout -= utils.TICK
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))
block_above = 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
g.crawling = block_above not in blocks.NON_SOLID_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 = Point3D(g.look_at)
elif g.path and len(g.path) > YAW_LOOK_AHEAD:
look_at = Point3D(g.path[YAW_LOOK_AHEAD])
elif g.path and len(g.path):
look_at = Point3D(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
if look_at_d.length() > 0.6:
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)
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.crawling = False
g.breaking = None
g.break_time = 0
g.dumping = None
g.draining = False
g.item_lock = False
g.command_lock = False
g.trades = []
g.job = jobs.JobStates(g)
g.chopped_tree = False
g.afk_timeout = 0
g.filling = False
def bot(global_state):
g = global_state
if not g.mcdata:
g.mcdata = DataManager('./minecraft_data')
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.')
init(g)
g.game.close_window()
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.')