Compare commits

...

5 Commits

Author SHA1 Message Date
c33e1e04b8 Adjust find sand algo 2020-09-17 03:11:08 -06:00
ce22946023 Fix more sand bugs 2020-09-17 00:01:10 -06:00
5c21634d16 Fix sand gather job bugs 2020-09-16 20:31:46 -06:00
f2e0b162f9 Port over job sleeping 2020-09-16 20:11:42 -06:00
58458a561f Fix jobstate bugs 2020-09-16 19:12:01 -06:00
6 changed files with 186 additions and 68 deletions

View File

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

86
game.py
View File

@ -2,12 +2,13 @@ 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
from protocol.packets import TimeUpdatePacket, SetSlotPacket, PlayerDiggingPacket, BlockBreakAnimationPacket, AcknowledgePlayerDiggingPacket, HeldItemChangePacket, PickItemPacket
import utils
importlib.reload(utils)
@ -15,6 +16,8 @@ import path
importlib.reload(path)
import blocks
importlib.reload(blocks)
import items
importlib.reload(items)
class MCWorld:
def __init__(self, global_state):
@ -40,7 +43,7 @@ class MCWorld:
def find_trees(self, center, distance):
logs = []
for i in range(5):
check = utils.padd(center, alternate(i, 3))
check = utils.padd(center, utils.alternate(i, 3))
logs.extend(self.find_blocks(check, distance, blocks.LOG_IDS, 50))
trees = []
@ -66,37 +69,37 @@ class MCWorld:
log = utils.padd(log, path.BLOCK_BELOW)
trees.append(log)
trees.sort(key=lambda x: phyp(center, x))
trees.sort(key=lambda x: utils.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.g.chunks)
maze_solver = path.Pathfinder(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 CHECK_DIRECTIONS:
offset = pmul(direction, distance+1)
for direction in path.CHECK_DIRECTIONS:
offset = utils.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 = MazeSolver(self.g.chunks)
maze_solver = path.Pathfinder(self.g.chunks)
try:
s = maze_solver.astar(start, place)
return list(s) if s else None
except AStarTimeout:
except path.AStarTimeout:
return None
def find_bed_areas(self, center, distance):
air = []
for i in range(5):
check = utils.padd(center, alternate(i, 1))
check = utils.padd(center, utils.alternate(i, 1))
air.extend(self.find_blocks(check, distance, [0], 200))
areas = []
@ -115,11 +118,11 @@ class MCWorld:
areas.append(a)
areas.sort(key=lambda x: phyp(center, x))
areas.sort(key=lambda x: utils.phyp(center, x))
return areas
def sand_adjacent_safe(self, sand):
for direction in CHECK_DIRECTIONS:
for direction in path.CHECK_DIRECTIONS:
if self.block_at(*utils.padd(sand, direction)) in blocks.AVOID_IDS:
return False
return True
@ -127,8 +130,8 @@ class MCWorld:
def find_sand(self, center, distance, origin):
sand = []
for i in range(10):
check = utils.padd(center, alternate(i, 1))
sand.extend(self.find_blocks(check, distance, [66], 20))
check = utils.padd(center, utils.alternate(i, 1))
sand.extend(self.find_blocks(check, distance, [blocks.SAND], 20))
safe_sand = []
for s in sand:
@ -155,7 +158,7 @@ class MCWorld:
# returns coords in a cardinal direction where we can stand by bed
result = []
for direction in CHECK_DIRECTIONS:
for direction in path.CHECK_DIRECTIONS:
result.append(utils.padd(area, direction))
return result
@ -188,11 +191,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(g.goal))
solution = path.Pathfinder(self.g.chunks).astar(utils.pint(self.g.pos), utils.pint(self.g.goal))
if solution:
solution = list(solution)
self.g.path = solution
#g.jobstate.state = self.g.jobstate.stop
self.g.job.state = self.g.job.stop
print(len(solution))
print(solution)
print(round(time.time() - start, 3), 'seconds')
@ -261,6 +264,34 @@ 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)
@ -291,6 +322,7 @@ 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
@ -298,7 +330,8 @@ class Game:
print(packet)
def handle_break_ack(self, packet):
print(packet)
#print(packet)
return
def animate(self):
packet = serverbound.play.AnimationPacket()
@ -308,7 +341,7 @@ class Game:
def place_block(self, location, face):
packet = serverbound.play.PlayerBlockPlacementPacket()
packet.hand = 0
packet.location = pos
packet.location = location
packet.face = face
packet.x = 0.5
packet.y = 0.5
@ -316,6 +349,23 @@ 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()

31
items.py Normal file
View File

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

View File

@ -1,5 +1,5 @@
import importlib
from math import floor, ceil
from math import floor, ceil, sqrt, hypot
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*1.5
return hypot(p1[0] - p2[0], height_diff, p1[2] - p2[2]) + origin_distance*0.5
def pint(p):
return (floor(p[0]), floor(p[1]), floor(p[2]))
@ -31,12 +31,45 @@ 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']
tool_multipliers = blocks.mcd.materials.get(data['material'], [])
material = data.get('material', 'n/a')
tool_multipliers = blocks.mcd.materials.get(material, [])
is_best_tool = held_item in tool_multipliers
time = data['hardness']