|
|
|
@ -1,7 +1,9 @@ |
|
|
|
|
import os |
|
|
|
|
import time |
|
|
|
|
import functools |
|
|
|
|
from math import ceil, floor, hypot |
|
|
|
|
from math import ceil, floor, hypot, sqrt |
|
|
|
|
from itertools import count |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import blocks |
|
|
|
|
|
|
|
|
@ -318,6 +320,116 @@ class MazeSolver(AStar): |
|
|
|
|
(x2, y2, z2) = n2 |
|
|
|
|
return hypot(x2 - x1, z2 - z1) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def spiral(n): |
|
|
|
|
# return x, 0, z coords along a spiral at step n |
|
|
|
|
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) |
|
|
|
|
|
|
|
|
|
BLOCK_ABOVE = (0, +1, 0) |
|
|
|
|
BLOCK_BELOW = (0, -1, 0) |
|
|
|
|
|
|
|
|
|
CHECK_NORTH = (0, 0, -1) |
|
|
|
|
CHECK_SOUTH = (0, 0, +1) |
|
|
|
|
CHECK_EAST = (+1, 0, 0) |
|
|
|
|
CHECK_WEST = (-1, 0, 0) |
|
|
|
|
|
|
|
|
|
CHECK_DIRECTIONS = [ |
|
|
|
|
CHECK_NORTH, |
|
|
|
|
CHECK_SOUTH, |
|
|
|
|
CHECK_EAST, |
|
|
|
|
CHECK_WEST, |
|
|
|
|
] |
|
|
|
|
|
|
|
|
|
class MCWorld: |
|
|
|
|
def __init__(self, chunks): |
|
|
|
|
self.chunks = chunks |
|
|
|
|
|
|
|
|
|
def block_at(self, x, y, z): |
|
|
|
|
return self.chunks.get_block_at(x, y, z) |
|
|
|
|
|
|
|
|
|
def find_blocks(self, center, distance, block_ids, limit=0): |
|
|
|
|
# search in a spiral from center to all blocks with ID |
|
|
|
|
result = [] |
|
|
|
|
for n in count(): |
|
|
|
|
offset = spiral(n) |
|
|
|
|
check = padd(center, offset) |
|
|
|
|
if self.block_at(*check) in block_ids: |
|
|
|
|
if hypot(*offset) < distance: |
|
|
|
|
result.append(check) |
|
|
|
|
if limit and len(result) == limit: |
|
|
|
|
return result |
|
|
|
|
if offset[0] > distance: |
|
|
|
|
return result |
|
|
|
|
|
|
|
|
|
def find_tree(self, center, distance): |
|
|
|
|
logs = [] |
|
|
|
|
for i in range(5): |
|
|
|
|
check = padd(center, alternate(i, 4)) |
|
|
|
|
logs.extend(self.find_blocks(center, distance, blocks.LOG_IDS, 5)) |
|
|
|
|
|
|
|
|
|
for log in logs: |
|
|
|
|
# crawl to the top log |
|
|
|
|
while self.block_at(*padd(log, BLOCK_ABOVE)) in blocks.LOG_IDS: |
|
|
|
|
log = padd(log, BLOCK_ABOVE) |
|
|
|
|
|
|
|
|
|
# make sure it's a tree |
|
|
|
|
if self.block_at(*padd(log, BLOCK_ABOVE)) in blocks.LEAF_IDS: |
|
|
|
|
break |
|
|
|
|
else: # for |
|
|
|
|
return None |
|
|
|
|
|
|
|
|
|
# crawl to the bottom log |
|
|
|
|
while self.block_at(*padd(log, BLOCK_BELOW)) in blocks.LOG_IDS: |
|
|
|
|
log = padd(log, BLOCK_BELOW) |
|
|
|
|
|
|
|
|
|
return log |
|
|
|
|
|
|
|
|
|
def find_tree_openings(self, tree): |
|
|
|
|
# returns coords in a cardinal direction where we can stand by tree |
|
|
|
|
maze_solver = MazeSolver(self.chunks) |
|
|
|
|
result = [] |
|
|
|
|
|
|
|
|
|
for distance in range(5): |
|
|
|
|
for direction in CHECK_DIRECTIONS: |
|
|
|
|
offset = (0, 0, 0) |
|
|
|
|
for _ in range(distance): |
|
|
|
|
offset = padd(offset, direction) |
|
|
|
|
if maze_solver.check_traverse(tree, offset): |
|
|
|
|
result.append(padd(tree, offset)) |
|
|
|
|
return result |
|
|
|
|
|
|
|
|
|
def navigate_to_opening(self, start, opening): |
|
|
|
|
maze_solver = MazeSolver(self.chunks) |
|
|
|
|
|
|
|
|
|
try: |
|
|
|
|
return list(maze_solver.astar(start, opening)) |
|
|
|
|
except AStarTimeout: |
|
|
|
|
return None |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
TICK = 0.05 |
|
|
|
|
ANGLE_DIR = LVector3f(x=0, y=0, z=-1) |
|
|
|
|
ANGLE_REF = LVector3f(x=0, y=1, z=0) |
|
|
|
@ -497,6 +609,20 @@ def main(connection, player_info): |
|
|
|
|
except BaseException as e: |
|
|
|
|
import traceback |
|
|
|
|
print(traceback.format_exc()) |
|
|
|
|
elif '!tree' in chat_packet.json_data: |
|
|
|
|
try: |
|
|
|
|
mc_world = MCWorld(player_info.chunks) |
|
|
|
|
start = time.time() |
|
|
|
|
coords = mc_world.find_tree(pint(player_info.pos), 100) |
|
|
|
|
print(coords) |
|
|
|
|
openings = mc_world.find_tree_openings(coords) |
|
|
|
|
print(openings) |
|
|
|
|
path = mc_world.navigate_to_opening(pint(player_info.pos), openings[0]) |
|
|
|
|
print(path) |
|
|
|
|
print(round(time.time() - start, 3), 'seconds') |
|
|
|
|
except BaseException as e: |
|
|
|
|
import traceback |
|
|
|
|
print(traceback.format_exc()) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
connection.register_packet_listener( |
|
|
|
|