|
|
|
@ -1,5 +1,6 @@ |
|
|
|
|
import os |
|
|
|
|
import time |
|
|
|
|
import functools |
|
|
|
|
from math import ceil, floor, hypot |
|
|
|
|
|
|
|
|
|
import blocks |
|
|
|
@ -11,6 +12,9 @@ from minecraft.networking.packets import Packet, clientbound, serverbound |
|
|
|
|
from minecraft.compat import input |
|
|
|
|
from minecraft.managers import ChunksManager |
|
|
|
|
|
|
|
|
|
class AStarTimeout(Exception): |
|
|
|
|
pass |
|
|
|
|
|
|
|
|
|
class DataManager: |
|
|
|
|
def __init__(self): |
|
|
|
|
self.blocks_states = {} |
|
|
|
@ -107,19 +111,41 @@ PARKOUR = [ |
|
|
|
|
PARKOUR_WEST, |
|
|
|
|
] |
|
|
|
|
|
|
|
|
|
HYPOT_LUT = { |
|
|
|
|
(0, -1): 1.0, |
|
|
|
|
(0, 1): 1.0, |
|
|
|
|
(1, 0): 1.0, |
|
|
|
|
(-1, 0): 1.0, |
|
|
|
|
(1, -1): 1.414, |
|
|
|
|
(-1, -1): 1.414, |
|
|
|
|
(1, 1): 1.414, |
|
|
|
|
(-1, 1): 1.414, |
|
|
|
|
(0, 2): 2.0, |
|
|
|
|
(-2, 0): 2.0, |
|
|
|
|
(2, 0): 2.0, |
|
|
|
|
(0, -2): 2.0, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def padd(p1, p2): |
|
|
|
|
return (p1[0] + p2[0], p1[1] + p2[1], p1[2] + p2[2]) |
|
|
|
|
|
|
|
|
|
def pint(p): |
|
|
|
|
return (int(p[0]), int(p[1]), int(p[2])) |
|
|
|
|
|
|
|
|
|
# larger started being slower |
|
|
|
|
BLOCK_CACHE_SIZE = 2**14 |
|
|
|
|
|
|
|
|
|
class MazeSolver(AStar): |
|
|
|
|
def __init__(self, chunks): |
|
|
|
|
self.chunks = chunks |
|
|
|
|
self.start_time = time.time() |
|
|
|
|
|
|
|
|
|
@functools.lru_cache(maxsize=BLOCK_CACHE_SIZE) |
|
|
|
|
def bair(self, p): |
|
|
|
|
return self.chunks.get_block_at(*p) in blocks.NON_SOLID_IDS |
|
|
|
|
|
|
|
|
|
@functools.lru_cache(maxsize=BLOCK_CACHE_SIZE) |
|
|
|
|
def bavoid(self, p): |
|
|
|
|
return self.chunks.get_block_at(*p) in blocks.AVOID_IDS |
|
|
|
|
|
|
|
|
@ -225,18 +251,19 @@ class MazeSolver(AStar): |
|
|
|
|
return True |
|
|
|
|
|
|
|
|
|
def check_parkour(self, node, offset): |
|
|
|
|
if not self.check_ascend(node, offset): |
|
|
|
|
return False |
|
|
|
|
|
|
|
|
|
dest = padd(node, offset) |
|
|
|
|
half_offset = tuple(int(0.5*x) for x in offset) |
|
|
|
|
half_offset = (int(offset[0]/2), offset[1], int(offset[2]/2)) |
|
|
|
|
middle = padd(node, half_offset) |
|
|
|
|
middle_head = padd(middle, BLOCK_ABOVE) |
|
|
|
|
|
|
|
|
|
# dont jump if we can walk instead |
|
|
|
|
if not self.bair(padd(middle, BLOCK_BELOW)): |
|
|
|
|
return False |
|
|
|
|
|
|
|
|
|
if not self.check_ascend(node, offset): |
|
|
|
|
return False |
|
|
|
|
|
|
|
|
|
middle_head = padd(middle, BLOCK_ABOVE) |
|
|
|
|
|
|
|
|
|
if not self.bair(middle_head): |
|
|
|
|
return False |
|
|
|
|
|
|
|
|
@ -270,12 +297,16 @@ class MazeSolver(AStar): |
|
|
|
|
if self.check_parkour(node, offset): |
|
|
|
|
results.append(padd(node, offset)) |
|
|
|
|
|
|
|
|
|
if not results: |
|
|
|
|
if time.time() - self.start_time > 2.0: |
|
|
|
|
raise(AStarTimeout) |
|
|
|
|
|
|
|
|
|
return results |
|
|
|
|
|
|
|
|
|
def distance_between(self, n1, n2): |
|
|
|
|
(x1, y1, z1) = n1 |
|
|
|
|
(x2, y2, z2) = n2 |
|
|
|
|
return hypot(x2 - x1, z2 - z1) |
|
|
|
|
return HYPOT_LUT[x2 - x1, z2 - z1] |
|
|
|
|
|
|
|
|
|
def heuristic_cost_estimate(self, n1, n2): |
|
|
|
|
(x1, y1, z1) = n1 |
|
|
|
@ -407,10 +438,13 @@ def main(connection, player_info): |
|
|
|
|
s['goal'] = LPoint3f(x=p.location[0], y=p.location[1], z=p.location[2]) |
|
|
|
|
print('new waypoint:', s['goal']) |
|
|
|
|
|
|
|
|
|
start = time.time() |
|
|
|
|
solution = MazeSolver(player_info.chunks).astar(pint(player_info.pos), pint(s['goal'])) |
|
|
|
|
if solution: |
|
|
|
|
s['path'] = list(solution) |
|
|
|
|
print(s['path']) |
|
|
|
|
solution = list(solution) |
|
|
|
|
s['path'] = solution |
|
|
|
|
print(len(solution)) |
|
|
|
|
print(round(time.time() - start, 3), 'seconds') |
|
|
|
|
else: |
|
|
|
|
packet = serverbound.play.ChatPacket() |
|
|
|
|
packet.message = 'No path found' |
|
|
|
|