Files
minecraft-bot/mosfet/info/blocks.py
T

121 lines
4.1 KiB
Python

"""Minecraft 26.3 block-state metadata and legacy automation selectors."""
from itertools import product
from mosfet.info import mcdata
MCD_BLOCKS = mcdata.mcd.blocks
JSON_BLOCKS = {'minecraft:' + name: data
for name, data in MCD_BLOCKS.items()}
BLOCKS = {}
PROPS = {}
COLLISION_BOXES = {}
for name, data in MCD_BLOCKS.items():
first = data['minStateId']
last = data['maxStateId']
properties = data.get('states', [])
property_values = [prop.get('values', []) for prop in properties]
combinations = list(product(*property_values)) if property_values else [()]
for offset, state_id in enumerate(range(first, last + 1)):
BLOCKS[state_id] = name
if offset < len(combinations):
PROPS[state_id] = {
prop['name']: value
for prop, value in zip(properties, combinations[offset])
}
else:
PROPS[state_id] = {}
shape_ref = mcdata.mcd.collision_shapes['blocks'].get(name, 1)
refs = shape_ref if isinstance(shape_ref, list) else [shape_ref] * (last-first+1)
for offset, state_id in enumerate(range(first, last + 1)):
ref = refs[offset] if offset < len(refs) else refs[-1]
COLLISION_BOXES[state_id] = mcdata.mcd.collision_shapes['shapes'].get(
str(ref), [])
BREAK_DISTANCE = 6
AIR = MCD_BLOCKS['air']['minStateId']
STONE = MCD_BLOCKS['stone']['minStateId']
SAND = MCD_BLOCKS['sand']['minStateId']
SOUL_TORCH = MCD_BLOCKS['soul_torch']['minStateId']
EMERALD_BLOCK = MCD_BLOCKS['emerald_block']['minStateId']
SINGLE_SNOW = MCD_BLOCKS.get('snow', MCD_BLOCKS.get('snow_layer', {})).get(
'minStateId', AIR)
TEST_BLOCK = (616, 78, 496)
def get_set(names):
"""Return every state ID belonging to the named blocks; ignore removed names."""
result = set()
for name in names:
name = name.removeprefix('minecraft:')
data = MCD_BLOCKS.get(name)
if data is not None:
result.update(range(data['minStateId'], data['maxStateId'] + 1))
return result
# Collision geometry is safer for navigation than the old hard-coded 1.16 list.
NON_SOLID_IDS = {
state_id for state_id, boxes in COLLISION_BOXES.items() if not boxes
}
AVOID = {
'lava', 'water', 'fire', 'magma_block', 'sweet_berry_bush',
'nether_portal', 'end_portal', 'cactus', 'powder_snow',
}
AVOID_IDS = get_set(AVOID)
AVOID_IDS.update(
state_id for state_id, name in BLOCKS.items()
if name.endswith(('_fence', '_fence_gate', '_wall'))
)
WATER_IDS = get_set(['water'])
LOGS = sorted(name for name in MCD_BLOCKS
if name.endswith(('_log', '_wood', '_stem', '_hyphae')))
LEAVES = sorted(name for name in MCD_BLOCKS if name.endswith('_leaves'))
SAPLINGS = sorted(name for name in MCD_BLOCKS
if name.endswith('_sapling') or name.endswith('_propagule'))
BEDS = sorted(name for name in MCD_BLOCKS if name.endswith('_bed'))
INDEXED = ['chest', 'trapped_chest', 'emerald_block', 'barrel'] + BEDS + [
'wheat', 'potatoes', 'carrots', 'beetroots',
] + LOGS
LOG_IDS = get_set(LOGS)
LEAF_IDS = get_set(LEAVES)
CHEST_IDS = get_set(['chest'])
BARREL_IDS = get_set(['barrel'])
TRAPPED_CHEST_IDS = get_set(['trapped_chest'])
NETHERWART_IDS = get_set(['nether_wart'])
WHEAT_IDS = get_set(['wheat'])
POTATO_IDS = get_set(['potatoes'])
CARROT_IDS = get_set(['carrots'])
BEETROOT_IDS = get_set(['beetroots'])
SAPLING_IDS = get_set(SAPLINGS)
BED_IDS = get_set(BEDS)
INDEXED_IDS = get_set(INDEXED)
def _mature_state(name, property_name, mature_value):
data = MCD_BLOCKS.get(name)
if data is None:
return None
for state_id in range(data['minStateId'], data['maxStateId'] + 1):
if PROPS[state_id].get(property_name) == str(mature_value):
return state_id
return data['maxStateId']
MATURE_WHEAT_ID = _mature_state('wheat', 'age', 7)
MATURE_POTATO_ID = _mature_state('potatoes', 'age', 7)
MATURE_CARROT_ID = _mature_state('carrots', 'age', 7)
MATURE_BEETROOT_ID = _mature_state('beetroots', 'age', 3)
def get(block_state_id):
return MCD_BLOCKS[BLOCKS[block_state_id]]
def find(name):
return MCD_BLOCKS[name.removeprefix('minecraft:')]