Add 3D BFS iterator
This commit is contained in:
parent
6c4aaf8d7d
commit
0bbe516818
12
blocks.py
12
blocks.py
|
@ -59,6 +59,12 @@ AVOID = [
|
|||
'sandstone_wall',
|
||||
'end_stone_brick_wall',
|
||||
'diorite_wall',
|
||||
'oak_sapling', # saplings can grow up and hurt
|
||||
'spruce_sapling',
|
||||
'birch_sapling',
|
||||
'jungle_sapling',
|
||||
'acacia_sapling',
|
||||
'dark_oak_sapling',
|
||||
]
|
||||
|
||||
NON_SOLID = [
|
||||
|
@ -194,12 +200,6 @@ NON_SOLID = [
|
|||
'cave_air',
|
||||
'lantern',
|
||||
'soul_torch',
|
||||
#'oak_sapling', # saplings can grow up and hurt
|
||||
#'spruce_sapling',
|
||||
#'birch_sapling',
|
||||
#'jungle_sapling',
|
||||
#'acacia_sapling',
|
||||
#'dark_oak_sapling',
|
||||
]
|
||||
|
||||
LOGS = [
|
||||
|
|
49
game.py
49
game.py
|
@ -41,6 +41,12 @@ class MCWorld:
|
|||
def block_at(self, x, y, z):
|
||||
return self.g.chunks.get_block_at(x, y, z)
|
||||
|
||||
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(self, center, distance, block_ids, limit=0):
|
||||
# search in a spiral from center to all blocks with ID
|
||||
result = []
|
||||
|
@ -112,16 +118,10 @@ class MCWorld:
|
|||
return None
|
||||
|
||||
def find_bed_areas(self, center, distance):
|
||||
air = []
|
||||
for i in range(5):
|
||||
check = utils.padd(center, utils.alternate(i, 1))
|
||||
air.extend(self.find_blocks(check, distance, [0], 0))
|
||||
|
||||
bed_clearance = 25 # 5x5 area
|
||||
clear_distance = 3
|
||||
|
||||
areas = []
|
||||
for a in air:
|
||||
for a in self.find_blocks_3d(center, [0], distance, 10):
|
||||
# check for air around the area
|
||||
if len(self.find_blocks(a, clear_distance, [0], bed_clearance)) < bed_clearance:
|
||||
continue
|
||||
|
@ -134,10 +134,7 @@ class MCWorld:
|
|||
if len(self.find_blocks(utils.padd(a, path.BLOCK_ABOVE), clear_distance, [0], bed_clearance)) < bed_clearance:
|
||||
continue
|
||||
|
||||
areas.append(a)
|
||||
|
||||
areas.sort(key=lambda x: utils.phyp(center, x))
|
||||
return areas
|
||||
yield a
|
||||
|
||||
def find_cache_areas(self, center, distance):
|
||||
return self.find_bed_areas(center, distance)
|
||||
|
@ -264,15 +261,19 @@ class Game:
|
|||
def handle_chat(self, message):
|
||||
source, text = message
|
||||
reply = None
|
||||
private = False
|
||||
|
||||
if source == 'SYSTEM':
|
||||
print('unlocking command...')
|
||||
self.g.command_lock = False
|
||||
return
|
||||
|
||||
match = re.match(r'<(\w+)> (.*)', text)
|
||||
if match:
|
||||
sender, text = match.groups()
|
||||
match1 = re.match(r'<(\w+)> (.*)', text)
|
||||
match2 = re.match(r'\[(\w+) -> me] (.*)', text)
|
||||
if match1:
|
||||
sender, text = match1.groups()
|
||||
elif match2:
|
||||
sender, text = match2.groups()
|
||||
private = True
|
||||
else:
|
||||
return
|
||||
|
||||
|
@ -350,15 +351,12 @@ class Game:
|
|||
reply = 'ok'
|
||||
|
||||
if command == 'inv':
|
||||
print(self.g.inv)
|
||||
inv_list = []
|
||||
for i in self.g.inv.values():
|
||||
if i.present:
|
||||
inv_list.append('{}:{} x {}'.format(items.ITEM_NAMES[i.item_id], str(i.item_id), i.item_count))
|
||||
reply = ', '.join(inv_list)
|
||||
|
||||
if not reply:
|
||||
reply = 'empty'
|
||||
result = '\n'.join(inv_list)
|
||||
print(result or 'Empty')
|
||||
|
||||
if command == 'drop':
|
||||
self.drop_stack()
|
||||
|
@ -416,9 +414,16 @@ class Game:
|
|||
if data and v.item_id != int(data): continue
|
||||
print(str(k) + ':', v)
|
||||
|
||||
if command == 'cache':
|
||||
self.g.job.state = self.g.job.cache_items
|
||||
reply = 'ok'
|
||||
|
||||
if reply:
|
||||
print(reply)
|
||||
self.g.chat.send(reply)
|
||||
if private and not reply.startswith('/'):
|
||||
self.g.chat.send('/m ' + sender + ' ' + reply)
|
||||
else:
|
||||
self.g.chat.send(reply)
|
||||
|
||||
def handle_time_update(self, packet):
|
||||
self.g.time = packet.time_of_day % 24000
|
||||
|
@ -578,7 +583,7 @@ class Game:
|
|||
def handle_spawn_object(self, packet):
|
||||
#return
|
||||
if packet.type_id != 37: return
|
||||
print(packet)
|
||||
#print(packet)
|
||||
self.g.objects[packet.entity_id] = Munch(
|
||||
entity_id=packet.entity_id,
|
||||
x=packet.x,
|
||||
|
|
3
items.py
3
items.py
|
@ -47,4 +47,5 @@ CHEST_ID = set([ITEMS['minecraft:chest']['protocol_id']])
|
|||
|
||||
GAPPLE_ID = set([ITEMS['minecraft:enchanted_golden_apple']['protocol_id']])
|
||||
|
||||
USEFUL_ITEMS = BED_IDS | CHEST_ID
|
||||
NEEDED_ITEMS = BED_IDS | CHEST_ID
|
||||
WANTED_ITEMS = SAPLING_IDS
|
||||
|
|
101
jobs.py
101
jobs.py
|
@ -385,20 +385,16 @@ class SleepWithBedStates:
|
|||
w = self.g.world
|
||||
p = utils.pint(self.g.pos)
|
||||
|
||||
areas = w.find_bed_areas(p, 100)
|
||||
print('Found areas:', areas)
|
||||
|
||||
if len(areas):
|
||||
while areas[0] in self.bad_areas:
|
||||
areas.pop(0)
|
||||
self.area = areas[0]
|
||||
elif self.last_area:
|
||||
self.area = self.last_area
|
||||
else:
|
||||
print('Unable to find area, and no last area')
|
||||
for area in w.find_bed_areas(p, 100):
|
||||
print('Found area:', area)
|
||||
if area not in self.bad_areas:
|
||||
break
|
||||
else: # for
|
||||
print('Unable to find area')
|
||||
self.state = self.cleanup
|
||||
return
|
||||
|
||||
self.area = area
|
||||
openings = w.find_bed_openings(self.area)
|
||||
|
||||
for o in openings:
|
||||
|
@ -413,7 +409,6 @@ class SleepWithBedStates:
|
|||
|
||||
self.g.path = navpath
|
||||
self.state = self.going_to_area
|
||||
self.last_area = self.area
|
||||
|
||||
def going_to_area(self):
|
||||
if utils.pint(self.g.pos) == self.opening:
|
||||
|
@ -479,7 +474,6 @@ class SleepWithBedStates:
|
|||
self.area = None
|
||||
self.opening = None
|
||||
self.bad_areas = []
|
||||
self.last_area = None
|
||||
self.wait_time = 0
|
||||
|
||||
def run(self):
|
||||
|
@ -491,8 +485,11 @@ class CacheItemsStates:
|
|||
return None
|
||||
|
||||
def init(self):
|
||||
self.skip_slots = []
|
||||
self.skip_items = []
|
||||
|
||||
num_stacks = len([x for x in self.g.inv.values() if x.present])
|
||||
print('inventory amount:', num_stacks)
|
||||
print('Inventory amount:', num_stacks)
|
||||
if num_stacks >= 27:
|
||||
self.state = self.find_cache_spot
|
||||
else:
|
||||
|
@ -504,20 +501,16 @@ class CacheItemsStates:
|
|||
w = self.g.world
|
||||
p = utils.pint(self.g.pos)
|
||||
|
||||
areas = w.find_cache_areas(p, 100)
|
||||
print('Found areas:', areas)
|
||||
|
||||
if len(areas):
|
||||
while areas[0] in self.bad_areas:
|
||||
areas.pop(0)
|
||||
self.area = areas[0]
|
||||
elif self.last_area:
|
||||
self.area = self.last_area
|
||||
else:
|
||||
print('Unable to find area, and no last area')
|
||||
for area in w.find_cache_areas(p, 100):
|
||||
print('Found area:', area)
|
||||
if area not in self.bad_areas:
|
||||
break
|
||||
else: # for
|
||||
print('Unable to find area')
|
||||
self.state = self.cleanup
|
||||
return
|
||||
|
||||
self.area = area
|
||||
openings = w.find_cache_openings(self.area)
|
||||
|
||||
for o in openings:
|
||||
|
@ -532,7 +525,6 @@ class CacheItemsStates:
|
|||
|
||||
self.g.path = navpath
|
||||
self.state = self.going_to_area
|
||||
self.last_area = self.area
|
||||
|
||||
def going_to_area(self):
|
||||
if utils.pint(self.g.pos) == self.opening:
|
||||
|
@ -571,6 +563,8 @@ class CacheItemsStates:
|
|||
w_info = data.WINDOWS[w.data.window_type]
|
||||
w_inventory_slots = w_info.inventory
|
||||
|
||||
slot_list = []
|
||||
|
||||
for slot_num in w_inventory_slots:
|
||||
if slot_num not in w.contents:
|
||||
continue
|
||||
|
@ -580,14 +574,25 @@ class CacheItemsStates:
|
|||
if not slot.present:
|
||||
continue
|
||||
|
||||
if slot.item_id in items.USEFUL_ITEMS:
|
||||
if slot.item_id in self.needed_items:
|
||||
continue
|
||||
|
||||
if slot_num in self.skip_slots:
|
||||
continue
|
||||
|
||||
slot_list.append((slot_num, slot))
|
||||
|
||||
slot_list.sort(key=lambda x: x[1].item_count, reverse=True)
|
||||
|
||||
for slot_num, slot in slot_list:
|
||||
if slot.item_id in self.wanted_items and slot.item_id not in self.skip_items:
|
||||
print('skipping wanted item', slot)
|
||||
self.skip_slots.append(slot_num)
|
||||
self.skip_items.append(slot.item_id)
|
||||
continue
|
||||
|
||||
print('moving', slot)
|
||||
|
||||
#inv_slot_num = slot_num - w_info.slot_diff
|
||||
#self.g.inv.pop(inv_slot_num, None)
|
||||
|
||||
self.g.item_lock = True
|
||||
self.g.game.click_window(slot_num, 0, 1, slot)
|
||||
return
|
||||
|
@ -613,10 +618,17 @@ class CacheItemsStates:
|
|||
self.g = global_state
|
||||
self.state = self.idle
|
||||
|
||||
# keep all needed items
|
||||
self.needed_items = items.NEEDED_ITEMS
|
||||
# keep one stack of wanted items
|
||||
self.wanted_items = items.WANTED_ITEMS
|
||||
|
||||
self.skip_slots = []
|
||||
self.skip_items = []
|
||||
|
||||
self.area = None
|
||||
self.opening = None
|
||||
self.bad_areas = []
|
||||
self.last_area = None
|
||||
self.wait_time = 0
|
||||
|
||||
def run(self):
|
||||
|
@ -681,19 +693,16 @@ class PlantTreeStates:
|
|||
w = self.g.world
|
||||
p = utils.pint(self.g.pos)
|
||||
|
||||
areas = w.find_cache_areas(p, 20)
|
||||
print('Found areas:', areas)
|
||||
|
||||
try:
|
||||
while areas[0] in self.bad_areas:
|
||||
areas.pop(0)
|
||||
self.area = areas[0]
|
||||
except IndexError:
|
||||
print('No good areas left, aborting.')
|
||||
self.bad_areas = []
|
||||
for area in w.find_cache_areas(p, 20):
|
||||
print('Found area:', area)
|
||||
if area not in self.bad_areas:
|
||||
break
|
||||
else: # for
|
||||
print('Unable to find area')
|
||||
self.state = self.cleanup
|
||||
return
|
||||
|
||||
self.area = area
|
||||
navpath = w.path_to_place(p, self.area)
|
||||
|
||||
if not navpath:
|
||||
|
@ -803,6 +812,16 @@ class JobStates:
|
|||
def idle(self):
|
||||
return None
|
||||
|
||||
def cache_items(self):
|
||||
s1 = self.cache_items_states
|
||||
|
||||
if s1.state == s1.idle:
|
||||
s1.state = s1.init
|
||||
elif s1.state == s1.done:
|
||||
self.state = self.idle
|
||||
|
||||
s1.run()
|
||||
|
||||
def find_gapple(self):
|
||||
s1 = self.find_gapple_states
|
||||
|
||||
|
|
48
utils.py
48
utils.py
|
@ -1,4 +1,5 @@
|
|||
import importlib
|
||||
import collections
|
||||
from math import floor, ceil, sqrt, hypot
|
||||
|
||||
import blocks
|
||||
|
@ -94,3 +95,50 @@ def break_time(block_id, held_item=0, in_water=False, on_ground=True, enchantmen
|
|||
if not on_ground: time *= 5.0
|
||||
|
||||
return time
|
||||
|
||||
def search_3d(distance=0, y_limit=0):
|
||||
def get_neighbors(x,y,z):
|
||||
return [
|
||||
(x+1, y+1, z+0),
|
||||
(x+1, y-1, z+0),
|
||||
(x+1, y+1, z+1),
|
||||
(x+1, y+0, z+1),
|
||||
(x+1, y-1, z+1),
|
||||
(x+1, y+1, z-1),
|
||||
(x+1, y+0, z-1),
|
||||
(x+1, y-1, z-1),
|
||||
(x+1, y+0, z+0),
|
||||
(x+0, y+1, z+0),
|
||||
(x+0, y-1, z+0),
|
||||
(x+0, y+1, z+1),
|
||||
(x+0, y+0, z+1),
|
||||
(x+0, y-1, z+1),
|
||||
(x+0, y+1, z-1),
|
||||
(x+0, y+0, z-1),
|
||||
(x+0, y-1, z-1),
|
||||
(x-1, y+1, z+0),
|
||||
(x-1, y-1, z+0),
|
||||
(x-1, y+1, z+1),
|
||||
(x-1, y+0, z+1),
|
||||
(x-1, y-1, z+1),
|
||||
(x-1, y+1, z-1),
|
||||
(x-1, y+0, z-1),
|
||||
(x-1, y-1, z-1),
|
||||
(x-1, y+0, z+0),
|
||||
]
|
||||
|
||||
to_visit = collections.deque([(0, 0, 0)])
|
||||
visited = set()
|
||||
|
||||
while to_visit:
|
||||
cur = to_visit.pop()
|
||||
if cur in visited:
|
||||
continue
|
||||
if y_limit and abs(cur[1]) > y_limit:
|
||||
continue
|
||||
if distance and hypot(*cur) > distance:
|
||||
continue
|
||||
for neighbor in get_neighbors(*cur):
|
||||
to_visit.appendleft(neighbor)
|
||||
visited.add(cur)
|
||||
yield cur
|
||||
|
|
Loading…
Reference in New Issue
Block a user