|
|
|
@ -1,6 +1,7 @@ |
|
|
|
|
import re |
|
|
|
|
import time |
|
|
|
|
import importlib |
|
|
|
|
from math import hypot |
|
|
|
|
|
|
|
|
|
from panda3d.core import LPoint3f |
|
|
|
|
|
|
|
|
@ -15,6 +16,151 @@ importlib.reload(path) |
|
|
|
|
import blocks |
|
|
|
|
importlib.reload(blocks) |
|
|
|
|
|
|
|
|
|
class MCWorld: |
|
|
|
|
def __init__(self, global_state): |
|
|
|
|
self.g = global_state |
|
|
|
|
self.l = self.g.local_state |
|
|
|
|
|
|
|
|
|
def block_at(self, x, y, z): |
|
|
|
|
return self.g.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 = utils.spiral(n) |
|
|
|
|
check = utils.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_trees(self, center, distance): |
|
|
|
|
logs = [] |
|
|
|
|
for i in range(5): |
|
|
|
|
check = utils.padd(center, alternate(i, 3)) |
|
|
|
|
logs.extend(self.find_blocks(check, distance, blocks.LOG_IDS, 50)) |
|
|
|
|
|
|
|
|
|
trees = [] |
|
|
|
|
for log in logs: |
|
|
|
|
# crawl to the bottom log |
|
|
|
|
while self.block_at(*utils.padd(log, path.BLOCK_BELOW)) in blocks.LOG_IDS: |
|
|
|
|
log = utils.padd(log, path.BLOCK_BELOW) |
|
|
|
|
|
|
|
|
|
# make sure we are on the ground |
|
|
|
|
if self.block_at(*utils.padd(log, path.BLOCK_BELOW)) in blocks.NON_SOLID_IDS: |
|
|
|
|
continue |
|
|
|
|
|
|
|
|
|
# crawl to the top log to count |
|
|
|
|
log_count = 1 |
|
|
|
|
while self.block_at(*utils.padd(log, path.BLOCK_ABOVE)) in blocks.LOG_IDS: |
|
|
|
|
log = utils.padd(log, path.BLOCK_ABOVE) |
|
|
|
|
log_count += 1 |
|
|
|
|
|
|
|
|
|
# make sure it's a good tree |
|
|
|
|
if self.block_at(*utils.padd(log, path.BLOCK_ABOVE)) in blocks.LEAF_IDS and log_count > 2: |
|
|
|
|
# crawl back to the bottom log |
|
|
|
|
while self.block_at(*utils.padd(log, path.BLOCK_BELOW)) in blocks.LOG_IDS: |
|
|
|
|
log = utils.padd(log, path.BLOCK_BELOW) |
|
|
|
|
trees.append(log) |
|
|
|
|
|
|
|
|
|
trees.sort(key=lambda x: phyp(center, x)) |
|
|
|
|
return trees |
|
|
|
|
|
|
|
|
|
def find_tree_openings(self, tree): |
|
|
|
|
# returns coords in a cardinal direction where we can stand by tree |
|
|
|
|
maze_solver = MazeSolver(self.g.chunks) |
|
|
|
|
result = [] |
|
|
|
|
|
|
|
|
|
# TODO: make sure only non-solid and leaves between |
|
|
|
|
# make sure traversable too |
|
|
|
|
|
|
|
|
|
for distance in range(5): |
|
|
|
|
for direction in CHECK_DIRECTIONS: |
|
|
|
|
offset = pmul(direction, distance+1) |
|
|
|
|
if maze_solver.check_traverse(tree, offset): |
|
|
|
|
result.append(utils.padd(tree, offset)) |
|
|
|
|
return result |
|
|
|
|
|
|
|
|
|
def path_to_place(self, start, place): |
|
|
|
|
maze_solver = MazeSolver(self.g.chunks) |
|
|
|
|
|
|
|
|
|
try: |
|
|
|
|
s = maze_solver.astar(start, place) |
|
|
|
|
return list(s) if s else None |
|
|
|
|
except AStarTimeout: |
|
|
|
|
return None |
|
|
|
|
|
|
|
|
|
def find_bed_areas(self, center, distance): |
|
|
|
|
air = [] |
|
|
|
|
for i in range(5): |
|
|
|
|
check = utils.padd(center, alternate(i, 1)) |
|
|
|
|
air.extend(self.find_blocks(check, distance, [0], 200)) |
|
|
|
|
|
|
|
|
|
areas = [] |
|
|
|
|
for a in air: |
|
|
|
|
# check for ground around the area |
|
|
|
|
if len(self.find_blocks(utils.padd(a, path.BLOCK_BELOW), 2, blocks.NON_SOLID_IDS, 9)): |
|
|
|
|
continue |
|
|
|
|
|
|
|
|
|
# check for air around the area |
|
|
|
|
if len(self.find_blocks(a, 2, [0], 9)) < 9: |
|
|
|
|
continue |
|
|
|
|
|
|
|
|
|
# check for air above the area |
|
|
|
|
if len(self.find_blocks(utils.padd(a, path.BLOCK_ABOVE), 2, [0], 9)) < 9: |
|
|
|
|
continue |
|
|
|
|
|
|
|
|
|
areas.append(a) |
|
|
|
|
|
|
|
|
|
areas.sort(key=lambda x: phyp(center, x)) |
|
|
|
|
return areas |
|
|
|
|
|
|
|
|
|
def sand_adjacent_safe(self, sand): |
|
|
|
|
for direction in CHECK_DIRECTIONS: |
|
|
|
|
if self.block_at(*utils.padd(sand, direction)) in blocks.AVOID_IDS: |
|
|
|
|
return False |
|
|
|
|
return True |
|
|
|
|
|
|
|
|
|
def find_sand(self, center, distance, origin): |
|
|
|
|
sand = [] |
|
|
|
|
for i in range(10): |
|
|
|
|
check = utils.padd(center, alternate(i, 1)) |
|
|
|
|
sand.extend(self.find_blocks(check, distance, [66], 20)) |
|
|
|
|
|
|
|
|
|
safe_sand = [] |
|
|
|
|
for s in sand: |
|
|
|
|
# make sure it has solid below |
|
|
|
|
if self.block_at(*utils.padd(s, path.BLOCK_BELOW)) in blocks.NON_SOLID_IDS: |
|
|
|
|
continue |
|
|
|
|
# make sure it has solid two below - prevent hanging sand |
|
|
|
|
if self.block_at(*utils.padd(s, path.BLOCK_BELOW2)) in blocks.NON_SOLID_IDS: |
|
|
|
|
continue |
|
|
|
|
|
|
|
|
|
# and walkable air above |
|
|
|
|
if self.block_at(*utils.padd(s, path.BLOCK_ABOVE)) not in blocks.NON_SOLID_IDS: |
|
|
|
|
continue |
|
|
|
|
|
|
|
|
|
if not self.sand_adjacent_safe(s): |
|
|
|
|
continue |
|
|
|
|
|
|
|
|
|
safe_sand.append(s) |
|
|
|
|
|
|
|
|
|
safe_sand.sort(key=lambda x: utils.phyp_bias(center, x, origin)) |
|
|
|
|
return safe_sand |
|
|
|
|
|
|
|
|
|
def find_bed_openings(self, area): |
|
|
|
|
# returns coords in a cardinal direction where we can stand by bed |
|
|
|
|
result = [] |
|
|
|
|
|
|
|
|
|
for direction in CHECK_DIRECTIONS: |
|
|
|
|
result.append(utils.padd(area, direction)) |
|
|
|
|
return result |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Game: |
|
|
|
|
def __init__(self, global_state): |
|
|
|
|
self.g = global_state |
|
|
|
@ -164,6 +310,17 @@ class Game: |
|
|
|
|
packet.hand = packet.HAND_MAIN |
|
|
|
|
self.g.connection.write_packet(packet) |
|
|
|
|
|
|
|
|
|
def place_block(self, location, face): |
|
|
|
|
packet = serverbound.play.PlayerBlockPlacementPacket() |
|
|
|
|
packet.hand = 0 |
|
|
|
|
packet.location = pos |
|
|
|
|
packet.face = face |
|
|
|
|
packet.x = 0.5 |
|
|
|
|
packet.y = 0.5 |
|
|
|
|
packet.z = 0.5 |
|
|
|
|
packet.inside_block = False |
|
|
|
|
self.g.connection.write_packet(packet) |
|
|
|
|
|
|
|
|
|
def tick(self): |
|
|
|
|
if self.l.breaking: |
|
|
|
|
self.animate() |
|
|
|
|