aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormat <github@matdoes.dev>2022-06-16 23:38:51 -0500
committermat <github@matdoes.dev>2022-06-16 23:38:51 -0500
commit74c3ae52f84d988b8bf3f0affe143d2cd2d8143a (patch)
treef4755ffe59e7f5feac34569b788c92f7a88b9489
parent4f89f70091962c967a7022e6f293f11a446abc3c (diff)
downloadazalea-drasl-74c3ae52f84d988b8bf3f0affe143d2cd2d8143a.tar.xz
azalea-world uses azalea-block
-rwxr-xr-xCargo.lock1
-rw-r--r--azalea-block/block-macros/src/lib.rs12
-rw-r--r--azalea-block/src/lib.rs41
-rw-r--r--azalea-world/Cargo.toml1
-rw-r--r--azalea-world/src/bit_storage.rs6
-rw-r--r--azalea-world/src/lib.rs21
6 files changed, 76 insertions, 6 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 1ef95311..f3b5df08 100755
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -183,6 +183,7 @@ dependencies = [
name = "azalea-world"
version = "0.1.0"
dependencies = [
+ "azalea-block",
"azalea-core",
"azalea-nbt",
"azalea-protocol",
diff --git a/azalea-block/block-macros/src/lib.rs b/azalea-block/block-macros/src/lib.rs
index d38062d4..6206bb65 100644
--- a/azalea-block/block-macros/src/lib.rs
+++ b/azalea-block/block-macros/src/lib.rs
@@ -461,9 +461,12 @@ pub fn make_block_states(input: TokenStream) -> TokenStream {
block_structs.extend(block_struct);
}
+ let last_state_id = (state_id - 1) as u32;
quote! {
#property_enums
+ #[repr(u32)]
+ #[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum BlockState {
#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()
}
diff --git a/azalea-block/src/lib.rs b/azalea-block/src/lib.rs
index 01c86b11..95e8ce37 100644
--- a/azalea-block/src/lib.rs
+++ b/azalea-block/src/lib.rs
@@ -4,3 +4,44 @@ mod blocks;
pub use behavior::BlockBehavior;
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());
+ }
+}
diff --git a/azalea-world/Cargo.toml b/azalea-world/Cargo.toml
index e8d81ac3..79e6155d 100644
--- a/azalea-world/Cargo.toml
+++ b/azalea-world/Cargo.toml
@@ -9,3 +9,4 @@ version = "0.1.0"
azalea-core = {path = "../azalea-core"}
azalea-nbt = {path = "../azalea-nbt"}
azalea-protocol = {path = "../azalea-protocol"}
+azalea-block = {path = "../azalea-block"}
diff --git a/azalea-world/src/bit_storage.rs b/azalea-world/src/bit_storage.rs
index aba52aef..c69cb216 100644
--- a/azalea-world/src/bit_storage.rs
+++ b/azalea-world/src/bit_storage.rs
@@ -188,6 +188,12 @@ impl BitStorage {
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;
}
+
+ /// The number of entries.
+ #[inline]
+ pub fn size(&self) -> usize {
+ self.size
+ }
}
#[cfg(test)]
diff --git a/azalea-world/src/lib.rs b/azalea-world/src/lib.rs
index 766c61f0..8777c0a3 100644
--- a/azalea-world/src/lib.rs
+++ b/azalea-world/src/lib.rs
@@ -8,6 +8,7 @@ use azalea_core::{BlockPos, ChunkBlockPos, ChunkPos, ChunkSectionBlockPos};
use azalea_protocol::mc_buf::{McBufReadable, McBufWritable};
pub use bit_storage::BitStorage;
use palette::PalettedContainer;
+use azalea_block::BlockState;
use std::{
io::{Read, Write},
ops::{Index, IndexMut},
@@ -57,7 +58,7 @@ impl World {
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)
}
}
@@ -122,7 +123,7 @@ impl ChunkStorage {
&& (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);
println!("chunk_pos {:?} block_pos {:?}", chunk_pos, pos);
let chunk = &self[&chunk_pos];
@@ -175,7 +176,7 @@ impl Chunk {
(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);
// TODO: make sure the section exists
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!"
// );
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)?;
Ok(Section {
block_count,
@@ -229,9 +238,9 @@ impl McBufWritable for Section {
}
impl Section {
- // TODO: return a BlockState instead of a u32
- fn get(&self, pos: ChunkSectionBlockPos) -> u32 {
+ fn get(&self, pos: ChunkSectionBlockPos) -> BlockState {
+ // TODO: use the unsafe method and do the check earlier
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.")
}
}