Move World class into its own file
This commit is contained in:
parent
221d497204
commit
9874e23aa6
|
@ -26,6 +26,7 @@ from munch import Munch
|
|||
|
||||
from mosfet import blocks
|
||||
from mosfet import game
|
||||
from mosfet import world
|
||||
from mosfet import items
|
||||
from mosfet import job
|
||||
from mosfet import mcdata
|
||||
|
@ -264,7 +265,7 @@ def bot(global_state):
|
|||
g.chat = ChatManager(g)
|
||||
|
||||
g.game = game.Game(g)
|
||||
g.world = game.MCWorld(g)
|
||||
g.world = world.World(g)
|
||||
|
||||
try:
|
||||
while not g.pos:
|
||||
|
|
306
mosfet/game.py
306
mosfet/game.py
|
@ -2,11 +2,9 @@ import re
|
|||
import time
|
||||
import importlib
|
||||
import random
|
||||
import functools
|
||||
from math import hypot
|
||||
from itertools import count
|
||||
from munch import Munch
|
||||
from copy import copy
|
||||
|
||||
from minecraft.networking.packets import Packet, clientbound, serverbound
|
||||
from minecraft.networking.types import BlockFace
|
||||
|
@ -34,310 +32,6 @@ from mosfet import mobs
|
|||
from mosfet import bot
|
||||
from mosfet import vector
|
||||
|
||||
class MCWorld:
|
||||
def __init__(self, global_state):
|
||||
self.g = global_state
|
||||
|
||||
def block_at(self, x, y, z):
|
||||
return self.g.chunks.get_block_at(x, y, z)
|
||||
|
||||
def check_air_column(self, pos, distance):
|
||||
for i in range(distance):
|
||||
check = utils.padd(pos, (0, i, 0))
|
||||
if self.block_at(*check) not in blocks.NON_SOLID_IDS:
|
||||
return False
|
||||
return True
|
||||
|
||||
def find_blocks_3d(self, center, block_ids, distance=0, y_limit=0):
|
||||
for offset in utils.search_3d(distance, y_limit):
|
||||
check = utils.padd(center, offset)
|
||||
if self.block_at(*check) in block_ids:
|
||||
yield check
|
||||
|
||||
def find_blocks_indexed(self, center, block_ids, distance=0):
|
||||
print('finding', block_ids)
|
||||
index = []
|
||||
for bid in block_ids:
|
||||
index.extend(self.g.chunks.index.get(bid, []))
|
||||
|
||||
print('index', index)
|
||||
|
||||
result = []
|
||||
for block in index:
|
||||
if self.block_at(*block) not in block_ids:
|
||||
continue
|
||||
if distance and utils.phyp(center, block) > distance:
|
||||
continue
|
||||
if block not in result:
|
||||
result.append(block)
|
||||
|
||||
result.sort(key=lambda x: utils.phyp(center, x))
|
||||
return result
|
||||
|
||||
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):
|
||||
found_trees = []
|
||||
for log in self.find_blocks_3d(center, blocks.LOG_IDS, distance, 15):
|
||||
# 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)
|
||||
base = log
|
||||
|
||||
if base in found_trees:
|
||||
continue
|
||||
|
||||
# make sure we are on the ground
|
||||
if self.block_at(*utils.padd(base, path.BLOCK_BELOW)) in blocks.NON_SOLID_IDS:
|
||||
continue
|
||||
|
||||
# crawl to the top log to count and check leaves
|
||||
log_count = 1
|
||||
good_leaves = False
|
||||
while self.block_at(*utils.padd(log, path.BLOCK_ABOVE)) in blocks.LOG_IDS:
|
||||
log = utils.padd(log, path.BLOCK_ABOVE)
|
||||
log_count += 1
|
||||
|
||||
for offset in path.CHECK_DIRECTIONS:
|
||||
if self.block_at(*utils.padd(log, offset)) in blocks.LEAF_IDS:
|
||||
good_leaves = True
|
||||
|
||||
# make sure it's a good tree
|
||||
if not good_leaves or log_count < 3:
|
||||
continue
|
||||
|
||||
found_trees.append(base)
|
||||
|
||||
yield base
|
||||
|
||||
def find_tree_openings(self, tree):
|
||||
# returns coords in a cardinal direction where we can stand by tree
|
||||
maze_solver = path.Pathfinder(self.g)
|
||||
result = []
|
||||
|
||||
# TODO: make sure only non-solid and leaves between
|
||||
# make sure traversable too and non-avoid
|
||||
|
||||
for distance in range(5):
|
||||
for direction in path.CHECK_DIRECTIONS:
|
||||
offset = utils.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 = path.Pathfinder(self.g)
|
||||
|
||||
try:
|
||||
s = maze_solver.astar(start, place)
|
||||
return list(s) if s else None
|
||||
except path.AStarTimeout:
|
||||
return None
|
||||
|
||||
def find_bed_areas(self, center, distance):
|
||||
bed_clearance = 9 # 5x5 area
|
||||
clear_distance = 2
|
||||
|
||||
for a in self.find_blocks_3d(center, [0], distance, 50):
|
||||
# check for air around the area
|
||||
if len(self.find_blocks(a, clear_distance, [0], bed_clearance)) < bed_clearance:
|
||||
continue
|
||||
|
||||
# check for ground around the area
|
||||
if len(self.find_blocks(utils.padd(a, path.BLOCK_BELOW), clear_distance, blocks.NON_SOLID_IDS, bed_clearance)):
|
||||
continue
|
||||
|
||||
# check for air above the area
|
||||
if len(self.find_blocks(utils.padd(a, path.BLOCK_ABOVE), clear_distance, [0], bed_clearance)) < bed_clearance:
|
||||
continue
|
||||
|
||||
# ensure there's no monsters within 20 blocks
|
||||
# can't sleep if they are within 10, good to have a buffer
|
||||
if self.find_monsters(a, 20):
|
||||
continue
|
||||
|
||||
yield a
|
||||
|
||||
def find_cache_areas(self, center, distance):
|
||||
return self.find_bed_areas(center, distance)
|
||||
|
||||
def sand_adjacent_safe(self, sand):
|
||||
for direction in path.CHECK_DIRECTIONS:
|
||||
if self.block_at(*utils.padd(sand, direction)) in blocks.AVOID_IDS:
|
||||
return False
|
||||
return True
|
||||
|
||||
def find_sand(self, center, distance, player):
|
||||
sand = []
|
||||
sand.extend(self.find_blocks(center, distance, [blocks.SAND], 25))
|
||||
|
||||
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(player, x))
|
||||
return safe_sand
|
||||
|
||||
def check_sand_slice(self, center):
|
||||
# checks if a 5x5x1 slice has sand in it
|
||||
for i in range(9):
|
||||
s = utils.padd(center, utils.spiral(i))
|
||||
if self.block_at(*s) != blocks.SAND:
|
||||
continue
|
||||
# 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
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def find_sand_slice(self, center, distance, y_limit=0, bad_slices=[], prev_layer=0):
|
||||
# returns the centre coord of the next 5x5x1 slice that still has
|
||||
# diggable sand in it. lower slices are only valid if there's an
|
||||
# adjacent slice farther at the same level. this should ensure an
|
||||
# upside down pyramid gets excavated so the edges are still climbable
|
||||
for v in count(prev_layer):
|
||||
peak = utils.padd(center, (0, 10-v, 0))
|
||||
|
||||
slices = []
|
||||
layer = 0
|
||||
for step in count():
|
||||
offset = utils.spiral(step)
|
||||
layer = max(layer, *offset)
|
||||
offset = utils.pmul(offset, 3)
|
||||
check = utils.padd(peak, offset)
|
||||
check = utils.padd(check, (0, layer, 0))
|
||||
|
||||
if y_limit and check[1] - center[1] > y_limit:
|
||||
break
|
||||
if utils.phyp_king(center, check) > distance:
|
||||
break
|
||||
|
||||
if self.check_sand_slice(check) and check not in bad_slices:
|
||||
slices.append(check)
|
||||
|
||||
if len(slices):
|
||||
return v, slices[-1]
|
||||
elif v > 40:
|
||||
return None, None
|
||||
|
||||
|
||||
def find_bed_openings(self, area):
|
||||
# returns coords in a cardinal direction where we can stand by bed
|
||||
result = []
|
||||
|
||||
for direction in path.CHECK_DIRECTIONS:
|
||||
result.append(utils.padd(area, direction))
|
||||
return result
|
||||
|
||||
def find_cache_openings(self, area):
|
||||
return self.find_bed_openings(area)
|
||||
|
||||
def find_objects(self, object_ids):
|
||||
result = []
|
||||
for eid, obj in copy(self.g.objects).items():
|
||||
if obj.get('item_id', None) in object_ids:
|
||||
result.append(obj)
|
||||
return result
|
||||
|
||||
def find_leaves(self, center, distance):
|
||||
for a in self.find_blocks_3d(center, blocks.LEAF_IDS, distance, 10):
|
||||
yield a
|
||||
|
||||
def find_monsters(self, center, distance):
|
||||
# finds monsters within distance
|
||||
result = []
|
||||
for eid, mob in copy(self.g.mobs).items():
|
||||
if mob.type not in mobs.EVIL_IDS:
|
||||
continue
|
||||
pos = utils.pint((mob.x, mob.y, mob.z))
|
||||
if utils.phyp(center, pos) > distance:
|
||||
continue
|
||||
result.append(mob)
|
||||
return result
|
||||
|
||||
def find_threats(self, center, distance):
|
||||
# finds monsters on the surface within distance
|
||||
monsters = self.find_monsters(center, distance)
|
||||
result = []
|
||||
for mob in monsters:
|
||||
pos = utils.pint((mob.x, mob.y, mob.z))
|
||||
# check distance number of blocks above, close enough?
|
||||
if not self.check_air_column(pos, distance):
|
||||
continue
|
||||
result.append(mob)
|
||||
return result
|
||||
|
||||
def find_villagers(self, center, distance):
|
||||
# finds villagers within distance
|
||||
result = []
|
||||
for eid, mob in copy(self.g.mobs).items():
|
||||
type_name = mobs.MOB_NAMES[mob.type]
|
||||
if type_name != 'villager' : continue
|
||||
pos = utils.pint((mob.x, mob.y, mob.z))
|
||||
if utils.phyp(center, pos) > distance:
|
||||
continue
|
||||
result.append(mob)
|
||||
return result
|
||||
|
||||
def find_villager_openings(self, villager):
|
||||
# returns coords in a cardinal direction where we can stand by a villager
|
||||
maze_solver = path.Pathfinder(self.g)
|
||||
result = []
|
||||
|
||||
for distance in range(3):
|
||||
for direction in path.CHECK_DIRECTIONS:
|
||||
offset = utils.pmul(direction, distance+1)
|
||||
|
||||
if not maze_solver.check_traverse(villager, offset):
|
||||
continue
|
||||
|
||||
# check for line of sight
|
||||
for check in range(distance+1):
|
||||
offset2 = utils.pmul(direction, check+1)
|
||||
offset2 = utils.padd(offset2, path.BLOCK_ABOVE)
|
||||
check = utils.padd(villager, offset2)
|
||||
if self.block_at(*check) not in blocks.NON_SOLID_IDS:
|
||||
break
|
||||
else: # for
|
||||
result.append(utils.padd(villager, offset))
|
||||
return result
|
||||
|
||||
|
||||
class Game:
|
||||
def __init__(self, global_state):
|
||||
self.g = global_state
|
||||
|
|
314
mosfet/world.py
Normal file
314
mosfet/world.py
Normal file
|
@ -0,0 +1,314 @@
|
|||
import re
|
||||
import time
|
||||
import random
|
||||
from math import hypot
|
||||
from itertools import count
|
||||
from copy import copy
|
||||
|
||||
from mosfet import utils
|
||||
from mosfet import path
|
||||
from mosfet import blocks
|
||||
from mosfet import mobs
|
||||
|
||||
class World:
|
||||
def __init__(self, global_state):
|
||||
self.g = global_state
|
||||
|
||||
def block_at(self, x, y, z):
|
||||
return self.g.chunks.get_block_at(x, y, z)
|
||||
|
||||
def check_air_column(self, pos, distance):
|
||||
for i in range(distance):
|
||||
check = utils.padd(pos, (0, i, 0))
|
||||
if self.block_at(*check) not in blocks.NON_SOLID_IDS:
|
||||
return False
|
||||
return True
|
||||
|
||||
def find_blocks_3d(self, center, block_ids, distance=0, y_limit=0):
|
||||
for offset in utils.search_3d(distance, y_limit):
|
||||
check = utils.padd(center, offset)
|
||||
if self.block_at(*check) in block_ids:
|
||||
yield check
|
||||
|
||||
def find_blocks_indexed(self, center, block_ids, distance=0):
|
||||
print('finding', block_ids)
|
||||
index = []
|
||||
for bid in block_ids:
|
||||
index.extend(self.g.chunks.index.get(bid, []))
|
||||
|
||||
print('index', index)
|
||||
|
||||
result = []
|
||||
for block in index:
|
||||
if self.block_at(*block) not in block_ids:
|
||||
continue
|
||||
if distance and utils.phyp(center, block) > distance:
|
||||
continue
|
||||
if block not in result:
|
||||
result.append(block)
|
||||
|
||||
result.sort(key=lambda x: utils.phyp(center, x))
|
||||
return result
|
||||
|
||||
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):
|
||||
found_trees = []
|
||||
for log in self.find_blocks_3d(center, blocks.LOG_IDS, distance, 15):
|
||||
# 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)
|
||||
base = log
|
||||
|
||||
if base in found_trees:
|
||||
continue
|
||||
|
||||
# make sure we are on the ground
|
||||
if self.block_at(*utils.padd(base, path.BLOCK_BELOW)) in blocks.NON_SOLID_IDS:
|
||||
continue
|
||||
|
||||
# crawl to the top log to count and check leaves
|
||||
log_count = 1
|
||||
good_leaves = False
|
||||
while self.block_at(*utils.padd(log, path.BLOCK_ABOVE)) in blocks.LOG_IDS:
|
||||
log = utils.padd(log, path.BLOCK_ABOVE)
|
||||
log_count += 1
|
||||
|
||||
for offset in path.CHECK_DIRECTIONS:
|
||||
if self.block_at(*utils.padd(log, offset)) in blocks.LEAF_IDS:
|
||||
good_leaves = True
|
||||
|
||||
# make sure it's a good tree
|
||||
if not good_leaves or log_count < 3:
|
||||
continue
|
||||
|
||||
found_trees.append(base)
|
||||
|
||||
yield base
|
||||
|
||||
def find_tree_openings(self, tree):
|
||||
# returns coords in a cardinal direction where we can stand by tree
|
||||
maze_solver = path.Pathfinder(self.g)
|
||||
result = []
|
||||
|
||||
# TODO: make sure only non-solid and leaves between
|
||||
# make sure traversable too and non-avoid
|
||||
|
||||
for distance in range(5):
|
||||
for direction in path.CHECK_DIRECTIONS:
|
||||
offset = utils.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 = path.Pathfinder(self.g)
|
||||
|
||||
try:
|
||||
s = maze_solver.astar(start, place)
|
||||
return list(s) if s else None
|
||||
except path.AStarTimeout:
|
||||
return None
|
||||
|
||||
def find_bed_areas(self, center, distance):
|
||||
bed_clearance = 9 # 5x5 area
|
||||
clear_distance = 2
|
||||
|
||||
for a in self.find_blocks_3d(center, [0], distance, 50):
|
||||
# check for air around the area
|
||||
if len(self.find_blocks(a, clear_distance, [0], bed_clearance)) < bed_clearance:
|
||||
continue
|
||||
|
||||
# check for ground around the area
|
||||
if len(self.find_blocks(utils.padd(a, path.BLOCK_BELOW), clear_distance, blocks.NON_SOLID_IDS, bed_clearance)):
|
||||
continue
|
||||
|
||||
# check for air above the area
|
||||
if len(self.find_blocks(utils.padd(a, path.BLOCK_ABOVE), clear_distance, [0], bed_clearance)) < bed_clearance:
|
||||
continue
|
||||
|
||||
# ensure there's no monsters within 20 blocks
|
||||
# can't sleep if they are within 10, good to have a buffer
|
||||
if self.find_monsters(a, 20):
|
||||
continue
|
||||
|
||||
yield a
|
||||
|
||||
def find_cache_areas(self, center, distance):
|
||||
return self.find_bed_areas(center, distance)
|
||||
|
||||
def sand_adjacent_safe(self, sand):
|
||||
for direction in path.CHECK_DIRECTIONS:
|
||||
if self.block_at(*utils.padd(sand, direction)) in blocks.AVOID_IDS:
|
||||
return False
|
||||
return True
|
||||
|
||||
def find_sand(self, center, distance, player):
|
||||
sand = []
|
||||
sand.extend(self.find_blocks(center, distance, [blocks.SAND], 25))
|
||||
|
||||
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(player, x))
|
||||
return safe_sand
|
||||
|
||||
def check_sand_slice(self, center):
|
||||
# checks if a 5x5x1 slice has sand in it
|
||||
for i in range(9):
|
||||
s = utils.padd(center, utils.spiral(i))
|
||||
if self.block_at(*s) != blocks.SAND:
|
||||
continue
|
||||
# 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
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def find_sand_slice(self, center, distance, y_limit=0, bad_slices=[], prev_layer=0):
|
||||
# returns the centre coord of the next 5x5x1 slice that still has
|
||||
# diggable sand in it. lower slices are only valid if there's an
|
||||
# adjacent slice farther at the same level. this should ensure an
|
||||
# upside down pyramid gets excavated so the edges are still climbable
|
||||
for v in count(prev_layer):
|
||||
peak = utils.padd(center, (0, 10-v, 0))
|
||||
|
||||
slices = []
|
||||
layer = 0
|
||||
for step in count():
|
||||
offset = utils.spiral(step)
|
||||
layer = max(layer, *offset)
|
||||
offset = utils.pmul(offset, 3)
|
||||
check = utils.padd(peak, offset)
|
||||
check = utils.padd(check, (0, layer, 0))
|
||||
|
||||
if y_limit and check[1] - center[1] > y_limit:
|
||||
break
|
||||
if utils.phyp_king(center, check) > distance:
|
||||
break
|
||||
|
||||
if self.check_sand_slice(check) and check not in bad_slices:
|
||||
slices.append(check)
|
||||
|
||||
if len(slices):
|
||||
return v, slices[-1]
|
||||
elif v > 40:
|
||||
return None, None
|
||||
|
||||
|
||||
def find_bed_openings(self, area):
|
||||
# returns coords in a cardinal direction where we can stand by bed
|
||||
result = []
|
||||
|
||||
for direction in path.CHECK_DIRECTIONS:
|
||||
result.append(utils.padd(area, direction))
|
||||
return result
|
||||
|
||||
def find_cache_openings(self, area):
|
||||
return self.find_bed_openings(area)
|
||||
|
||||
def find_objects(self, object_ids):
|
||||
result = []
|
||||
for eid, obj in copy(self.g.objects).items():
|
||||
if obj.get('item_id', None) in object_ids:
|
||||
result.append(obj)
|
||||
return result
|
||||
|
||||
def find_leaves(self, center, distance):
|
||||
for a in self.find_blocks_3d(center, blocks.LEAF_IDS, distance, 10):
|
||||
yield a
|
||||
|
||||
def find_monsters(self, center, distance):
|
||||
# finds monsters within distance
|
||||
result = []
|
||||
for eid, mob in copy(self.g.mobs).items():
|
||||
if mob.type not in mobs.EVIL_IDS:
|
||||
continue
|
||||
pos = utils.pint((mob.x, mob.y, mob.z))
|
||||
if utils.phyp(center, pos) > distance:
|
||||
continue
|
||||
result.append(mob)
|
||||
return result
|
||||
|
||||
def find_threats(self, center, distance):
|
||||
# finds monsters on the surface within distance
|
||||
monsters = self.find_monsters(center, distance)
|
||||
result = []
|
||||
for mob in monsters:
|
||||
pos = utils.pint((mob.x, mob.y, mob.z))
|
||||
# check distance number of blocks above, close enough?
|
||||
if not self.check_air_column(pos, distance):
|
||||
continue
|
||||
result.append(mob)
|
||||
return result
|
||||
|
||||
def find_villagers(self, center, distance):
|
||||
# finds villagers within distance
|
||||
result = []
|
||||
for eid, mob in copy(self.g.mobs).items():
|
||||
type_name = mobs.MOB_NAMES[mob.type]
|
||||
if type_name != 'villager' : continue
|
||||
pos = utils.pint((mob.x, mob.y, mob.z))
|
||||
if utils.phyp(center, pos) > distance:
|
||||
continue
|
||||
result.append(mob)
|
||||
return result
|
||||
|
||||
def find_villager_openings(self, villager):
|
||||
# returns coords in a cardinal direction where we can stand by a villager
|
||||
maze_solver = path.Pathfinder(self.g)
|
||||
result = []
|
||||
|
||||
for distance in range(3):
|
||||
for direction in path.CHECK_DIRECTIONS:
|
||||
offset = utils.pmul(direction, distance+1)
|
||||
|
||||
if not maze_solver.check_traverse(villager, offset):
|
||||
continue
|
||||
|
||||
# check for line of sight
|
||||
for check in range(distance+1):
|
||||
offset2 = utils.pmul(direction, check+1)
|
||||
offset2 = utils.padd(offset2, path.BLOCK_ABOVE)
|
||||
check = utils.padd(villager, offset2)
|
||||
if self.block_at(*check) not in blocks.NON_SOLID_IDS:
|
||||
break
|
||||
else: # for
|
||||
result.append(utils.padd(villager, offset))
|
||||
return result
|
Loading…
Reference in New Issue
Block a user