126 lines
4.3 KiB
Python
126 lines
4.3 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', 'nether_wart',
|
|
] + 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'])
|
|
DOOR_NAMES = sorted(name for name in MCD_BLOCKS
|
|
if name.endswith('_door'))
|
|
DOOR_IDS = get_set(DOOR_NAMES)
|
|
OPENABLE_DOOR_IDS = get_set(
|
|
name for name in DOOR_NAMES if name != 'iron_door')
|
|
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:')]
|