Compare commits

..

No commits in common. "c33e1e04b8f0c139f0bc8d40a6e617cc4200efa1" and "c30ac5aefc3fe0225deb1386e410ddf9be6eb393" have entirely different histories.

6 changed files with 68 additions and 186 deletions

View File

@ -15,13 +15,9 @@ for name, data in JSON_BLOCKS.items():
for state in data['states']:
BLOCKS[state['id']] = name.replace('minecraft:', '')
AIR = 0
SAND = 66
SINGLE_SNOW = 3921
SOUL_TORCH = 4008
AVOID = [
'lava',
'water',

7
bot.py
View File

@ -32,8 +32,6 @@ import utils
importlib.reload(utils)
import path
importlib.reload(path)
import jobs
importlib.reload(jobs)
last_tick = time.time()
@ -135,7 +133,6 @@ def tick(global_state):
g.connection.write_packet(packet, force=True)
g.game.tick()
g.job.tick()
def init(global_state):
@ -153,7 +150,8 @@ def init(global_state):
g.breaking = None
g.break_time = 0
g.job = jobs.JobStates(g)
#g.jobstate = JobStates(connection, player_info)
#g.jobstate.run()
def bot(global_state):
g = global_state
@ -193,7 +191,6 @@ def bot(global_state):
print('Chunks loaded.')
init(g)
print('Initialized.')
while g.running:
tick(g)

86
game.py
View File

@ -2,13 +2,12 @@ import re
import time
import importlib
from math import hypot
from itertools import count
from panda3d.core import LPoint3f
from minecraft.networking.packets import Packet, clientbound, serverbound
from protocol.packets import TimeUpdatePacket, SetSlotPacket, PlayerDiggingPacket, BlockBreakAnimationPacket, AcknowledgePlayerDiggingPacket, HeldItemChangePacket, PickItemPacket
from protocol.packets import TimeUpdatePacket, SetSlotPacket, PlayerDiggingPacket, BlockBreakAnimationPacket, AcknowledgePlayerDiggingPacket
import utils
importlib.reload(utils)
@ -16,8 +15,6 @@ import path
importlib.reload(path)
import blocks
importlib.reload(blocks)
import items
importlib.reload(items)
class MCWorld:
def __init__(self, global_state):
@ -43,7 +40,7 @@ class MCWorld:
def find_trees(self, center, distance):
logs = []
for i in range(5):
check = utils.padd(center, utils.alternate(i, 3))
check = utils.padd(center, alternate(i, 3))
logs.extend(self.find_blocks(check, distance, blocks.LOG_IDS, 50))
trees = []
@ -69,37 +66,37 @@ class MCWorld:
log = utils.padd(log, path.BLOCK_BELOW)
trees.append(log)
trees.sort(key=lambda x: utils.phyp(center, x))
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 = path.Pathfinder(self.g.chunks)
maze_solver = MazeSolver(self.g.chunks)
result = []
# TODO: make sure only non-solid and leaves between
# make sure traversable too
for distance in range(5):
for direction in path.CHECK_DIRECTIONS:
offset = utils.pmul(direction, distance+1)
for direction in CHECK_DIRECTIONS:
offset = pmul(direction, distance+1)
if maze_solver.check_traverse(tree, offset):
result.append(utils.padd(tree, offset))
return result
def path_to_place(self, start, place):
maze_solver = path.Pathfinder(self.g.chunks)
maze_solver = MazeSolver(self.g.chunks)
try:
s = maze_solver.astar(start, place)
return list(s) if s else None
except path.AStarTimeout:
except AStarTimeout:
return None
def find_bed_areas(self, center, distance):
air = []
for i in range(5):
check = utils.padd(center, utils.alternate(i, 1))
check = utils.padd(center, alternate(i, 1))
air.extend(self.find_blocks(check, distance, [0], 200))
areas = []
@ -118,11 +115,11 @@ class MCWorld:
areas.append(a)
areas.sort(key=lambda x: utils.phyp(center, x))
areas.sort(key=lambda x: phyp(center, x))
return areas
def sand_adjacent_safe(self, sand):
for direction in path.CHECK_DIRECTIONS:
for direction in CHECK_DIRECTIONS:
if self.block_at(*utils.padd(sand, direction)) in blocks.AVOID_IDS:
return False
return True
@ -130,8 +127,8 @@ class MCWorld:
def find_sand(self, center, distance, origin):
sand = []
for i in range(10):
check = utils.padd(center, utils.alternate(i, 1))
sand.extend(self.find_blocks(check, distance, [blocks.SAND], 20))
check = utils.padd(center, alternate(i, 1))
sand.extend(self.find_blocks(check, distance, [66], 20))
safe_sand = []
for s in sand:
@ -158,7 +155,7 @@ class MCWorld:
# returns coords in a cardinal direction where we can stand by bed
result = []
for direction in path.CHECK_DIRECTIONS:
for direction in CHECK_DIRECTIONS:
result.append(utils.padd(area, direction))
return result
@ -191,11 +188,11 @@ class Game:
print('new waypoint:', self.g.goal)
start = time.time()
solution = path.Pathfinder(self.g.chunks).astar(utils.pint(self.g.pos), utils.pint(self.g.goal))
solution = path.Pathfinder(self.g.chunks).astar(utils.pint(self.g.pos), utils.pint(g.goal))
if solution:
solution = list(solution)
self.g.path = solution
self.g.job.state = self.g.job.stop
#g.jobstate.state = self.g.jobstate.stop
print(len(solution))
print(solution)
print(round(time.time() - start, 3), 'seconds')
@ -264,34 +261,6 @@ class Game:
self.break_block((616, 78, 496))
reply = 'ok'
if command == 'gather' and data:
if data == 'wood':
self.g.job.state = self.g.job.lumberjack
reply = 'ok'
elif data == 'sand':
self.g.job.state = self.g.job.gather_sand
reply = 'ok'
if reply:
for i in self.g.inv.values():
print(i.item_id)
if i.item_id in items.BED_IDS:
break
else:
reply += ', I need a bed'
if command == 'stop':
self.g.job.state = self.g.job.stop
reply = 'ok'
if command == 'inv':
for i in self.g.inv.values():
if i.present:
print(items.ITEM_NAMES[i.item_id], 'x', i.item_count)
if command == 'time':
reply = str(self.g.time)
if reply:
print(reply)
self.g.chat.send(reply)
@ -322,7 +291,6 @@ class Game:
packet.location = self.g.breaking
packet.face = 1
self.g.connection.write_packet(packet)
self.g.chunks.set_block_at(*self.g.breaking, 0)
self.g.breaking = None
@ -330,8 +298,7 @@ class Game:
print(packet)
def handle_break_ack(self, packet):
#print(packet)
return
print(packet)
def animate(self):
packet = serverbound.play.AnimationPacket()
@ -341,7 +308,7 @@ class Game:
def place_block(self, location, face):
packet = serverbound.play.PlayerBlockPlacementPacket()
packet.hand = 0
packet.location = location
packet.location = pos
packet.face = face
packet.x = 0.5
packet.y = 0.5
@ -349,23 +316,6 @@ class Game:
packet.inside_block = False
self.g.connection.write_packet(packet)
def pick(self, slot):
packet = PickItemPacket()
packet.slot_to_use = slot
self.g.connection.write_packet(packet)
def hold(self, slot):
packet = HeldItemChangePacket()
packet.slot = slot
self.g.connection.write_packet(packet)
def choose_slot(self, slot):
if slot >= 36:
slot -= 36
self.hold(slot)
else:
self.pick(slot)
def tick(self):
if self.g.breaking:
self.animate()

View File

@ -1,31 +0,0 @@
import json
with open('mcdata/registries.json') as f:
ITEMS = json.load(f)['minecraft:item']['entries']
BEDS = [
'white_bed',
'orange_bed',
'magenta_bed',
'light_blue_bed',
'yellow_bed',
'lime_bed',
'pink_bed',
'gray_bed',
'light_gray_bed',
'cyan_bed',
'purple_bed',
'blue_bed',
'brown_bed',
'green_bed',
'red_bed',
'black_bed',
]
BED_IDS = set()
for item_name in BEDS:
BED_IDS.add(ITEMS['minecraft:'+item_name]['protocol_id'])
ITEM_NAMES = {}
for item_name, item in ITEMS.items():
ITEM_NAMES[ITEMS[item_name]['protocol_id']] = item_name.replace('minecraft:', '')

87
jobs.py
View File

@ -13,8 +13,6 @@ import path
importlib.reload(path)
import blocks
importlib.reload(blocks)
import items
importlib.reload(items)
class LumberjackStates:
@ -57,10 +55,10 @@ class LumberjackStates:
self.state = self.cleanup
return
navpath = w.path_to_place(p, self.openings[0])
path = w.path_to_place(p, self.openings[0])
if navpath:
self.g.path = navpath
if path:
self.g.path = path
self.state = self.going_to_tree
else:
self.openings.pop(0)
@ -73,10 +71,10 @@ class LumberjackStates:
def clear_leaves(self):
if not self.g.breaking:
p = utils.pint(self.g.pos)
diff = utils.psub(self.tree, p)
diff = psub(self.tree, p)
for x in utils.diffrange(diff[0]):
for z in utils.diffrange(diff[2]):
for x in diffrange(diff[0]):
for z in diffrange(diff[2]):
for y in range(2):
check = utils.padd(p, (x, y, z))
if check == self.tree:
@ -102,10 +100,10 @@ class LumberjackStates:
else:
w = self.g.world
p = utils.pint(self.g.pos)
navpath = w.path_to_place(p, self.tree)
path = w.path_to_place(p, self.tree)
if navpath:
self.g.path = navpath
if path:
self.g.path = path
self.state = self.going_to_trunk_base
else:
self.openings.pop(0)
@ -136,7 +134,7 @@ class LumberjackStates:
def wait(self):
# wait for the last log to fall
if self.wait_time > 0:
self.wait_time -= utils.TICK
self.wait_time -= TICK
else:
self.state = self.cleanup
@ -151,6 +149,7 @@ class LumberjackStates:
def __init__(self, global_state):
self.g = global_state
self.l = self.g.local_state
self.state = self.idle
self.tree = None
@ -180,14 +179,12 @@ class GatherSandStates:
w = self.g.world
p = utils.pint(self.g.pos)
sand = w.find_sand(p, 50, self.origin)
sand = w.find_sand(p, 150, self.origin)
print('Found sand:', sand)
for check in sand:
if check in self.bad_sand:
continue
self.sand = check
break
while sand[0] in self.bad_sand:
sand.pop(0)
self.sand = sand[0]
self.state = self.nav_to_sand
@ -195,12 +192,12 @@ class GatherSandStates:
w = self.g.world
p = utils.pint(self.g.pos)
self.g.chunks.set_block_at(*self.sand, blocks.AIR)
navpath = w.path_to_place(p, self.sand)
self.g.chunks.set_block_at(*self.sand, blocks.SAND)
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 navpath:
self.g.path = navpath[:-1]
if path:
self.g.path = path[:-1]
self.state = self.going_to_sand
else:
self.bad_sand.append(self.sand)
@ -222,10 +219,10 @@ class GatherSandStates:
def get_sand(self):
w = self.g.world
p = utils.pint(self.g.pos)
navpath = w.path_to_place(p, self.sand)
path = w.path_to_place(p, self.sand)
if navpath:
self.g.path = navpath
if path:
self.g.path = path
self.state = self.going_to_item
else:
self.bad_sand.append(self.sand)
@ -247,6 +244,7 @@ class GatherSandStates:
def __init__(self, global_state):
self.g = global_state
self.l = self.g.local_state
self.state = self.idle
self.origin = utils.pint(self.g.pos)
@ -291,16 +289,16 @@ class SleepWithBedStates:
openings = w.find_bed_openings(self.area)
for o in openings:
navpath = w.path_to_place(p, o)
path = w.path_to_place(p, o)
self.opening = o
if navpath: break
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
self.g.path = navpath
self.g.path = path
self.state = self.going_to_area
self.last_area = self.area
@ -314,22 +312,22 @@ class SleepWithBedStates:
if item.item_id in items.BED_IDS:
print('Found bed in slot', slot)
self.g.look_at = utils.padd(self.area, path.BLOCK_BELOW)
self.g.game.choose_slot(slot)
choose_slot(self.connection, slot)
self.state = self.place_bed
break
else: # for
self.g.chat.send('I need a bed')
say(self.connection, 'I need a bed')
self.state = self.cleanup
def place_bed(self):
self.g.game.place_block(self.area, BlockFace.TOP)
place_block(self.connection, 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)
self.g.chat.send('zzz')
place_block(self.connection, self.area, BlockFace.TOP)
say(self.connection, 'zzz')
self.state = self.sleep_bed
def sleep_bed(self):
@ -350,7 +348,7 @@ class SleepWithBedStates:
def wait(self):
# wait to pick up bed
if self.wait_time > 0:
self.wait_time -= utils.TICK
self.wait_time -= TICK
else:
self.state = self.cleanup
@ -364,6 +362,7 @@ class SleepWithBedStates:
def __init__(self, global_state):
self.g = global_state
self.l = self.g.local_state
self.state = self.idle
self.area = None
@ -403,9 +402,10 @@ class JobStates:
s.state = s.init
# check time, etc
self.prev_state = self.gather_sand
self.state = self.sleep_with_bed
return
if self.survive:
self.prev_state = self.gather_sand
self.state = self.sleep_with_bed
return
s.run()
@ -417,9 +417,10 @@ class JobStates:
s.state = s.init
# check time, etc
self.prev_state = self.lumberjack
self.state = self.sleep_with_bed
return
if self.survive:
self.prev_state = self.lumberjack
self.state = self.sleep_with_bed
return
s.run()
@ -431,12 +432,14 @@ class JobStates:
def __init__(self, global_state):
self.g = global_state
self.l = self.g.local_state
self.state = self.idle
self.prev_state = None
self.lumberjack_states = LumberjackStates(self.g)
self.gather_sand_states = GatherSandStates(self.g)
self.sleep_with_bed_states = SleepWithBedStates(self.g)
self.survive = False
def tick(self):
def run(self):
self.state()

View File

@ -1,5 +1,5 @@
import importlib
from math import floor, ceil, sqrt, hypot
from math import floor, ceil
import blocks
importlib.reload(blocks)
@ -22,7 +22,7 @@ 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*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]))
@ -31,45 +31,12 @@ def cap(x, amount):
sign = 1 if x >= 0 else -1
return sign * min(abs(x), amount)
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_time(block_id, held_item=0, in_water=False, on_ground=True, enchantments=[], effects={}):
# from PrismarineJS/prismarine-block
data = blocks.get(block_id)
can_harvest = 'harvestTools' not in data or str(held_item) in data['harvestTools']
material = data.get('material', 'n/a')
tool_multipliers = blocks.mcd.materials.get(material, [])
tool_multipliers = blocks.mcd.materials.get(data['material'], [])
is_best_tool = held_item in tool_multipliers
time = data['hardness']