use std::collections::HashMap; use std::sync::LazyLock; use serde::Deserialize; use crate::loot::LootTable; pub static BLOCKS: LazyLock = LazyLock::new(|| { serde_json::from_str(include_str!("../../../assets/blocks.json")) .expect("Could not parse blocks.json registry.") }); pub static BLOCKS_BY_ID: LazyLock> = LazyLock::new(|| { let mut map = HashMap::new(); for block in &BLOCKS.blocks { map.insert(block.id, block.clone()); } map }); pub static BLOCK_ID_BY_REGISTRY_ID: LazyLock> = LazyLock::new(|| { let mut map = HashMap::new(); for block in &BLOCKS.blocks { map.insert(block.name.clone(), block.id); } map }); pub static BLOCK_ID_TO_REGISTRY_ID: LazyLock> = LazyLock::new(|| { let mut map = HashMap::new(); for block in &*BLOCKS.blocks { map.insert(block.default_state_id, block.name.clone()); } map }); pub static BLOCK_ID_BY_STATE_ID: LazyLock> = LazyLock::new(|| { let mut map = HashMap::new(); for block in &BLOCKS.blocks { for state in &block.states { map.insert(state.id, block.id); } } map }); pub static STATE_INDEX_BY_STATE_ID: LazyLock> = LazyLock::new(|| { let mut map = HashMap::new(); for block in &BLOCKS.blocks { for (index, state) in block.states.iter().enumerate() { map.insert(state.id, index as u16); } } map }); pub static BLOCK_ID_BY_ITEM_ID: LazyLock> = LazyLock::new(|| { let mut map = HashMap::new(); for block in &BLOCKS.blocks { map.insert(block.item_id, block.id); } map }); pub fn get_block(registry_id: &str) -> Option<&Block> { let id = BLOCK_ID_BY_REGISTRY_ID.get(®istry_id.replace("minecraft:", ""))?; BLOCKS_BY_ID.get(id) } pub fn get_block_by_id<'a>(id: u16) -> Option<&'a Block> { BLOCKS_BY_ID.get(&id) } pub fn get_state_by_state_id<'a>(id: u16) -> Option<&'a State> { get_block_and_state_by_state_id(id).map(|(_, state)| state) } pub fn get_block_by_state_id<'a>(id: u16) -> Option<&'a Block> { let block_id = BLOCK_ID_BY_STATE_ID.get(&id)?; BLOCKS_BY_ID.get(block_id) } pub fn get_block_and_state_by_state_id<'a>(id: u16) -> Option<(&'a Block, &'a State)> { let block_id = BLOCK_ID_BY_STATE_ID.get(&id)?; let block = BLOCKS_BY_ID.get(block_id)?; let state_index = STATE_INDEX_BY_STATE_ID.get(&id)?; let state = block.states.get(*state_index as usize)?; Some((block, state)) } pub fn get_block_by_item<'a>(item_id: u16) -> Option<&'a Block> { let block_id = BLOCK_ID_BY_ITEM_ID.get(&item_id)?; BLOCKS_BY_ID.get(block_id) } pub fn get_block_collision_shapes(block_id: u16) -> Option> { let block = BLOCKS_BY_ID.get(&BLOCK_ID_BY_STATE_ID[&block_id])?; let state = &block.states[STATE_INDEX_BY_STATE_ID[&block_id] as usize]; let mut shapes: Vec = vec![]; for i in 0..state.collision_shapes.len() { let shape = &BLOCKS.shapes[state.collision_shapes[i] as usize]; shapes.push(shape.clone()); } Some(shapes) } #[derive(Deserialize, Clone)] pub struct TopLevel { pub block_entity_types: Vec, shapes: Vec, pub blocks: Vec, } #[derive(Deserialize, Clone)] pub struct Block { pub id: u16, pub item_id: u16, pub hardness: f32, pub wall_variant_id: Option, pub translation_key: String, pub name: String, pub loot_table: Option, pub properties: Vec, pub default_state_id: u16, pub states: Vec, } #[derive(Deserialize, Clone, Debug)] pub struct Property { pub name: String, pub values: Vec, } #[derive(Deserialize, Clone, Debug)] pub struct State { pub id: u16, pub air: bool, pub luminance: u8, pub burnable: bool, pub tool_required: bool, pub opacity: Option, pub replaceable: bool, pub collision_shapes: Vec, pub block_entity_type: Option, } #[derive(Deserialize, Clone, Debug)] pub struct Shape { pub min: [f64; 3], pub max: [f64; 3], }