Add sign-labeled chest storage
This commit is contained in:
@@ -83,6 +83,25 @@ EMERALD_ID = get_id('emerald')
|
||||
BERRIES_ID = get_id('sweet_berries')
|
||||
IRON_INGOT_ID = get_id('iron_ingot')
|
||||
|
||||
|
||||
_LABEL_ITEM_IDS = {
|
||||
'seeds': get_set({
|
||||
'beetroot', 'beetroot_seeds', 'carrot', 'melon_seeds',
|
||||
'nether_wart', 'pitcher_pod', 'potato', 'pumpkin_seeds',
|
||||
'torchflower_seeds', 'wheat_seeds',
|
||||
}),
|
||||
'wheat': {WHEAT_ID},
|
||||
}
|
||||
|
||||
|
||||
def storage_item_ids_for_label(label):
|
||||
"""Return protocol item IDs assigned to a sign storage label."""
|
||||
normalized = ' '.join(str(label).casefold().split()).strip(' :')
|
||||
normalized = (normalized.rstrip('s')
|
||||
if normalized not in ('seeds', 'beds') else normalized)
|
||||
return set(_LABEL_ITEM_IDS.get(normalized, ()))
|
||||
|
||||
|
||||
INIT_NEEDED_ITEMS = BED_IDS | FOOD_IDS
|
||||
INIT_NEEDED_ITEMS.add(CHEST_ID)
|
||||
NEEDED_ITEMS = INIT_NEEDED_ITEMS
|
||||
|
||||
@@ -22,6 +22,8 @@ class CacheItemsStates:
|
||||
def init(self):
|
||||
self.skip_slots = []
|
||||
self.skip_items = []
|
||||
self.is_labeled_container = False
|
||||
self.container_item_ids = None
|
||||
|
||||
num_stacks = self.g.game.count_inventory_slots()
|
||||
minimum = getattr(
|
||||
@@ -36,25 +38,54 @@ class CacheItemsStates:
|
||||
self.state = self.cleanup
|
||||
|
||||
def find_trapped_chests(self):
|
||||
print('Finding trapped chests...')
|
||||
print('Finding labeled and trapped chests...')
|
||||
w = self.g.world
|
||||
p = utils.pint(self.g.pos)
|
||||
|
||||
self.labeled_chests = w.find_labeled_chests(p, 80)
|
||||
self.checked_labeled_chests = set()
|
||||
self.trapped_chests = w.find_blocks_indexed(p, blocks.TRAPPED_CHEST_IDS)
|
||||
print('Found:', self.trapped_chests)
|
||||
print('Found labeled chests:', len(self.labeled_chests),
|
||||
'trapped chests:', self.trapped_chests)
|
||||
self.state = self.choose_trapped_chest
|
||||
|
||||
def choose_trapped_chest(self):
|
||||
print('Choosing a trapped chest...')
|
||||
print('Choosing a labeled or trapped chest...')
|
||||
w = self.g.world
|
||||
p = utils.pint(self.g.pos)
|
||||
c = self.g.chunks
|
||||
|
||||
for container in self.labeled_chests:
|
||||
key = container['positions']
|
||||
if key in self.checked_labeled_chests:
|
||||
continue
|
||||
self.checked_labeled_chests.add(key)
|
||||
if not any(item.present and item.item_id in container['item_ids']
|
||||
for item in self.g.inv.values()):
|
||||
continue
|
||||
|
||||
self.area = container['position']
|
||||
self.container_item_ids = container['item_ids']
|
||||
self.is_labeled_container = True
|
||||
for opening in w.find_cache_openings(self.area):
|
||||
navpath = w.path_to_place(p, opening)
|
||||
if navpath:
|
||||
print('Going to labeled chest', container['labels'],
|
||||
self.area)
|
||||
self.opening = opening
|
||||
self.g.path = navpath
|
||||
self.state = self.going_to_trapped_chest
|
||||
return
|
||||
print('No path to labeled chest', self.area)
|
||||
|
||||
if not len(self.trapped_chests):
|
||||
print('No trapped chests')
|
||||
self.is_labeled_container = False
|
||||
self.container_item_ids = None
|
||||
print('No labeled or trapped chests')
|
||||
self.state = self.select_chest
|
||||
return
|
||||
|
||||
self.is_labeled_container = False
|
||||
self.container_item_ids = None
|
||||
chest = self.trapped_chests[0]
|
||||
self.area = chest
|
||||
|
||||
@@ -83,6 +114,8 @@ class CacheItemsStates:
|
||||
self.state = self.open_chest
|
||||
|
||||
def select_chest(self):
|
||||
self.is_labeled_container = False
|
||||
self.container_item_ids = None
|
||||
if self.g.game.select_item([items.CHEST_ID]):
|
||||
self.state = self.find_cache_spot
|
||||
else:
|
||||
@@ -149,6 +182,41 @@ class CacheItemsStates:
|
||||
else:
|
||||
self.state = self.move_items
|
||||
|
||||
def _needed_inventory_slots_to_keep(self):
|
||||
needed = set(items.NEEDED_ITEMS)
|
||||
groups = (
|
||||
items.BED_IDS, {items.CHEST_ID}, items.FOOD_IDS,
|
||||
items.AXE_IDS, items.SHOVEL_IDS,
|
||||
)
|
||||
keep = set()
|
||||
covered = set()
|
||||
for group in groups:
|
||||
group = needed.intersection(group)
|
||||
if not group:
|
||||
continue
|
||||
covered.update(group)
|
||||
stacks = [(slot, item) for slot, item in self.g.inv.items()
|
||||
if 5 <= slot <= 45 and item.present and
|
||||
item.item_id in group]
|
||||
if stacks:
|
||||
keep.add(max(stacks, key=lambda pair: pair[1].item_count)[0])
|
||||
|
||||
for item_id in needed - covered:
|
||||
stacks = [(slot, item) for slot, item in self.g.inv.items()
|
||||
if 5 <= slot <= 45 and item.present and
|
||||
item.item_id == item_id]
|
||||
if stacks:
|
||||
keep.add(max(stacks, key=lambda pair: pair[1].item_count)[0])
|
||||
return keep
|
||||
|
||||
def _window_player_slot(self, window_slot):
|
||||
offset = window_slot - self.g.window.container_slots
|
||||
if 0 <= offset < 27:
|
||||
return 9 + offset
|
||||
if 27 <= offset < 36:
|
||||
return 36 + offset - 27
|
||||
return None
|
||||
|
||||
def move_items(self):
|
||||
if self.g.item_lock: return
|
||||
w = self.g.window
|
||||
@@ -177,10 +245,13 @@ class CacheItemsStates:
|
||||
print('Container is too full, aborting')
|
||||
self.g.game.close_window()
|
||||
self.g.look_at = None
|
||||
self.state = self.cleanup
|
||||
self.state = (self.close_chest if self.is_labeled_container
|
||||
else self.cleanup)
|
||||
return
|
||||
|
||||
slot_list = []
|
||||
needed_slots = (self._needed_inventory_slots_to_keep()
|
||||
if self.is_labeled_container else set())
|
||||
|
||||
for slot_num in w_inventory_slots:
|
||||
if slot_num not in w.contents:
|
||||
@@ -191,7 +262,14 @@ class CacheItemsStates:
|
||||
if not slot.present:
|
||||
continue
|
||||
|
||||
if slot.item_id in items.NEEDED_ITEMS:
|
||||
if self.is_labeled_container:
|
||||
if slot.item_id not in self.container_item_ids:
|
||||
continue
|
||||
inventory_slot = self._window_player_slot(slot_num)
|
||||
if (slot.item_id in items.NEEDED_ITEMS and
|
||||
inventory_slot in needed_slots):
|
||||
continue
|
||||
elif slot.item_id in items.NEEDED_ITEMS:
|
||||
continue
|
||||
|
||||
if slot_num in self.skip_slots:
|
||||
@@ -222,6 +300,11 @@ class CacheItemsStates:
|
||||
self.g.game.close_window()
|
||||
if not self.silent:
|
||||
self.g.chat.send('cache at ' + str(self.area)[1:-1])
|
||||
if self.is_labeled_container:
|
||||
self.is_labeled_container = False
|
||||
self.container_item_ids = None
|
||||
self.state = self.choose_trapped_chest
|
||||
else:
|
||||
self.state = self.cleanup
|
||||
|
||||
def cleanup(self):
|
||||
@@ -244,6 +327,10 @@ class CacheItemsStates:
|
||||
self.skip_slots = []
|
||||
self.skip_items = []
|
||||
|
||||
self.labeled_chests = []
|
||||
self.checked_labeled_chests = set()
|
||||
self.is_labeled_container = False
|
||||
self.container_item_ids = None
|
||||
self.area = None
|
||||
self.opening = None
|
||||
self.trapped_chests = []
|
||||
|
||||
@@ -30,7 +30,7 @@ class GrabSuppliesStates:
|
||||
|
||||
def init(self):
|
||||
print('Started grab supplies states')
|
||||
self.checked_barrels = []
|
||||
self.checked_supply_chests = set()
|
||||
|
||||
used_slots = self.g.game.count_inventory_slots()
|
||||
print('used:', used_slots, 'total:', self.g.maximum_supply_slots)
|
||||
@@ -41,6 +41,7 @@ class GrabSuppliesStates:
|
||||
|
||||
self.checked_ground_items = set()
|
||||
self.checked_ground_groups = set()
|
||||
self.checked_supply_chests = set()
|
||||
self.ground_stack_counts = {}
|
||||
self.ground_entity_id = None
|
||||
self.ground_position = None
|
||||
@@ -78,8 +79,8 @@ class GrabSuppliesStates:
|
||||
self.ground_position = None
|
||||
|
||||
def check_supplies(self):
|
||||
# Search every configured item group on the ground before going to a
|
||||
# barrel; a missing bed must not hide a nearby chest or food drop.
|
||||
# Search every configured item group on the ground before looking in
|
||||
# labeled chests; a missing bed must not hide a nearby chest or food drop.
|
||||
missing = []
|
||||
for item_ids, limits in self.supplies.items():
|
||||
minimum, maximum = limits
|
||||
@@ -110,9 +111,9 @@ class GrabSuppliesStates:
|
||||
|
||||
if missing:
|
||||
self.target_items, self.target_minimum, self.target_maximum_stacks = missing[0]
|
||||
print('No more ground drops; checking barrels for',
|
||||
print('No more ground drops; checking supply-labeled chests for',
|
||||
self.target_items)
|
||||
self.state = self.find_barrels
|
||||
self.state = self.find_supply_chests
|
||||
return
|
||||
|
||||
print('Aborting, dont need any supplies')
|
||||
@@ -122,6 +123,10 @@ class GrabSuppliesStates:
|
||||
stack_count = self.ground_stack_counts.get(self.target_items, 0)
|
||||
if self.target_maximum_stacks and stack_count >= self.target_maximum_stacks:
|
||||
self.checked_ground_groups.add(self.target_items)
|
||||
if (self.g.game.count_items(self.target_items) <
|
||||
self.target_minimum):
|
||||
self.state = self.find_supply_chests
|
||||
else:
|
||||
self.state = self.check_supplies
|
||||
return
|
||||
|
||||
@@ -199,60 +204,52 @@ class GrabSuppliesStates:
|
||||
self.ground_position = None
|
||||
self.state = self.find_ground_items
|
||||
|
||||
def find_barrels(self):
|
||||
print('Finding barrels...')
|
||||
w = self.g.world
|
||||
def find_supply_chests(self):
|
||||
print('Finding chests labeled for this bot\'s supplies...')
|
||||
p = utils.pint(self.g.pos)
|
||||
self.supply_chests = self.g.world.find_supply_chests(
|
||||
p, self.g.name, 80)
|
||||
print('Found:', len(self.supply_chests), 'supply-labeled chests')
|
||||
self.state = self.choose_supply_chest
|
||||
|
||||
self.barrels = w.find_blocks_indexed(p, blocks.BARREL_IDS, 80)
|
||||
print('Found:', self.barrels)
|
||||
self.state = self.choose_barrel
|
||||
|
||||
def choose_barrel(self):
|
||||
print('Choosing a barrel...')
|
||||
for barrel in self.barrels:
|
||||
if barrel in self.checked_barrels:
|
||||
def choose_supply_chest(self):
|
||||
print('Choosing a supply-labeled chest...')
|
||||
for container in self.supply_chests:
|
||||
key = container['positions']
|
||||
if key in self.checked_supply_chests:
|
||||
continue
|
||||
if barrel in self.bad_barrels:
|
||||
continue
|
||||
|
||||
print('Chose:', barrel)
|
||||
self.barrel = barrel
|
||||
self.state = self.path_to_barrel
|
||||
self.checked_supply_chests.add(key)
|
||||
self.chest = container['position']
|
||||
self.area = self.chest
|
||||
print('Chose supply chest:', self.chest)
|
||||
self.state = self.path_to_supply_chest
|
||||
return
|
||||
|
||||
print('No barrels')
|
||||
print('No more supply-labeled chests')
|
||||
self.state = self.cleanup
|
||||
|
||||
def path_to_barrel(self):
|
||||
print('Finding path to barrel')
|
||||
w = self.g.world
|
||||
def path_to_supply_chest(self):
|
||||
print('Finding path to supply chest')
|
||||
p = utils.pint(self.g.pos)
|
||||
c = self.g.chunks
|
||||
|
||||
navpath = w.path_to_place_faked(p, self.barrel)
|
||||
navpath = self.g.world.path_to_place_faked(p, self.chest)
|
||||
print('navpath:', navpath)
|
||||
|
||||
if navpath:
|
||||
self.g.path = navpath[:-1]
|
||||
self.opening = self.g.path[-1]
|
||||
self.checked_barrels.append(self.barrel)
|
||||
self.area = self.barrel
|
||||
self.state = self.going_to_barrel
|
||||
self.state = self.going_to_supply_chest
|
||||
self.checked_supplies = []
|
||||
return
|
||||
else:
|
||||
print('Barrel is unreachable; ending supply task')
|
||||
self.bad_barrels.append(self.barrel)
|
||||
self.state = self.cleanup
|
||||
print('Supply chest is unreachable; trying another labeled chest')
|
||||
self.state = self.choose_supply_chest
|
||||
|
||||
def going_to_barrel(self):
|
||||
def going_to_supply_chest(self):
|
||||
if utils.pint(self.g.pos) == self.opening:
|
||||
self.g.look_at = self.area
|
||||
self.state = self.open_barrel
|
||||
self.state = self.open_supply_chest
|
||||
|
||||
def open_barrel(self):
|
||||
print('Opening barrel')
|
||||
def open_supply_chest(self):
|
||||
print('Opening supply chest')
|
||||
self.g.game.open_container(self.area)
|
||||
self.wait_time = 1
|
||||
self.state = self.wait
|
||||
@@ -288,8 +285,8 @@ class GrabSuppliesStates:
|
||||
self.state = self.grab_items
|
||||
return
|
||||
|
||||
print('Aborting, dont need any more supplies')
|
||||
self.state = self.close_barrel
|
||||
print('No matching items in this supply chest')
|
||||
self.state = self.close_supply_chest
|
||||
|
||||
def grab_items(self):
|
||||
if self.g.item_lock: return
|
||||
@@ -299,7 +296,7 @@ class GrabSuppliesStates:
|
||||
print('Didnt get a window, aborting')
|
||||
self.state = self.cleanup
|
||||
return
|
||||
if w.get('container_slots', 0) != 27:
|
||||
if w.get('container_slots', 0) not in (27, 54):
|
||||
print('Got wrong container size, aborting')
|
||||
self.state = self.cleanup
|
||||
return
|
||||
@@ -338,11 +335,11 @@ class GrabSuppliesStates:
|
||||
self.wait_time = 0.25
|
||||
self.state = self.wait
|
||||
|
||||
def close_barrel(self):
|
||||
print('Closing barrel')
|
||||
def close_supply_chest(self):
|
||||
print('Closing supply chest')
|
||||
self.g.game.close_window()
|
||||
self.g.look_at = None
|
||||
self.state = self.choose_barrel
|
||||
self.state = self.choose_supply_chest
|
||||
|
||||
def cleanup(self):
|
||||
self.state = self.done
|
||||
@@ -356,10 +353,9 @@ class GrabSuppliesStates:
|
||||
self.state = self.idle
|
||||
|
||||
self.supplies = self.default_supplies()
|
||||
self.barrels = []
|
||||
self.checked_barrels = []
|
||||
self.bad_barrels = []
|
||||
self.barrel = None
|
||||
self.supply_chests = []
|
||||
self.checked_supply_chests = set()
|
||||
self.supply_chest = None
|
||||
self.checked_supplies = []
|
||||
self.target_items = None
|
||||
self.maximum_stacks = 0
|
||||
|
||||
+117
@@ -9,6 +9,7 @@ from copy import copy
|
||||
from mosfet import utils
|
||||
from mosfet import path
|
||||
from mosfet.info import blocks
|
||||
from mosfet.info import items
|
||||
from mosfet.info import mobs
|
||||
|
||||
class World:
|
||||
@@ -76,6 +77,122 @@ class World:
|
||||
result.sort(key=lambda sign: utils.phyp(center, sign['position']))
|
||||
return result
|
||||
|
||||
def _double_chest_positions(self, chest):
|
||||
state_id = self.block_at(*chest)
|
||||
properties = blocks.PROPS.get(state_id, {})
|
||||
chest_type = properties.get('type')
|
||||
if chest_type not in ('left', 'right'):
|
||||
return (tuple(chest),)
|
||||
|
||||
other_type = 'right' if chest_type == 'left' else 'left'
|
||||
for offset in ((1, 0, 0), (-1, 0, 0), (0, 0, 1), (0, 0, -1)):
|
||||
partner = utils.padd(chest, offset)
|
||||
other = blocks.PROPS.get(self.block_at(*partner), {})
|
||||
if (other.get('type') == other_type and
|
||||
other.get('facing') == properties.get('facing')):
|
||||
return tuple(sorted((tuple(chest), partner)))
|
||||
return (tuple(chest),)
|
||||
|
||||
def find_labeled_chests(self, center, distance=80):
|
||||
"""Find single/double chests assigned item categories by nearby signs."""
|
||||
grouped = {}
|
||||
sign_offsets = (
|
||||
(0, 0, 0), (0, -1, 0),
|
||||
(1, 0, 0), (-1, 0, 0), (0, 0, 1), (0, 0, -1),
|
||||
)
|
||||
for sign in self.find_signs(center, distance):
|
||||
categories = set()
|
||||
labels = set()
|
||||
for line in sign['lines']:
|
||||
item_ids = items.storage_item_ids_for_label(line)
|
||||
if item_ids:
|
||||
categories.update(item_ids)
|
||||
labels.add(line.strip())
|
||||
if not categories:
|
||||
continue
|
||||
|
||||
sign_pos = sign['position']
|
||||
adjacent = {
|
||||
utils.padd(sign_pos, offset)
|
||||
for offset in sign_offsets
|
||||
if self.block_at(*utils.padd(sign_pos, offset)) in blocks.CHEST_IDS
|
||||
}
|
||||
if not adjacent:
|
||||
nearby = self.find_blocks_indexed(
|
||||
sign_pos, blocks.CHEST_IDS, 2)
|
||||
if nearby:
|
||||
nearest = min(utils.phyp(sign_pos, chest)
|
||||
for chest in nearby)
|
||||
adjacent = {chest for chest in nearby
|
||||
if utils.phyp(sign_pos, chest) == nearest}
|
||||
|
||||
for chest in adjacent:
|
||||
positions = self._double_chest_positions(chest)
|
||||
record = grouped.setdefault(positions, {
|
||||
'position': tuple(chest),
|
||||
'positions': positions,
|
||||
'item_ids': set(),
|
||||
'labels': set(),
|
||||
'sign_positions': set(),
|
||||
})
|
||||
record['item_ids'].update(categories)
|
||||
record['labels'].update(labels)
|
||||
record['sign_positions'].add(sign_pos)
|
||||
|
||||
result = list(grouped.values())
|
||||
result.sort(key=lambda chest: utils.phyp(center, chest['position']))
|
||||
return result
|
||||
|
||||
def find_supply_chests(self, center, bot_name, distance=80):
|
||||
"""Find chests whose sign is addressed to this bot's supplies."""
|
||||
bot_name = str(bot_name).casefold()
|
||||
group_name = (bot_name[:-1] if len(bot_name) > 1 and
|
||||
bot_name[-1] in '123' else None)
|
||||
addresses = {bot_name}
|
||||
if group_name:
|
||||
addresses.add(group_name)
|
||||
|
||||
grouped = {}
|
||||
sign_offsets = (
|
||||
(0, 0, 0), (0, -1, 0),
|
||||
(1, 0, 0), (-1, 0, 0), (0, 0, 1), (0, 0, -1),
|
||||
)
|
||||
for sign in self.find_signs(center, distance):
|
||||
text = ' '.join(line for line in sign['lines'] if line.strip())
|
||||
tokens = re.findall(r'[a-z0-9_]+', text.casefold())
|
||||
if (len(tokens) < 2 or tokens[0] not in addresses or
|
||||
'supplies' not in tokens[1:]):
|
||||
continue
|
||||
|
||||
sign_pos = sign['position']
|
||||
candidates = {
|
||||
utils.padd(sign_pos, offset)
|
||||
for offset in sign_offsets
|
||||
if self.block_at(*utils.padd(sign_pos, offset)) in blocks.CHEST_IDS
|
||||
}
|
||||
if not candidates:
|
||||
nearby = self.find_blocks_indexed(
|
||||
sign_pos, blocks.CHEST_IDS, 2)
|
||||
if nearby:
|
||||
nearest = min(utils.phyp(sign_pos, chest) for chest in nearby)
|
||||
candidates = {chest for chest in nearby
|
||||
if utils.phyp(sign_pos, chest) == nearest}
|
||||
|
||||
for chest in candidates:
|
||||
positions = self._double_chest_positions(chest)
|
||||
record = grouped.setdefault(positions, {
|
||||
'position': tuple(chest),
|
||||
'positions': positions,
|
||||
'labels': set(),
|
||||
'sign_positions': set(),
|
||||
})
|
||||
record['labels'].update(tokens[1:])
|
||||
record['sign_positions'].add(sign_pos)
|
||||
|
||||
result = list(grouped.values())
|
||||
result.sort(key=lambda chest: utils.phyp(center, chest['position']))
|
||||
return result
|
||||
|
||||
def sign_policies(self, bot_name, distance=64):
|
||||
"""Parse sign policies addressed to this bot or its numbered group."""
|
||||
bot_name = str(bot_name).casefold()
|
||||
|
||||
@@ -147,7 +147,7 @@ class GatherWoodPortTests(unittest.TestCase):
|
||||
self.assertTrue(items.AXE_IDS.issubset(items.NEEDED_ITEMS))
|
||||
self.assertTrue(items.SAPLING_IDS.issubset(items.WANTED_ITEMS))
|
||||
|
||||
job.grab_supplies_states.state = job.grab_supplies_states.find_barrels
|
||||
job.grab_supplies_states.state = job.grab_supplies_states.find_supply_chests
|
||||
job.clear_leaves_states.state = job.clear_leaves_states.find_leaves
|
||||
job.plant_tree_states.state = job.plant_tree_states.check_feet
|
||||
job.grab_sapling_states.state = job.grab_sapling_states.find_saplings
|
||||
|
||||
@@ -8,6 +8,14 @@ from mosfet.jobs.grab_supplies import GrabSuppliesStates
|
||||
class GroundSupplyTests(unittest.TestCase):
|
||||
def test_default_needed_supplies_are_configured_by_constructor(self):
|
||||
state = GrabSuppliesStates(Munch())
|
||||
self.assertEqual(items.FOOD, [
|
||||
'cooked_porkchop', 'cooked_beef', 'bread', 'cooked_chicken',
|
||||
'cooked_cod', 'cooked_salmon',
|
||||
])
|
||||
self.assertEqual(items.FOOD_IDS, items.get_set({
|
||||
'cooked_porkchop', 'cooked_beef', 'bread', 'cooked_chicken',
|
||||
'cooked_cod', 'cooked_salmon',
|
||||
}))
|
||||
self.assertEqual(state.supplies, {
|
||||
tuple(items.BED_IDS): (1, 1),
|
||||
(items.CHEST_ID,): (1, 1),
|
||||
@@ -44,19 +52,50 @@ class GroundSupplyTests(unittest.TestCase):
|
||||
self.assertEqual(state.target_items, (items.CHEST_ID,))
|
||||
self.assertIs(state.state.__func__, state.find_ground_items.__func__)
|
||||
|
||||
def test_unreachable_barrel_ends_supply_task_without_trying_more(self):
|
||||
def test_supply_selection_uses_only_addressed_supply_chests(self):
|
||||
position = (4, 64, 0)
|
||||
chest_record = {
|
||||
'position': position,
|
||||
'positions': (position,),
|
||||
'labels': {'mosfet supplies'},
|
||||
'sign_positions': {(4, 64, 1)},
|
||||
}
|
||||
|
||||
class FakeWorld:
|
||||
@staticmethod
|
||||
def path_to_place_faked(_start, _barrel):
|
||||
return None
|
||||
def find_supply_chests(_center, _bot_name, _distance):
|
||||
return [chest_record]
|
||||
|
||||
@staticmethod
|
||||
def find_blocks_indexed(*_args):
|
||||
raise AssertionError('grab_supplies must not search barrels')
|
||||
|
||||
state = GrabSuppliesStates(Munch(
|
||||
name='mosfet1', pos=(0.5, 64.0, 0.5), world=FakeWorld()))
|
||||
state.find_supply_chests()
|
||||
state.choose_supply_chest()
|
||||
|
||||
self.assertEqual(state.chest, position)
|
||||
self.assertIs(state.state.__func__, state.path_to_supply_chest.__func__)
|
||||
|
||||
def test_unreachable_supply_chest_ends_task_without_searching_barrels(self):
|
||||
class FakeWorld:
|
||||
@staticmethod
|
||||
def path_to_place_faked(_start, _chest):
|
||||
return None
|
||||
|
||||
position = (10, 64, 10)
|
||||
state = GrabSuppliesStates(Munch(
|
||||
pos=(0.5, 64.0, 0.5), world=FakeWorld(), chunks=Munch()))
|
||||
state.barrel = (10, 64, 10)
|
||||
state.path_to_barrel()
|
||||
state.supply_chests = [{
|
||||
'position': position, 'positions': (position,),
|
||||
'labels': {'mosfet supplies'},
|
||||
}]
|
||||
state.choose_supply_chest()
|
||||
state.path_to_supply_chest()
|
||||
state.choose_supply_chest()
|
||||
|
||||
self.assertIs(state.state.__func__, state.cleanup.__func__)
|
||||
self.assertEqual(state.bad_barrels, [(10, 64, 10)])
|
||||
|
||||
def test_job_walks_to_and_picks_up_dropped_supply_before_barrels(self):
|
||||
axe_id = next(iter(items.AXE_IDS))
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
import unittest
|
||||
from munch import Munch
|
||||
|
||||
from mosfet.info import blocks, items
|
||||
from mosfet.jobs.cache_items import CacheItemsStates
|
||||
from mosfet.world import World
|
||||
|
||||
|
||||
class LabeledStorageTests(unittest.TestCase):
|
||||
def test_labels_resolve_to_item_categories(self):
|
||||
seeds = items.storage_item_ids_for_label('Seeds')
|
||||
wheat = items.storage_item_ids_for_label('Wheat')
|
||||
|
||||
self.assertEqual(seeds, items.get_set({
|
||||
'beetroot', 'beetroot_seeds', 'carrot', 'melon_seeds',
|
||||
'nether_wart', 'pitcher_pod', 'potato', 'pumpkin_seeds',
|
||||
'torchflower_seeds', 'wheat_seeds',
|
||||
}))
|
||||
self.assertEqual(items.storage_item_ids_for_label('Dirt'), set())
|
||||
self.assertEqual(items.storage_item_ids_for_label('Stone'), set())
|
||||
self.assertIn(items.WHEAT_SEEDS_ID, seeds)
|
||||
self.assertEqual(wheat, {items.WHEAT_ID})
|
||||
self.assertNotIn(items.WHEAT_SEEDS_ID, wheat)
|
||||
|
||||
def test_sign_label_associates_with_adjacent_double_chest(self):
|
||||
sign_pos = (0, 64, 0)
|
||||
left_chest = (0, 64, 1)
|
||||
right_chest = (1, 64, 1)
|
||||
blocks_by_pos = {left_chest: 5552, right_chest: 5560}
|
||||
chunks = Munch(
|
||||
block_entities={sign_pos: {
|
||||
'type': 7,
|
||||
'data': {'front_text': {'messages': [
|
||||
'Seeds', '', '', '',
|
||||
]}},
|
||||
}},
|
||||
index={},
|
||||
get_block_at=lambda *pos: blocks_by_pos.get(tuple(pos)),
|
||||
)
|
||||
chests = World(Munch(chunks=chunks)).find_labeled_chests(
|
||||
sign_pos, 10)
|
||||
|
||||
self.assertEqual(len(chests), 1)
|
||||
self.assertEqual(chests[0]['positions'], (left_chest, right_chest))
|
||||
self.assertIn(items.WHEAT_SEEDS_ID, chests[0]['item_ids'])
|
||||
self.assertEqual(chests[0]['labels'], {'Seeds'})
|
||||
|
||||
def test_wheat_chest_does_not_cache_seeds(self):
|
||||
wheat = Munch(present=True, item_id=items.WHEAT_ID, item_count=64)
|
||||
seeds = Munch(present=True, item_id=items.WHEAT_SEEDS_ID, item_count=64)
|
||||
clicks = []
|
||||
|
||||
class FakeGame:
|
||||
@staticmethod
|
||||
def count_window_slots():
|
||||
return 0
|
||||
|
||||
@staticmethod
|
||||
def click_window(*args):
|
||||
clicks.append(args)
|
||||
|
||||
cache = CacheItemsStates(Munch(
|
||||
inv={9: wheat, 10: seeds}, item_lock=False,
|
||||
window=Munch(container_slots=27, contents={
|
||||
**dict.fromkeys(range(27)), 27: wheat, 28: seeds,
|
||||
}),
|
||||
game=FakeGame(),
|
||||
))
|
||||
cache.is_labeled_container = True
|
||||
cache.container_item_ids = items.storage_item_ids_for_label('Wheat')
|
||||
cache.move_items()
|
||||
|
||||
self.assertEqual(clicks, [(27, 0, 1, wheat)])
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user