Add sign-labeled chest storage
This commit is contained in:
+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()
|
||||
|
||||
Reference in New Issue
Block a user