"""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:')]