Compare commits
5 Commits
c30ac5aefc
...
c33e1e04b8
Author | SHA1 | Date | |
---|---|---|---|
c33e1e04b8 | |||
ce22946023 | |||
5c21634d16 | |||
f2e0b162f9 | |||
58458a561f |
|
@ -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
7
bot.py
|
@ -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
86
game.py
|
@ -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
31
items.py
Normal 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
87
jobs.py
|
@ -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()
|
||||
|
|
39
utils.py
39
utils.py
|
@ -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']
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user