diff --git a/pumpkin-data/build.rs b/pumpkin-data/build.rs index a09dfbf0e..e391dd2f4 100644 --- a/pumpkin-data/build.rs +++ b/pumpkin-data/build.rs @@ -65,175 +65,218 @@ fn main() { } fn generate_block_state_collision_shapes() { - let json_data: Vec> = serde_json::from_str(include_str!("../assets/block_state_collision_shapes.json")) - .expect("Could not parse json file."); + let json_data: Vec> = + serde_json::from_str(include_str!("../assets/block_state_collision_shapes.json")) + .expect("Could not parse json file."); - let shapes: Vec<_> = json_data.into_iter().map(|block_state_shape_idxs| quote::quote! { - &[ #(#block_state_shape_idxs),* ] - }).collect(); + let shapes: Vec<_> = json_data + .into_iter() + .map(|block_state_shape_idxs| { + quote::quote! { + &[ #(#block_state_shape_idxs),* ] + } + }) + .collect(); let len: usize = shapes.len(); - save_to_file("block_state_collision_shapes.rs", quote::quote! { - pub static BLOCK_STATE_COLLISION_SHAPES: [&[u16]; #len ] = [ #(#shapes),* ]; - }); + save_to_file( + "block_state_collision_shapes.rs", + quote::quote! { + pub static BLOCK_STATE_COLLISION_SHAPES: [&[u16]; #len ] = [ #(#shapes),* ]; + }, + ); } fn generate_shapes() { - let json_data: Vec = serde_json::from_str(include_str!("../assets/block_shapes.json")) - .expect("Could not parse json file."); - - let shapes: Vec<_> = json_data.into_iter().map(|s| { - let (max_x, max_y, max_z) = (s.max_x, s.max_y, s.max_z); - let (min_x, min_y, min_z) = (s.min_x, s.min_y, s.min_z); - quote::quote! { - Shape { - max_x: #max_x, - max_y: #max_y, - max_z: #max_z, - min_x: #min_x, - min_y: #min_y, - min_z: #min_z, + let json_data: Vec = + serde_json::from_str(include_str!("../assets/block_shapes.json")) + .expect("Could not parse json file."); + + let shapes: Vec<_> = json_data + .into_iter() + .map(|s| { + let (max_x, max_y, max_z) = (s.max_x, s.max_y, s.max_z); + let (min_x, min_y, min_z) = (s.min_x, s.min_y, s.min_z); + quote::quote! { + Shape { + max_x: #max_x, + max_y: #max_y, + max_z: #max_z, + min_x: #min_x, + min_y: #min_y, + min_z: #min_z, + } } - } - }).collect(); + }) + .collect(); let len: usize = shapes.len(); - save_to_file("block_shapes.rs", quote::quote! { - use pumpkin_core::registries::blocks::Shape; - pub static BLOCK_SHAPES: [Shape; #len ] = [ #(#shapes),* ]; - }); + save_to_file( + "block_shapes.rs", + quote::quote! { + use pumpkin_core::registries::blocks::Shape; + pub static BLOCK_SHAPES: [Shape; #len ] = [ #(#shapes),* ]; + }, + ); } fn generate_block_state_properties() { - let json_data: Vec> = serde_json::from_str(include_str!("../assets/block_state_properties.json")) - .expect("Could not parse json file."); + let json_data: Vec> = + serde_json::from_str(include_str!("../assets/block_state_properties.json")) + .expect("Could not parse json file."); - let properties: Vec<_> = json_data.into_iter().map(|block_state_property_values| quote::quote! { - &[ #(#block_state_property_values),* ] - }).collect(); + let properties: Vec<_> = json_data + .into_iter() + .map(|block_state_property_values| { + quote::quote! { + &[ #(#block_state_property_values),* ] + } + }) + .collect(); let len = properties.len(); - save_to_file("block_state_properties.rs", quote::quote! { - pub static BLOCK_STATE_PROPERTY_VALUES: [&[&str]; #len ] = [ #(#properties),* ]; - }); + save_to_file( + "block_state_properties.rs", + quote::quote! { + pub static BLOCK_STATE_PROPERTY_VALUES: [&[&str]; #len ] = [ #(#properties),* ]; + }, + ); } fn generate_block_entities() { - let json_data: Vec = serde_json::from_str(include_str!("../assets/block_entities.json")) - .expect("Could not parse json file."); - - let block_entities: Vec<_> = json_data.into_iter().map(|e| { - let id = e.id; - let name = e.name; - let ident = e.ident; - quote::quote! { - BlockEntityKind { - id: #id, - name: #name, - ident: #ident, + let json_data: Vec = + serde_json::from_str(include_str!("../assets/block_entities.json")) + .expect("Could not parse json file."); + + let block_entities: Vec<_> = json_data + .into_iter() + .map(|e| { + let id = e.id; + let name = e.name; + let ident = e.ident; + quote::quote! { + BlockEntityKind { + id: #id, + name: #name, + ident: #ident, + } } - } - }).collect(); + }) + .collect(); let len: usize = block_entities.len(); - save_to_file("block_entities.rs", quote::quote! { - use pumpkin_core::registries::blocks::BlockEntityKind; - pub static BLOCK_ENTITY_KINDS: [BlockEntityKind; #len ] = [ #(#block_entities),* ]; - }); + save_to_file( + "block_entities.rs", + quote::quote! { + use pumpkin_core::registries::blocks::BlockEntityKind; + pub static BLOCK_ENTITY_KINDS: [BlockEntityKind; #len ] = [ #(#block_entities),* ]; + }, + ); } fn generate_block_states() { - let json_data: Vec = serde_json::from_str(include_str!("../assets/block_states.json")) - .expect("Could not parse json file."); - - let states: Vec<_> = json_data.into_iter().map(|s| { - let (id, block_id) = (s.id, s.block_id); - let (air, replacable) = (s.air, s.replaceable); - let luminance = s.luminance; - let burnable = s.burnable; - let opacity = to_option_tokens(s.opacity); - let block_entity = to_option_tokens(s.block_entity_type); - quote::quote! { - State { - id: #id, - block_id: #block_id, - air: #air, - replaceable: #replacable, - luminance: #luminance, - burnable: #burnable, - opacity: #opacity, - block_entity_type: #block_entity, + let json_data: Vec = + serde_json::from_str(include_str!("../assets/block_states.json")) + .expect("Could not parse json file."); + + let states: Vec<_> = json_data + .into_iter() + .map(|s| { + let (id, block_id) = (s.id, s.block_id); + let (air, replacable) = (s.air, s.replaceable); + let luminance = s.luminance; + let burnable = s.burnable; + let opacity = to_option_tokens(s.opacity); + let block_entity = to_option_tokens(s.block_entity_type); + quote::quote! { + State { + id: #id, + block_id: #block_id, + air: #air, + replaceable: #replacable, + luminance: #luminance, + burnable: #burnable, + opacity: #opacity, + block_entity_type: #block_entity, + } } - } - }).collect(); + }) + .collect(); let len: usize = states.len(); - save_to_file("block_states.rs", quote::quote! { - use pumpkin_core::registries::blocks::State; - pub static BLOCK_STATES: [State; #len ] = [ #(#states),* ]; - }); + save_to_file( + "block_states.rs", + quote::quote! { + use pumpkin_core::registries::blocks::State; + pub static BLOCK_STATES: [State; #len ] = [ #(#states),* ]; + }, + ); } fn generate_blocks() { let json_data: Vec = serde_json::from_str(include_str!("../assets/blocks.json")) .expect("Could not parse json file."); - let blocks: Vec<_> = json_data.into_iter().map(|b| { - let id = b.id; - let name = b.name; - let translation_key = b.translation_key; - let hardness = b.hardness; - let item_id = b.item_id; - let default_state_id = b.default_state_id; - let first_state_id = b.first_state_id; - let last_state_id = b.last_state_id; - let wall_variant_id = to_option_tokens(b.wall_variant_id); - - let properties = b.properties.iter().map(|p| { - let p_name = &p.name; - let p_values = &p.values; + let blocks: Vec<_> = json_data + .into_iter() + .map(|b| { + let id = b.id; + let name = b.name; + let translation_key = b.translation_key; + let hardness = b.hardness; + let item_id = b.item_id; + let default_state_id = b.default_state_id; + let first_state_id = b.first_state_id; + let last_state_id = b.last_state_id; + let wall_variant_id = to_option_tokens(b.wall_variant_id); + + let properties = b.properties.iter().map(|p| { + let p_name = &p.name; + let p_values = &p.values; + + quote::quote! { + Property { + name: #p_name, + values: &[ #(#p_values),* ], + } + } + }); quote::quote! { - Property { - name: #p_name, - values: &[ #(#p_values),* ], + Block { + id: #id, + item_id: #item_id, + hardness: #hardness, + wall_variant_id: #wall_variant_id, + translation_key: #translation_key, + name: #name, + properties: &[ #(#properties),* ], + default_state_id: #default_state_id, + first_state_id: #first_state_id, + last_state_id: #last_state_id, } } - }); - - quote::quote! { - Block { - id: #id, - item_id: #item_id, - hardness: #hardness, - wall_variant_id: #wall_variant_id, - translation_key: #translation_key, - name: #name, - properties: &[ #(#properties),* ], - default_state_id: #default_state_id, - first_state_id: #first_state_id, - last_state_id: #last_state_id, - } - } - }).collect(); + }) + .collect(); let len = blocks.len(); - save_to_file("blocks.rs", quote::quote! { - use pumpkin_core::registries::blocks::Block; - use pumpkin_core::registries::blocks::Property; - pub static BLOCKS: [Block; #len ] = [ #(#blocks),* ]; - }); + save_to_file( + "blocks.rs", + quote::quote! { + use pumpkin_core::registries::blocks::Block; + use pumpkin_core::registries::blocks::Property; + pub static BLOCKS: [Block; #len ] = [ #(#blocks),* ]; + }, + ); } fn save_to_file(name: &str, tokens: proc_macro2::TokenStream) { let out_dir_name = env::var_os("OUT_DIR").unwrap(); let out_path = Path::new(&out_dir_name); - let mut file = std::fs::File::create(out_path.join(name)) - .expect("Failed to create file"); + let mut file = std::fs::File::create(out_path.join(name)).expect("Failed to create file"); - let parsed = syn::parse2(tokens) - .expect("Failed to parse TokenStream"); + let parsed = syn::parse2(tokens).expect("Failed to parse TokenStream"); let formatted = prettyplease::unparse(&parsed); diff --git a/pumpkin-data/src/lib.rs b/pumpkin-data/src/lib.rs index 00823bf5d..9181e1764 100644 --- a/pumpkin-data/src/lib.rs +++ b/pumpkin-data/src/lib.rs @@ -1,8 +1,6 @@ pub mod block; +pub mod block_entities; +pub mod block_shapes; pub mod block_state; - -/// having this in a seperate module improves compile times by a lot pub mod block_state_collision_shapes; -pub mod block_shapes; -mod block_state_properties; -mod block_entities; +pub mod block_state_properties; diff --git a/pumpkin-world/src/block/block_registry.rs b/pumpkin-world/src/block/block_registry.rs index aea024904..4fe3e3789 100644 --- a/pumpkin-world/src/block/block_registry.rs +++ b/pumpkin-world/src/block/block_registry.rs @@ -1,8 +1,10 @@ use std::collections::HashMap; use std::sync::LazyLock; -use pumpkin_core::registries::blocks::{Block, State}; +use pumpkin_core::registries::blocks::{Block, BlockEntityKind, Shape, State}; use pumpkin_data::block::BLOCKS; +use pumpkin_data::block_entities::BLOCK_ENTITY_KINDS; +use pumpkin_data::block_shapes::BLOCK_SHAPES; use pumpkin_data::block_state::BLOCK_STATES; use pumpkin_data::block_state_collision_shapes::BLOCK_STATE_COLLISION_SHAPES; @@ -14,30 +16,49 @@ static BLOCKS_HASH_MAP: LazyLock> = LazyLock::new(|| { map }); -pub fn get_block(registry_id: &str) -> Option<&Block> { +/// todo: make this const if possible +pub fn get_block(registry_id: &str) -> Option<&'static Block> { let idx = BLOCKS_HASH_MAP.get(registry_id)?; BLOCKS.get(*idx) } -pub fn get_block_by_id<'a>(id: u16) -> Option<&'a Block> { +pub fn get_block_by_id(id: u16) -> Option<&'static Block> { BLOCKS.get(id as usize) } -pub fn get_state_by_state_id<'a>(id: u16) -> Option<&'a State> { +pub fn get_state_by_state_id(id: u16) -> Option<&'static State> { BLOCK_STATES.get(id as usize) } -pub fn get_block_by_state_id<'a>(id: u16) -> Option<&'a Block> { +pub fn get_block_by_state_id(id: u16) -> Option<&'static Block> { let state = get_state_by_state_id(id)?; get_block_by_id(state.block_id) } -pub fn get_block_and_state_by_state_id<'a>(id: u16) -> Option<(&'a Block, &'a State)> { +pub fn get_block_and_state_by_state_id(id: u16) -> Option<(&'static Block, &'static State)> { let state = get_state_by_state_id(id)?; Some((get_block_by_id(state.block_id)?, state)) } -// todo: consider moving this into State -pub fn get_block_state_collision_shape_ids(id: u16) -> Option<&'static [u16]> { - BLOCK_STATE_COLLISION_SHAPES.get(id as usize).copied() +pub fn get_block_entity_kind_by_id(block_entity_kind_id: u32) -> Option<&'static BlockEntityKind> { + BLOCK_ENTITY_KINDS.get(block_entity_kind_id as usize) +} + +pub fn get_collision_shape_by_id(collision_shape_id: u16) -> Option<&'static Shape> { + BLOCK_SHAPES.get(collision_shape_id as usize) +} + +pub fn get_block_state_collision_shape_ids(block_state_id: u16) -> Option<&'static [u16]> { + BLOCK_STATE_COLLISION_SHAPES + .get(block_state_id as usize) + .copied() +} + +pub fn iter_block_state_collision_shapes(block_state_id: u16) -> Option> { + let ids = get_block_state_collision_shape_ids(block_state_id)?; + let mut vec = Vec::with_capacity(ids.len()); + for id in ids { + vec.push(get_collision_shape_by_id(*id)?); + } + Some(vec) } diff --git a/pumpkin-world/src/item/item_registry.rs b/pumpkin-world/src/item/item_registry.rs index 5b75b5777..9a8a88afc 100644 --- a/pumpkin-world/src/item/item_registry.rs +++ b/pumpkin-world/src/item/item_registry.rs @@ -1,7 +1,10 @@ use std::{collections::HashMap, sync::LazyLock}; +use pumpkin_core::registries::blocks::Block; use serde::Deserialize; +use crate::block::block_registry; + const ITEMS_JSON: &str = include_str!("../../../assets/items.json"); pub static ITEMS: LazyLock> = LazyLock::new(|| { @@ -22,16 +25,22 @@ pub fn get_item(name: &str) -> Option<&Item> { } pub fn get_item_by_id(id: u16) -> Option<&'static Item> { - ITEMS_BY_ID.get(id as usize).map(|it| *it) + ITEMS_BY_ID.get(id as usize).copied() } #[derive(Deserialize, Clone, Debug)] pub struct Item { pub id: u16, - pub block_id: u16, + pub block_id: Option, pub components: ItemComponents, } +impl Item { + pub fn get_block(&self) -> Option<&Block> { + block_registry::get_block_by_id(self.block_id?) + } +} + #[derive(Deserialize, Clone, Debug)] pub struct ItemComponents { #[serde(rename = "minecraft:max_stack_size")] diff --git a/pumpkin/src/client/player_packet.rs b/pumpkin/src/client/player_packet.rs index c13001781..883abb2d0 100644 --- a/pumpkin/src/client/player_packet.rs +++ b/pumpkin/src/client/player_packet.rs @@ -32,7 +32,7 @@ use pumpkin_protocol::{ SSetCreativeSlot, SSetHeldItem, SSwingArm, SUseItemOn, Status, }, }; -use pumpkin_world::{block::{block_registry, BlockFace}, item::item_registry}; +use pumpkin_world::{block::BlockFace, item::item_registry}; use thiserror::Error; use super::PlayerConfig; @@ -616,10 +616,8 @@ impl Player { let mut inventory = self.inventory.lock().await; let item_slot = inventory.held_item_mut(); if let Some(item) = item_slot { - - let block = item_registry::get_item_by_id(item.item_id).and_then(|it| - block_registry::get_block_by_id(it.block_id) - ); + let block = + item_registry::get_item_by_id(item.item_id).and_then(|it| it.get_block()); // check if item is a block, Because Not every item can be placed :D if let Some(block) = block {