Locate nearest tree and pathfind to it
This commit is contained in:
parent
e124983414
commit
b0c27a98c1
30
blocks.py
30
blocks.py
|
@ -183,6 +183,26 @@ NON_SOLID = [
|
||||||
]
|
]
|
||||||
SINGLE_SNOW = 3919
|
SINGLE_SNOW = 3919
|
||||||
|
|
||||||
|
|
||||||
|
LOGS = [
|
||||||
|
'minecraft:oak_log',
|
||||||
|
'minecraft:spruce_log',
|
||||||
|
'minecraft:birch_log',
|
||||||
|
'minecraft:jungle_log',
|
||||||
|
'minecraft:acacia_log',
|
||||||
|
'minecraft:dark_oak_log',
|
||||||
|
]
|
||||||
|
|
||||||
|
LEAVES = [
|
||||||
|
'minecraft:oak_leaves',
|
||||||
|
'minecraft:spruce_leaves',
|
||||||
|
'minecraft:birch_leaves',
|
||||||
|
'minecraft:jungle_leaves',
|
||||||
|
'minecraft:acacia_leaves',
|
||||||
|
'minecraft:dark_oak_leaves',
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
NON_SOLID_IDS = set([SINGLE_SNOW])
|
NON_SOLID_IDS = set([SINGLE_SNOW])
|
||||||
for block_name in NON_SOLID:
|
for block_name in NON_SOLID:
|
||||||
for state in BLOCKS[block_name]['states']:
|
for state in BLOCKS[block_name]['states']:
|
||||||
|
@ -192,3 +212,13 @@ AVOID_IDS = set()
|
||||||
for block_name in AVOID:
|
for block_name in AVOID:
|
||||||
for state in BLOCKS[block_name]['states']:
|
for state in BLOCKS[block_name]['states']:
|
||||||
AVOID_IDS.add(state['id'])
|
AVOID_IDS.add(state['id'])
|
||||||
|
|
||||||
|
LOG_IDS = set()
|
||||||
|
for block_name in LOGS:
|
||||||
|
for state in BLOCKS[block_name]['states']:
|
||||||
|
LOG_IDS.add(state['id'])
|
||||||
|
|
||||||
|
LEAF_IDS = set()
|
||||||
|
for block_name in LEAVES:
|
||||||
|
for state in BLOCKS[block_name]['states']:
|
||||||
|
LEAF_IDS.add(state['id'])
|
||||||
|
|
128
bot.py
128
bot.py
|
@ -1,7 +1,9 @@
|
||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
import functools
|
import functools
|
||||||
from math import ceil, floor, hypot
|
from math import ceil, floor, hypot, sqrt
|
||||||
|
from itertools import count
|
||||||
|
|
||||||
|
|
||||||
import blocks
|
import blocks
|
||||||
|
|
||||||
|
@ -318,6 +320,116 @@ class MazeSolver(AStar):
|
||||||
(x2, y2, z2) = n2
|
(x2, y2, z2) = n2
|
||||||
return hypot(x2 - x1, z2 - z1)
|
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
|
TICK = 0.05
|
||||||
ANGLE_DIR = LVector3f(x=0, y=0, z=-1)
|
ANGLE_DIR = LVector3f(x=0, y=0, z=-1)
|
||||||
ANGLE_REF = LVector3f(x=0, y=1, z=0)
|
ANGLE_REF = LVector3f(x=0, y=1, z=0)
|
||||||
|
@ -497,6 +609,20 @@ def main(connection, player_info):
|
||||||
except BaseException as e:
|
except BaseException as e:
|
||||||
import traceback
|
import traceback
|
||||||
print(traceback.format_exc())
|
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(
|
connection.register_packet_listener(
|
||||||
|
|
Loading…
Reference in New Issue
Block a user