aboutsummaryrefslogtreecommitdiff
path: root/azalea-world/src/heightmap.rs
diff options
context:
space:
mode:
authormat <git@matdoes.dev>2023-09-17 21:44:17 -0500
committermat <git@matdoes.dev>2023-09-17 21:44:17 -0500
commit856a3252f693421df519cbc4d9bc03cfc0f0c212 (patch)
tree310cffa9d9c09a4651ab1707899ae20416713fc0 /azalea-world/src/heightmap.rs
parent61e63c08968f7b0f451c4c3b07ea8d4927b14a2f (diff)
downloadazalea-drasl-856a3252f693421df519cbc4d9bc03cfc0f0c212.tar.xz
heightmaps
Diffstat (limited to 'azalea-world/src/heightmap.rs')
-rw-r--r--azalea-world/src/heightmap.rs151
1 files changed, 151 insertions, 0 deletions
diff --git a/azalea-world/src/heightmap.rs b/azalea-world/src/heightmap.rs
new file mode 100644
index 00000000..ec73adf9
--- /dev/null
+++ b/azalea-world/src/heightmap.rs
@@ -0,0 +1,151 @@
+use std::{fmt::Display, str::FromStr};
+
+use azalea_block::BlockState;
+use azalea_core::{math, ChunkBlockPos};
+use azalea_registry::tags::blocks::LEAVES;
+
+use crate::{chunk_storage::get_block_state_from_sections, BitStorage, Section};
+
+// (wg stands for worldgen)
+
+#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
+pub enum HeightmapKind {
+ WorldSurfaceWg,
+ WorldSurface,
+ OceanFloorWg,
+ OceanFloor,
+ MotionBlocking,
+ MotionBlockingNoLeaves,
+}
+
+#[derive(Clone, Debug)]
+pub struct Heightmap {
+ pub data: BitStorage,
+ pub min_y: i32,
+ pub kind: HeightmapKind,
+}
+
+fn blocks_motion(block_state: BlockState) -> bool {
+ // TODO
+ !block_state.is_air()
+}
+
+fn motion_blocking(block_state: BlockState) -> bool {
+ // TODO
+ !block_state.is_air() || block_state.waterlogged()
+}
+
+impl HeightmapKind {
+ pub fn is_opaque(self, block_state: BlockState) -> bool {
+ let block = Box::<dyn azalea_block::Block>::from(block_state);
+ let registry_block = block.as_registry_block();
+ match self {
+ HeightmapKind::WorldSurfaceWg => !block_state.is_air(),
+ HeightmapKind::WorldSurface => !block_state.is_air(),
+ HeightmapKind::OceanFloorWg => blocks_motion(block_state),
+ HeightmapKind::OceanFloor => blocks_motion(block_state),
+ HeightmapKind::MotionBlocking => motion_blocking(block_state),
+ HeightmapKind::MotionBlockingNoLeaves => {
+ motion_blocking(block_state) && !LEAVES.contains(&registry_block)
+ }
+ }
+ }
+}
+
+impl Heightmap {
+ pub fn new(kind: HeightmapKind, dimension_height: u32, min_y: i32, data: Vec<u64>) -> Self {
+ let bits = math::ceil_log2(dimension_height + 1);
+ let data = BitStorage::new(bits as usize, 16 * 16, Some(data)).unwrap();
+ Self { kind, data, min_y }
+ }
+
+ pub fn get_index(x: u8, z: u8) -> usize {
+ (x as usize) + (z as usize) * 16
+ }
+
+ pub fn get_first_available_at_index(&self, index: usize) -> i32 {
+ self.data.get(index) as i32 + self.min_y
+ }
+
+ pub fn get_first_available(&self, x: u8, z: u8) -> i32 {
+ self.get_first_available_at_index(Self::get_index(x, z))
+ }
+
+ pub fn get_highest_taken(&self, x: u8, z: u8) -> i32 {
+ self.get_first_available(x, z) - 1
+ }
+
+ pub fn set_height(&mut self, x: u8, z: u8, height: i32) {
+ self.data
+ .set(Self::get_index(x, z), (height - self.min_y) as u64);
+ }
+
+ /// Updates the heightmap with the given block state at the given position.
+ pub fn update(
+ &mut self,
+ pos: &ChunkBlockPos,
+ block_state: BlockState,
+ sections: &[Section],
+ ) -> bool {
+ let first_available_y = self.get_first_available(pos.x, pos.z);
+ if pos.y <= first_available_y - 2 {
+ return false;
+ }
+ if self.kind.is_opaque(block_state) {
+ // increase y
+ if pos.y >= first_available_y {
+ self.set_height(pos.x, pos.z, pos.y + 1);
+ return true;
+ }
+ } else if first_available_y - 1 == pos.y {
+ // decrease y
+ for y in (self.min_y..pos.y).rev() {
+ if self.kind.is_opaque(
+ get_block_state_from_sections(
+ sections,
+ &ChunkBlockPos::new(pos.x, y, pos.z),
+ self.min_y,
+ )
+ .unwrap_or_default(),
+ ) {
+ self.set_height(pos.x, pos.z, y + 1);
+ return true;
+ }
+ }
+
+ self.set_height(pos.x, pos.z, self.min_y);
+ return true;
+ }
+
+ false
+ }
+}
+
+impl FromStr for HeightmapKind {
+ type Err = ();
+
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ match s {
+ "WORLD_SURFACE_WG" => Ok(HeightmapKind::WorldSurfaceWg),
+ "WORLD_SURFACE" => Ok(HeightmapKind::WorldSurface),
+ "OCEAN_FLOOR_WG" => Ok(HeightmapKind::OceanFloorWg),
+ "OCEAN_FLOOR" => Ok(HeightmapKind::OceanFloor),
+ "MOTION_BLOCKING" => Ok(HeightmapKind::MotionBlocking),
+ "MOTION_BLOCKING_NO_LEAVES" => Ok(HeightmapKind::MotionBlockingNoLeaves),
+ _ => Err(()),
+ }
+ }
+}
+
+impl Display for HeightmapKind {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ match self {
+ HeightmapKind::WorldSurfaceWg => write!(f, "WORLD_SURFACE_WG"),
+ HeightmapKind::WorldSurface => write!(f, "WORLD_SURFACE"),
+ HeightmapKind::OceanFloorWg => write!(f, "OCEAN_FLOOR_WG"),
+ HeightmapKind::OceanFloor => write!(f, "OCEAN_FLOOR"),
+ HeightmapKind::MotionBlocking => write!(f, "MOTION_BLOCKING"),
+ HeightmapKind::MotionBlockingNoLeaves => write!(f, "MOTION_BLOCKING_NO_LEAVES"),
+ }
+ }
+}