azalea-world uses azalea-block

This commit is contained in:
mat 2022-06-16 23:38:51 -05:00
parent 4f89f70091
commit 74c3ae52f8
6 changed files with 76 additions and 6 deletions

1
Cargo.lock generated
View file

@ -183,6 +183,7 @@ dependencies = [
name = "azalea-world" name = "azalea-world"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"azalea-block",
"azalea-core", "azalea-core",
"azalea-nbt", "azalea-nbt",
"azalea-protocol", "azalea-protocol",

View file

@ -461,9 +461,12 @@ pub fn make_block_states(input: TokenStream) -> TokenStream {
block_structs.extend(block_struct); block_structs.extend(block_struct);
} }
let last_state_id = (state_id - 1) as u32;
quote! { quote! {
#property_enums #property_enums
#[repr(u32)]
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum BlockState { pub enum BlockState {
#block_state_enum_variants #block_state_enum_variants
} }
@ -479,6 +482,15 @@ pub fn make_block_states(input: TokenStream) -> TokenStream {
} }
} }
} }
impl BlockState {
/// Returns the highest possible state
#[inline]
pub fn max_state() -> u32 {
#last_state_id
}
}
} }
.into() .into()
} }

View file

@ -4,3 +4,44 @@ mod blocks;
pub use behavior::BlockBehavior; pub use behavior::BlockBehavior;
pub use blocks::*; pub use blocks::*;
use std::mem;
impl BlockState {
/// Transmutes a u32 to a block state. UB if the value is not a valid block
/// state.
#[inline]
pub unsafe fn from_u32_unsafe(state_id: u32) -> Self {
mem::transmute::<u32, BlockState>(state_id)
}
#[inline]
pub fn is_valid_state(state_id: u32) -> bool {
state_id <= Self::max_state()
}
}
impl TryFrom<u32> for BlockState {
type Error = ();
/// Safely converts a state id to a block state.
fn try_from(state_id: u32) -> Result<Self, Self::Error> {
if Self::is_valid_state(state_id) {
Ok(unsafe { Self::from_u32_unsafe(state_id) })
} else {
Err(())
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_from_u32() {
assert_eq!(BlockState::try_from(0).unwrap(), BlockState::Air);
assert!(BlockState::try_from(BlockState::max_state()).is_ok());
assert!(BlockState::try_from(BlockState::max_state() + 1).is_err());
}
}

View file

@ -9,3 +9,4 @@ version = "0.1.0"
azalea-core = {path = "../azalea-core"} azalea-core = {path = "../azalea-core"}
azalea-nbt = {path = "../azalea-nbt"} azalea-nbt = {path = "../azalea-nbt"}
azalea-protocol = {path = "../azalea-protocol"} azalea-protocol = {path = "../azalea-protocol"}
azalea-block = {path = "../azalea-block"}

View file

@ -188,6 +188,12 @@ impl BitStorage {
let bit_index = (index - cell_index * self.values_per_long as usize) * self.bits; let bit_index = (index - cell_index * self.values_per_long as usize) * self.bits;
*cell = *cell & !(self.mask << bit_index) | (value & self.mask) << bit_index; *cell = *cell & !(self.mask << bit_index) | (value & self.mask) << bit_index;
} }
/// The number of entries.
#[inline]
pub fn size(&self) -> usize {
self.size
}
} }
#[cfg(test)] #[cfg(test)]

View file

@ -8,6 +8,7 @@ use azalea_core::{BlockPos, ChunkBlockPos, ChunkPos, ChunkSectionBlockPos};
use azalea_protocol::mc_buf::{McBufReadable, McBufWritable}; use azalea_protocol::mc_buf::{McBufReadable, McBufWritable};
pub use bit_storage::BitStorage; pub use bit_storage::BitStorage;
use palette::PalettedContainer; use palette::PalettedContainer;
use azalea_block::BlockState;
use std::{ use std::{
io::{Read, Write}, io::{Read, Write},
ops::{Index, IndexMut}, ops::{Index, IndexMut},
@ -57,7 +58,7 @@ impl World {
self.storage.view_center = *pos; self.storage.view_center = *pos;
} }
pub fn get_block_state(&self, pos: &BlockPos) -> Option<u32> { pub fn get_block_state(&self, pos: &BlockPos) -> Option<BlockState> {
self.storage.get_block_state(pos, self.min_y) self.storage.get_block_state(pos, self.min_y)
} }
} }
@ -122,7 +123,7 @@ impl ChunkStorage {
&& (chunk_pos.z - self.view_center.z).unsigned_abs() <= self.chunk_radius && (chunk_pos.z - self.view_center.z).unsigned_abs() <= self.chunk_radius
} }
pub fn get_block_state(&self, pos: &BlockPos, min_y: i32) -> Option<u32> { pub fn get_block_state(&self, pos: &BlockPos, min_y: i32) -> Option<BlockState> {
let chunk_pos = ChunkPos::from(pos); let chunk_pos = ChunkPos::from(pos);
println!("chunk_pos {:?} block_pos {:?}", chunk_pos, pos); println!("chunk_pos {:?} block_pos {:?}", chunk_pos, pos);
let chunk = &self[&chunk_pos]; let chunk = &self[&chunk_pos];
@ -175,7 +176,7 @@ impl Chunk {
(y.div_floor(16) - min_section_index) as u32 (y.div_floor(16) - min_section_index) as u32
} }
pub fn get(&self, pos: &ChunkBlockPos, min_y: i32) -> u32 { pub fn get(&self, pos: &ChunkBlockPos, min_y: i32) -> BlockState {
let section_index = self.section_index(pos.y, min_y); let section_index = self.section_index(pos.y, min_y);
// TODO: make sure the section exists // TODO: make sure the section exists
let section = &self.sections[section_index as usize]; let section = &self.sections[section_index as usize];
@ -210,6 +211,14 @@ impl McBufReadable for Section {
// "A section has more blocks than what should be possible. This is a bug!" // "A section has more blocks than what should be possible. This is a bug!"
// ); // );
let states = PalettedContainer::read_with_type(buf, &PalettedContainerType::BlockStates)?; let states = PalettedContainer::read_with_type(buf, &PalettedContainerType::BlockStates)?;
for i in 0..states.storage.size() {
if !BlockState::is_valid_state(states.storage.get(i) as u32) {
return Err(format!(
"Invalid block state {} (index {}) found in section.",
states.storage.get(i), i
));
}
}
let biomes = PalettedContainer::read_with_type(buf, &PalettedContainerType::Biomes)?; let biomes = PalettedContainer::read_with_type(buf, &PalettedContainerType::Biomes)?;
Ok(Section { Ok(Section {
block_count, block_count,
@ -229,9 +238,9 @@ impl McBufWritable for Section {
} }
impl Section { impl Section {
// TODO: return a BlockState instead of a u32 fn get(&self, pos: ChunkSectionBlockPos) -> BlockState {
fn get(&self, pos: ChunkSectionBlockPos) -> u32 { // TODO: use the unsafe method and do the check earlier
self.states self.states
.get(pos.x as usize, pos.y as usize, pos.z as usize) .get(pos.x as usize, pos.y as usize, pos.z as usize).try_into().expect("Invalid block state.")
} }
} }