1#![doc = include_str!("../README.md")]
2
3mod behavior;
4pub mod block_state;
5pub mod fluid_state;
6mod generated;
7mod range;
8
9use core::fmt::Debug;
10use std::{any::Any, collections::HashMap};
11
12pub use behavior::BlockBehavior;
13pub use block_state::BlockState;
15pub use generated::{blocks, properties};
16pub use range::BlockStates;
17
18pub trait BlockTrait: Debug + Any {
19 fn behavior(&self) -> BlockBehavior;
20 fn id(&self) -> &'static str;
24 fn as_block_state(&self) -> BlockState;
29 fn as_registry_block(&self) -> azalea_registry::Block;
34
35 fn property_map(&self) -> HashMap<&'static str, &'static str>;
41 fn get_property(&self, name: &str) -> Option<&'static str>;
46}
47
48impl dyn BlockTrait {
49 pub fn downcast_ref<T: BlockTrait>(&self) -> Option<&T> {
50 (self as &dyn Any).downcast_ref::<T>()
51 }
52}
53
54pub trait Property {
55 type Value;
56
57 fn try_from_block_state(state: BlockState) -> Option<Self::Value>;
58
59 fn to_static_str(&self) -> &'static str;
61}
62
63#[cfg(test)]
64mod tests {
65 use crate::BlockTrait;
66
67 #[test]
68 pub fn roundtrip_block_state() {
69 let block = crate::blocks::OakTrapdoor {
70 facing: crate::properties::FacingCardinal::East,
71 half: crate::properties::TopBottom::Bottom,
72 open: true,
73 powered: false,
74 waterlogged: false,
75 };
76 let block_state = block.as_block_state();
77 let block_from_state = Box::<dyn BlockTrait>::from(block_state);
78 let block_from_state = *block_from_state
79 .downcast_ref::<crate::blocks::OakTrapdoor>()
80 .unwrap();
81 assert_eq!(block, block_from_state);
82 }
83
84 #[test]
85 pub fn test_property_map() {
86 let block = crate::blocks::OakTrapdoor {
87 facing: crate::properties::FacingCardinal::East,
88 half: crate::properties::TopBottom::Bottom,
89 open: true,
90 powered: false,
91 waterlogged: false,
92 };
93
94 let property_map = block.property_map();
95
96 assert_eq!(property_map.len(), 5);
97 assert_eq!(property_map.get("facing"), Some(&"east"));
98 assert_eq!(property_map.get("half"), Some(&"bottom"));
99 assert_eq!(property_map.get("open"), Some(&"true"));
100 assert_eq!(property_map.get("powered"), Some(&"false"));
101 assert_eq!(property_map.get("waterlogged"), Some(&"false"));
102 }
103
104 #[test]
105 pub fn test_integer_properties() {
106 let sapling_stage_0 = crate::blocks::OakSapling {
108 stage: crate::properties::OakSaplingStage::_0,
109 };
110
111 let sapling_stage_1 = crate::blocks::OakSapling {
112 stage: crate::properties::OakSaplingStage::_1,
113 };
114
115 let properties_0 = sapling_stage_0.property_map();
117 assert_eq!(properties_0.len(), 1);
118 assert_eq!(properties_0.get("stage"), Some(&"0"));
119 assert_eq!(sapling_stage_0.get_property("stage"), Some("0"));
120
121 let properties_1 = sapling_stage_1.property_map();
123 assert_eq!(properties_1.len(), 1);
124 assert_eq!(properties_1.get("stage"), Some(&"1"));
125 assert_eq!(sapling_stage_1.get_property("stage"), Some("1"));
126
127 assert_eq!(sapling_stage_0.get_property("nonexistent"), None);
129 }
130}