aboutsummaryrefslogtreecommitdiff
path: root/azalea-block
diff options
context:
space:
mode:
authormat <27899617+mat-1@users.noreply.github.com>2023-03-07 22:09:56 -0600
committerGitHub <noreply@github.com>2023-03-07 22:09:56 -0600
commit5dd35c7ed82c38ef36ca28f630e8d05c5db2cbea (patch)
tree72719e46479e7884ea535c768ab7c244ce048063 /azalea-block
parent719379a8a76ab0685f2bd14bebe2f0cd1e97f06b (diff)
downloadazalea-drasl-5dd35c7ed82c38ef36ca28f630e8d05c5db2cbea.tar.xz
Add World::find_block (#80)
* start adding World::find_block * keep working on find_block * BlockStates * fix sorting * update examples that use find_one_block * azalea_block::properties * fix tests * add a gotoblock command to testbot
Diffstat (limited to 'azalea-block')
-rwxr-xr-xazalea-block/README.md12
-rwxr-xr-xazalea-block/azalea-block-macros/src/lib.rs110
-rwxr-xr-xazalea-block/src/generated.rs (renamed from azalea-block/src/blocks.rs)15
-rwxr-xr-xazalea-block/src/lib.rs60
-rw-r--r--azalea-block/src/range.rs33
5 files changed, 147 insertions, 83 deletions
diff --git a/azalea-block/README.md b/azalea-block/README.md
index e4b6357b..9be4c79b 100755
--- a/azalea-block/README.md
+++ b/azalea-block/README.md
@@ -8,11 +8,11 @@ There's three block types, used for different things. You can (mostly) convert b
```
# use azalea_block::BlockState;
-let block_state: BlockState = azalea_block::CobblestoneWallBlock {
- east: azalea_block::EastWall::Low,
- north: azalea_block::NorthWall::Low,
- south: azalea_block::SouthWall::Low,
- west: azalea_block::WestWall::Low,
+let block_state: BlockState = azalea_block::blocks::CobblestoneWall {
+ east: azalea_block::properties::EastWall::Low,
+ north: azalea_block::properties::NorthWall::Low,
+ south: azalea_block::properties::SouthWall::Low,
+ west: azalea_block::properties::WestWall::Low,
up: false,
waterlogged: false,
}
@@ -36,7 +36,7 @@ let block = Box::<dyn Block>::from(block_state);
```
# use azalea_block::{Block, BlockState};
# let block_state: BlockState = azalea_registry::Block::Jukebox.into();
-if let Some(jukebox) = Box::<dyn Block>::from(block_state).downcast_ref::<azalea_block::JukeboxBlock>() {
+if let Some(jukebox) = Box::<dyn Block>::from(block_state).downcast_ref::<azalea_block::blocks::Jukebox>() {
// ...
}
```
diff --git a/azalea-block/azalea-block-macros/src/lib.rs b/azalea-block/azalea-block-macros/src/lib.rs
index b69ebd06..a8739e7c 100755
--- a/azalea-block/azalea-block-macros/src/lib.rs
+++ b/azalea-block/azalea-block-macros/src/lib.rs
@@ -38,7 +38,7 @@ struct PropertyDefinitions {
properties: Vec<PropertyDefinition>,
}
-/// `snowy: false` or `axis: Axis::Y`
+/// `snowy: false` or `axis: properties::Axis::Y`
#[derive(Debug)]
struct PropertyWithNameAndDefault {
name: Ident,
@@ -59,7 +59,7 @@ struct BlockDefinition {
}
impl Parse for PropertyWithNameAndDefault {
fn parse(input: ParseStream) -> Result<Self> {
- // `snowy: false` or `axis: Axis::Y`
+ // `snowy: false` or `axis: properties::Axis::Y`
let property_name = input.parse()?;
input.parse::<Token![:]>()?;
@@ -74,7 +74,7 @@ impl Parse for PropertyWithNameAndDefault {
is_enum = true;
property_type = first_ident;
let variant = input.parse::<Ident>()?;
- property_default.extend(quote! { ::#variant });
+ property_default = quote! { properties::#property_default::#variant };
} else if first_ident_string == "true" || first_ident_string == "false" {
property_type = Ident::new("bool", first_ident.span());
} else {
@@ -310,6 +310,7 @@ pub fn make_block_states(input: TokenStream) -> TokenStream {
let mut from_state_to_block_match = quote! {};
let mut from_registry_block_to_block_match = quote! {};
let mut from_registry_block_to_blockstate_match = quote! {};
+ let mut from_registry_block_to_blockstates_match = quote! {};
for block in &input.block_definitions.blocks {
let block_property_names = &block
@@ -386,13 +387,16 @@ pub fn make_block_states(input: TokenStream) -> TokenStream {
for PropertyWithNameAndDefault {
property_type: struct_name,
name,
+ is_enum,
..
} in &properties_with_name
{
// let property_name_snake =
// Ident::new(&property.to_string(), proc_macro2::Span::call_site());
- block_struct_fields.extend(quote! {
- pub #name: #struct_name,
+ block_struct_fields.extend(if *is_enum {
+ quote! { pub #name: properties::#struct_name, }
+ } else {
+ quote! { pub #name: #struct_name, }
});
}
@@ -400,10 +404,7 @@ pub fn make_block_states(input: TokenStream) -> TokenStream {
&to_pascal_case(&block.name.to_string()),
proc_macro2::Span::call_site(),
);
- let block_struct_name = Ident::new(
- &format!("{block_name_pascal_case}Block"),
- proc_macro2::Span::call_site(),
- );
+ let block_struct_name = Ident::new(&block_name_pascal_case.to_string(), proc_macro2::Span::call_site());
let mut from_block_to_state_match_inner = quote! {};
@@ -445,7 +446,7 @@ pub fn make_block_states(input: TokenStream) -> TokenStream {
}
let property_type = if property.is_enum {
- quote! {#property_struct_name_ident::#variant}
+ quote! {properties::#property_struct_name_ident::#variant}
} else {
quote! {#variant}
};
@@ -476,9 +477,9 @@ pub fn make_block_states(input: TokenStream) -> TokenStream {
// 7035..=7058 => {
// let b = b - 7035;
// &AcaciaButtonBlock {
- // powered: Powered::from((b / 1) % 2),
- // facing: Facing::from((b / 2) % 4),
- // face: Face::from((b / 8) % 3),
+ // powered: properties::Powered::from((b / 1) % 2),
+ // facing: properties::Facing::from((b / 2) % 4),
+ // face: properties::Face::from((b / 8) % 3),
// }
// }
let mut from_state_to_block_inner = quote! {};
@@ -498,7 +499,7 @@ pub fn make_block_states(input: TokenStream) -> TokenStream {
// this is not a mistake, it starts with true for some reason
quote! {(b / #division) % #property_variants_count == 0}
} else {
- quote! {#property_struct_name_ident::from((b / #division) % #property_variants_count)}
+ quote! {properties::#property_struct_name_ident::from((b / #division) % #property_variants_count)}
}
};
from_state_to_block_inner.extend(quote! {
@@ -523,6 +524,9 @@ pub fn make_block_states(input: TokenStream) -> TokenStream {
from_registry_block_to_blockstate_match.extend(quote! {
azalea_registry::Block::#block_name_pascal_case => BlockState { id: #default_state_id },
});
+ from_registry_block_to_blockstates_match.extend(quote! {
+ azalea_registry::Block::#block_name_pascal_case => BlockStates::from(#first_state_id..=#last_state_id),
+ });
let mut block_default_fields = quote! {};
for PropertyWithNameAndDefault {
@@ -560,14 +564,14 @@ pub fn make_block_states(input: TokenStream) -> TokenStream {
fn id(&self) -> &'static str {
#block_id
}
- fn as_blockstate(&self) -> BlockState {
+ fn as_block_state(&self) -> BlockState {
#from_block_to_state_match
}
}
impl From<#block_struct_name> for BlockState {
fn from(b: #block_struct_name) -> Self {
- b.as_blockstate()
+ b.as_block_state()
}
}
@@ -585,21 +589,7 @@ pub fn make_block_states(input: TokenStream) -> TokenStream {
let last_state_id = state_id - 1;
let mut generated = quote! {
- #property_enums
-
- /// A representation of a state a block can be in. (for example, a stone
- /// block only has one state but each possible stair rotation is a
- /// different state).
- #[derive(Copy, Clone, PartialEq, Eq, Default)]
- pub struct BlockState {
- /// The protocol ID for the block state. IDs may change every
- /// version, so you shouldn't hard-code them or store them in databases.
- pub id: u32
- }
-
impl BlockState {
- pub const AIR: BlockState = BlockState { id: 0 };
-
/// Returns the highest possible state ID.
#[inline]
pub fn max_state() -> u32 {
@@ -607,38 +597,50 @@ pub fn make_block_states(input: TokenStream) -> TokenStream {
}
}
- impl std::fmt::Debug for BlockState {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- write!(f, "BlockState(id: {}, {:?})", self.id, Box::<dyn Block>::from(*self))
- }
+ pub mod properties {
+ use super::*;
+
+ #property_enums
}
};
generated.extend(quote! {
- #block_structs
-
- impl From<BlockState> for Box<dyn Block> {
- fn from(block_state: BlockState) -> Self {
- let b = block_state.id;
- match b {
- #from_state_to_block_match
- _ => panic!("Invalid block state: {}", b),
+ pub mod blocks {
+ use super::*;
+
+ #block_structs
+
+ impl From<BlockState> for Box<dyn Block> {
+ fn from(block_state: BlockState) -> Self {
+ let b = block_state.id;
+ match b {
+ #from_state_to_block_match
+ _ => panic!("Invalid block state: {}", b),
+ }
}
}
- }
- impl From<azalea_registry::Block> for Box<dyn Block> {
- fn from(block: azalea_registry::Block) -> Self {
- match block {
- #from_registry_block_to_block_match
- _ => unreachable!("There should always be a block struct for every azalea_registry::Block variant")
+ impl From<azalea_registry::Block> for Box<dyn Block> {
+ fn from(block: azalea_registry::Block) -> Self {
+ match block {
+ #from_registry_block_to_block_match
+ _ => unreachable!("There should always be a block struct for every azalea_registry::Block variant")
+ }
}
}
- }
- impl From<azalea_registry::Block> for BlockState {
- fn from(block: azalea_registry::Block) -> Self {
- match block {
- #from_registry_block_to_blockstate_match
- _ => unreachable!("There should always be a block state for every azalea_registry::Block variant")
+ impl From<azalea_registry::Block> for BlockState {
+ fn from(block: azalea_registry::Block) -> Self {
+ match block {
+ #from_registry_block_to_blockstate_match
+ _ => unreachable!("There should always be a block state for every azalea_registry::Block variant")
+ }
+ }
+ }
+ impl From<azalea_registry::Block> for BlockStates {
+ fn from(block: azalea_registry::Block) -> Self {
+ match block {
+ #from_registry_block_to_blockstates_match
+ _ => unreachable!("There should always be a block state for every azalea_registry::Block variant")
+ }
}
}
}
diff --git a/azalea-block/src/blocks.rs b/azalea-block/src/generated.rs
index e6923d59..afe6dfda 100755
--- a/azalea-block/src/blocks.rs
+++ b/azalea-block/src/generated.rs
@@ -1,20 +1,7 @@
-use std::any::Any;
-
-use crate::BlockBehavior;
+use crate::{Block, BlockBehavior, BlockState, BlockStates};
use azalea_block_macros::make_block_states;
use std::fmt::Debug;
-pub trait Block: Debug + Any {
- fn behavior(&self) -> BlockBehavior;
- fn id(&self) -> &'static str;
- fn as_blockstate(&self) -> BlockState;
-}
-impl dyn Block {
- pub fn downcast_ref<T: Block>(&self) -> Option<&T> {
- (self as &dyn Any).downcast_ref::<T>()
- }
-}
-
make_block_states! {
Properties => {
"snowy" => bool,
diff --git a/azalea-block/src/lib.rs b/azalea-block/src/lib.rs
index 7a62e588..43099db5 100755
--- a/azalea-block/src/lib.rs
+++ b/azalea-block/src/lib.rs
@@ -2,14 +2,49 @@
#![feature(trait_upcasting)]
mod behavior;
-mod blocks;
+mod generated;
+mod range;
+
+pub use generated::{blocks, properties};
use azalea_buf::{BufReadError, McBufReadable, McBufVarReadable, McBufVarWritable, McBufWritable};
pub use behavior::BlockBehavior;
-pub use blocks::*;
-use std::io::{Cursor, Write};
+use core::fmt::Debug;
+pub use range::BlockStates;
+use std::{
+ any::Any,
+ io::{Cursor, Write},
+};
+
+pub trait Block: Debug + Any {
+ fn behavior(&self) -> BlockBehavior;
+ /// Get the Minecraft ID for this block. For example `stone` or
+ /// `grass_block`.
+ fn id(&self) -> &'static str;
+ /// Convert the block to a block state. This is lossless, as the block
+ /// contains all the state data.
+ fn as_block_state(&self) -> BlockState;
+}
+impl dyn Block {
+ pub fn downcast_ref<T: Block>(&self) -> Option<&T> {
+ (self as &dyn Any).downcast_ref::<T>()
+ }
+}
+
+/// A representation of a state a block can be in.
+///
+/// For example, a stone block only has one state but each possible stair
+/// rotation is a different state.
+#[derive(Copy, Clone, PartialEq, Eq, Default, Hash)]
+pub struct BlockState {
+ /// The protocol ID for the block state. IDs may change every
+ /// version, so you shouldn't hard-code them or store them in databases.
+ pub id: u32,
+}
impl BlockState {
+ pub const AIR: BlockState = BlockState { id: 0 };
+
/// Transmutes a u32 to a block state.
///
/// # Safety
@@ -52,6 +87,17 @@ impl McBufWritable for BlockState {
}
}
+impl std::fmt::Debug for BlockState {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ write!(
+ f,
+ "BlockState(id: {}, {:?})",
+ self.id,
+ Box::<dyn Block>::from(*self)
+ )
+ }
+}
+
#[cfg(test)]
mod tests {
use super::*;
@@ -80,18 +126,14 @@ mod tests {
"{:?}",
BlockState::from(azalea_registry::Block::FloweringAzalea)
);
- assert!(
- formatted.ends_with(", FloweringAzaleaBlock)"),
- "{}",
- formatted
- );
+ assert!(formatted.ends_with(", FloweringAzalea)"), "{}", formatted);
let formatted = format!(
"{:?}",
BlockState::from(azalea_registry::Block::BigDripleafStem)
);
assert!(
- formatted.ends_with(", BigDripleafStemBlock { facing: North, waterlogged: false })"),
+ formatted.ends_with(", BigDripleafStem { facing: North, waterlogged: false })"),
"{}",
formatted
);
diff --git a/azalea-block/src/range.rs b/azalea-block/src/range.rs
new file mode 100644
index 00000000..6ccf4152
--- /dev/null
+++ b/azalea-block/src/range.rs
@@ -0,0 +1,33 @@
+use std::{collections::HashSet, ops::RangeInclusive};
+
+use crate::BlockState;
+
+#[derive(Debug, Clone)]
+pub struct BlockStates {
+ pub set: HashSet<BlockState>,
+}
+
+impl From<RangeInclusive<u32>> for BlockStates {
+ fn from(range: RangeInclusive<u32>) -> Self {
+ let mut set = HashSet::with_capacity((range.end() - range.start() + 1) as usize);
+ for id in range {
+ set.insert(BlockState { id });
+ }
+ Self { set }
+ }
+}
+
+impl IntoIterator for BlockStates {
+ type Item = BlockState;
+ type IntoIter = std::collections::hash_set::IntoIter<BlockState>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ self.set.into_iter()
+ }
+}
+
+impl BlockStates {
+ pub fn contains(&self, state: &BlockState) -> bool {
+ self.set.contains(state)
+ }
+}