184 lines
5.2 KiB
Python
184 lines
5.2 KiB
Python
import importlib
|
|
import collections
|
|
from math import floor, ceil, sqrt
|
|
|
|
from mosfet.info import blocks
|
|
from mosfet.info import mcdata
|
|
|
|
TICK = 0.05
|
|
|
|
def hypot(*coordinates):
|
|
# python's 3D hypot is too new, so we'll use our own
|
|
return sqrt(sum(x**2 for x in coordinates))
|
|
|
|
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=None, effects=None):
|
|
"""Return vanilla block-breaking duration rounded to whole game ticks."""
|
|
held_item = str(held_item)
|
|
block_data = blocks.get(block_id)
|
|
hardness = block_data.get('hardness', 0)
|
|
if hardness < 0:
|
|
return float('inf')
|
|
|
|
can_harvest = (
|
|
'harvestTools' not in block_data or
|
|
held_item in block_data['harvestTools'])
|
|
material = block_data.get('material', 'n/a')
|
|
tool_multipliers = mcdata.mcd.materials.get(material, {})
|
|
speed = tool_multipliers.get(held_item, 1.0)
|
|
|
|
enchantments = enchantments or {}
|
|
if speed > 1:
|
|
efficiency = int(enchantments.get(
|
|
'efficiency', enchantments.get('minecraft:efficiency', 0)) or 0)
|
|
if efficiency > 0:
|
|
speed += efficiency * efficiency + 1
|
|
|
|
effects = effects or {}
|
|
haste = int(effects.get('haste', effects.get('minecraft:haste', 0)) or 0)
|
|
if haste >= 0 and ('haste' in effects or 'minecraft:haste' in effects):
|
|
speed *= 1 + 0.2 * (haste + 1)
|
|
fatigue = int(effects.get(
|
|
'mining_fatigue', effects.get('minecraft:mining_fatigue', -1)))
|
|
if fatigue >= 0:
|
|
speed *= (0.3, 0.09, 0.0027, 0.00081, 0.000243)[min(fatigue, 4)]
|
|
|
|
duration = hardness * (1.5 if can_harvest else 5.0) / speed
|
|
if in_water:
|
|
duration *= 5.0
|
|
if not on_ground:
|
|
duration *= 5.0
|
|
|
|
# Vanilla advances breaking progress in 1/20-second ticks; clients cannot
|
|
# finish between ticks. Round up, while avoiding floating-point over-round.
|
|
ticks = max(1, ceil(duration / TICK - 1e-9))
|
|
return ticks * TICK
|
|
|
|
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 get_neighbors_3d(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),
|
|
]
|