minecraft-bot/utils.py

182 lines
4.7 KiB
Python

import importlib
import collections
from math import floor, ceil, sqrt, hypot
import blocks
import mcdata
TICK = 0.05
def padd(p1, p2):
return (p1[0] + p2[0], p1[1] + p2[1], p1[2] + p2[2])
def psub(p1, p2):
return (p1[0] - p2[0], p1[1] - p2[1], p1[2] - p2[2])
def pmul(p, s):
return (s*p[0], s*p[1], s*p[2])
def phyp(p1, p2):
return hypot(p1[0] - p2[0], p1[1] - p2[1], p1[2] - p2[2])
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
def phyp_king(p1, p2):
# calculates the Chebyshev distance
return max(abs(p1[0] - p2[0]), abs(p1[1] - p2[1]), abs(p1[2] - p2[2]))
def pint(p):
return (floor(p[0]), floor(p[1]), floor(p[2]))
def pboundingbox(p1, p2):
b1 = (min(p1[0], p2[0]), min(p1[1], p2[1]), min(p1[2], p2[2]))
b2 = (max(p1[0], p2[0]), max(p1[1], p2[1]), max(p1[2], p2[2]))
return b1, b2
def pvolume(p1, p2):
b1, b2 = pboundingbox(p1, p2)
box = psub(b2, b1)
return (box[0]+1) * (box[1]+1) * (box[2]+1)
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
held_item = str(held_item)
block_data = blocks.get(block_id)
can_harvest = 'harvestTools' not in block_data or str(held_item) in block_data['harvestTools']
material = block_data.get('material', 'n/a')
tool_multipliers = mcdata.mcd.materials.get(material, [])
is_best_tool = held_item in tool_multipliers
time = block_data['hardness']
if can_harvest:
time *= 1.5
else:
time *= 5.0
if is_best_tool:
speed_multiplier = tool_multipliers[held_item]
# TODO: calc efficiency, haste, mining fatigue
else:
speed_multiplier = 1.0
time /= speed_multiplier
if in_water: time *= 5.0
if not on_ground: time *= 5.0
return time
def search_2d(distance=0):
def get_neighbors(x,y,z):
return [
(x+1, y+0, z+0),
#(x+1, y+0, z+1),
(x+0, y+0, z-1),
#(x-1, y+0, z+1),
(x-1, y+0, z+0),
#(x-1, y+0, z-1),
(x+0, y+0, z+1),
#(x+1, y+0, z-1),
]
to_visit = collections.deque([(0, 0, 0)])
visited = set()
while to_visit:
cur = to_visit.pop()
if cur in visited:
continue
if distance and hypot(*cur) > distance:
continue
for neighbor in get_neighbors(*cur):
to_visit.appendleft(neighbor)
visited.add(cur)
yield cur
def search_3d(distance=0, y_limit=0):
def get_neighbors(x,y,z):
return [
(x+1, y+1, z+0),
(x+1, y-1, z+0),
(x+1, y+1, z+1),
(x+1, y+0, z+1),
(x+1, y-1, z+1),
(x+1, y+1, z-1),
(x+1, y+0, z-1),
(x+1, y-1, z-1),
(x+1, y+0, z+0),
(x+0, y+1, z+0),
(x+0, y-1, z+0),
(x+0, y+1, z+1),
(x+0, y+0, z+1),
(x+0, y-1, z+1),
(x+0, y+1, z-1),
(x+0, y+0, z-1),
(x+0, y-1, z-1),
(x-1, y+1, z+0),
(x-1, y-1, z+0),
(x-1, y+1, z+1),
(x-1, y+0, z+1),
(x-1, y-1, z+1),
(x-1, y+1, z-1),
(x-1, y+0, z-1),
(x-1, y-1, z-1),
(x-1, y+0, z+0),
]
to_visit = collections.deque([(0, 0, 0)])
visited = set()
while to_visit:
cur = to_visit.pop()
if cur in visited:
continue
if y_limit and abs(cur[1]) > y_limit:
continue
if distance and hypot(*cur) > distance:
continue
for neighbor in get_neighbors(*cur):
to_visit.appendleft(neighbor)
visited.add(cur)
yield cur