Skip to content

Commit

Permalink
some chunk gen optimizations
Browse files Browse the repository at this point in the history
  • Loading branch information
kralverde committed Nov 23, 2024
1 parent e898629 commit 5286d88
Show file tree
Hide file tree
Showing 7 changed files with 62 additions and 43 deletions.
18 changes: 10 additions & 8 deletions pumpkin-world/src/block/block_state.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,23 @@
use super::block_registry::{get_block, get_block_and_state_by_state_id};
use super::block_registry::{get_block, get_state_by_state_id};

#[derive(Clone, Copy, Debug)]
pub struct BlockState {
pub state_id: u16,
pub block_id: u16,
}

impl BlockState {
pub const AIR: BlockState = BlockState { state_id: 0 };
pub const AIR: BlockState = BlockState {
state_id: 0,
block_id: 0,
};

/// Get a Block from the Vanilla Block registry at Runtime
pub fn new(registry_id: &str) -> Option<Self> {
let block = get_block(registry_id);
block.map(|block| Self {
state_id: block.default_state_id,
block_id: block.id,
})
}

Expand All @@ -22,15 +27,12 @@ impl BlockState {

#[inline]
pub fn is_air(&self) -> bool {
let (_, state) = get_block_and_state_by_state_id(self.state_id).unwrap();
state.air
get_state_by_state_id(self.state_id).unwrap().air
}

#[inline]
pub fn of_block(&self, block_id: &str) -> bool {
let (this_block, _) = get_block_and_state_by_state_id(self.state_id).unwrap();
let check_block = get_block(block_id).unwrap();
this_block.id == check_block.id
pub fn of_block(&self, block_id: u16) -> bool {
self.block_id == block_id
}
}

Expand Down
13 changes: 5 additions & 8 deletions pumpkin-world/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use block::BlockState;
use world_gen::{
chunk_noise::ChunkNoiseGenerator,
chunk_noise::{ChunkNoiseGenerator, LAVA_BLOCK, WATER_BLOCK},
generation_shapes::GenerationShape,
noise::{config::NoiseConfig, router::OVERWORLD_NOISE_ROUTER},
proto_chunk::StandardChunkFluidLevelSampler,
Expand All @@ -22,16 +22,13 @@ pub const WORLD_LOWEST_Y: i16 = -64;
pub const WORLD_MAX_Y: i16 = WORLD_HEIGHT as i16 - WORLD_LOWEST_Y.abs();
pub const DIRECT_PALETTE_BITS: u32 = 15;

const LAVA: &str = "minecraft:lava";
const WATER: &str = "minecraft:water";

// TODO: is there a way to do in-file benches?
pub fn bench_create_chunk_noise_overworld() {
let config = NoiseConfig::new(0, &OVERWORLD_NOISE_ROUTER);
let generation_shape = GenerationShape::SURFACE;
let sampler = FluidLevelSampler::Chunk(StandardChunkFluidLevelSampler {
bottom_fluid: FluidLevel::new(-54, BlockState::new(LAVA).unwrap()),
top_fluid: FluidLevel::new(62, BlockState::new(WATER).unwrap()),
bottom_fluid: FluidLevel::new(-54, *LAVA_BLOCK),
top_fluid: FluidLevel::new(62, *WATER_BLOCK),
});

ChunkNoiseGenerator::new(
Expand All @@ -49,8 +46,8 @@ pub fn bench_create_chunk_noise_overworld() {
pub fn bench_create_and_populate_noise() {
let config = NoiseConfig::new(0, &OVERWORLD_NOISE_ROUTER);
let fluid_sampler = FluidLevelSampler::Chunk(StandardChunkFluidLevelSampler {
bottom_fluid: FluidLevel::new(-54, BlockState::new(LAVA).unwrap()),
top_fluid: FluidLevel::new(62, BlockState::new(WATER).unwrap()),
bottom_fluid: FluidLevel::new(-54, *LAVA_BLOCK),
top_fluid: FluidLevel::new(62, *WATER_BLOCK),
});
let generation_shape = GenerationShape::SURFACE;

Expand Down
7 changes: 7 additions & 0 deletions pumpkin-world/src/world_gen/chunk_noise.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::{collections::HashMap, hash::Hash, mem, num::Wrapping, ops::AddAssign, sync::Arc};

use lazy_static::lazy_static;
use num_traits::Zero;
use parking_lot::Mutex;
use pumpkin_core::math::{floor_div, vector2::Vector2, vector3::Vector3};
Expand Down Expand Up @@ -40,6 +41,12 @@ use super::{
},
};

lazy_static! {
pub static ref STONE_BLOCK: BlockState = BlockState::new("minecraft:stone").unwrap();
pub static ref LAVA_BLOCK: BlockState = BlockState::new("minecraft:lava").unwrap();
pub static ref WATER_BLOCK: BlockState = BlockState::new("minecraft:water").unwrap();
}

pub struct ChunkCacheOnceFunction<R: ComponentReference<ChunkNoiseState>> {
delegate: R,
sample_unique_index: u64,
Expand Down
20 changes: 15 additions & 5 deletions pumpkin-world/src/world_gen/implementation/test.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use std::{num::Wrapping, ops::SubAssign};

use dashmap::{DashMap, Entry};
use num_traits::Zero;
use pumpkin_core::math::{vector2::Vector2, vector3::Vector3};

use crate::{
Expand Down Expand Up @@ -91,7 +94,7 @@ impl BiomeGenerator for TestBiomeGenerator {
}

pub(crate) struct TestTerrainGenerator {
chunks: DashMap<Vector2<i32>, ProtoChunk>,
chunks: DashMap<Vector2<i32>, (ProtoChunk, Wrapping<u8>)>,
}

impl GeneratorInit for TestTerrainGenerator {
Expand All @@ -111,12 +114,19 @@ impl TerrainGenerator for TestTerrainGenerator {
//println!("Populating chunk: {:?}", at);
proto_chunk.populate_noise();
//println!("Done populating chunk: {:?} ({:?})", at, inst.elapsed());
entry.insert(proto_chunk);
entry.insert((proto_chunk, Wrapping(1)));
}
}

fn clean_chunk(&self, at: &Vector2<i32>) {
self.chunks.remove(at);
let entry = self.chunks.entry(*at);
if let Entry::Occupied(mut entry) = entry {
let (_, count) = entry.get_mut();
count.sub_assign(1);
if count.is_zero() {
entry.remove();
}
}
}

// TODO allow specifying which blocks should be at which height in the config.
Expand All @@ -126,8 +136,8 @@ impl TerrainGenerator for TestTerrainGenerator {
local_pos: Vector3<i32>,
_: Biome,
) -> BlockState {
if let Some(chunk) = self.chunks.get(chunk_pos) {
chunk.get_block_state(&local_pos)
if let Some(entry) = self.chunks.get(chunk_pos) {
entry.0.get_block_state(&local_pos)
} else {
panic!("Chunk needs to exist")
}
Expand Down
4 changes: 4 additions & 0 deletions pumpkin-world/src/world_gen/positions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,22 @@ pub mod block_pos {
BITS_X, BITS_Y, BITS_Z, BIT_SHIFT_X, BIT_SHIFT_Z, SIZE_BITS_X, SIZE_BITS_Y, SIZE_BITS_Z,
};

#[inline]
pub const fn unpack_x(packed: u64) -> i32 {
(((packed as i64) << (64 - BIT_SHIFT_X - SIZE_BITS_X)) >> (64 - SIZE_BITS_X)) as i32
}

#[inline]
pub const fn unpack_y(packed: u64) -> i32 {
(((packed as i64) << (64 - SIZE_BITS_Y)) >> (64 - SIZE_BITS_Y)) as i32
}

#[inline]
pub const fn unpack_z(packed: u64) -> i32 {
(((packed as i64) << (64 - BIT_SHIFT_Z - SIZE_BITS_Z)) >> (64 - SIZE_BITS_Z)) as i32
}

#[inline]
pub const fn packed(vec: &Vector3<i32>) -> u64 {
let mut result = 0i64;
// Need to go to i64 first to conserve sign
Expand Down
15 changes: 5 additions & 10 deletions pumpkin-world/src/world_gen/proto_chunk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use crate::{
};

use super::{
chunk_noise::ChunkNoiseGenerator,
chunk_noise::{ChunkNoiseGenerator, LAVA_BLOCK, STONE_BLOCK, WATER_BLOCK},
positions::chunk_pos::{start_block_x, start_block_z},
sampler::{FluidLevel, FluidLevelSamplerImpl},
};
Expand Down Expand Up @@ -45,9 +45,6 @@ pub struct ProtoChunk {
// may want to use chunk status
}

const LAVA: &str = "minecraft:lava";
const WATER: &str = "minecraft:water";

impl ProtoChunk {
pub fn new(chunk_pos: Vector2<i32>) -> Self {
// TODO: Don't hardcode these
Expand All @@ -61,8 +58,8 @@ impl ProtoChunk {

// TODO: Customize these
let sampler = FluidLevelSampler::Chunk(StandardChunkFluidLevelSampler {
bottom_fluid: FluidLevel::new(-54, BlockState::new(LAVA).unwrap()),
top_fluid: FluidLevel::new(62, BlockState::new(WATER).unwrap()),
bottom_fluid: FluidLevel::new(-54, *LAVA_BLOCK),
top_fluid: FluidLevel::new(62, *WATER_BLOCK),
});

let sampler = ChunkNoiseGenerator::new(
Expand Down Expand Up @@ -152,10 +149,8 @@ impl ProtoChunk {
self.sampler.interpolate_z(block_z, delta_z);

// TODO: Change default block
let block_state = self
.sampler
.sample_block_state()
.unwrap_or(BlockState::new("minecraft:stone").unwrap());
let block_state =
self.sampler.sample_block_state().unwrap_or(*STONE_BLOCK);
//log::debug!("Sampled block state in {:?}", inst.elapsed());

let local_pos = Vector3 {
Expand Down
28 changes: 16 additions & 12 deletions pumpkin-world/src/world_gen/sampler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use pumpkin_core::{
use crate::block::BlockState;

use super::{
chunk_noise::{ChunkNoiseDensityFunctions, ChunkNoiseState},
chunk_noise::{ChunkNoiseDensityFunctions, ChunkNoiseState, LAVA_BLOCK, WATER_BLOCK},
noise::{
clamped_map,
density::{
Expand All @@ -22,9 +22,6 @@ use super::{
section_coords,
};

const LAVA: &str = "minecraft:lava";
const WATER: &str = "minecraft:water";

pub enum BlockStateSampler {
Aquifer(AquiferSampler),
Ore(OreVeinSampler),
Expand Down Expand Up @@ -211,6 +208,7 @@ impl WorldAquiferSampler {
}
}

#[inline]
fn index(&self, x: i32, y: i32, z: i32) -> usize {
let i = (x - self.start_x) as usize;
let j = (y - self.start_y as i32) as usize;
Expand All @@ -219,6 +217,7 @@ impl WorldAquiferSampler {
(j * self.size_z + k) * self.size_x + i
}

#[inline]
fn max_distance(i: i32, a: i32) -> f64 {
1f64 - ((a - i).abs() as f64) / 25f64
}
Expand All @@ -235,8 +234,10 @@ impl WorldAquiferSampler {
let block_state1 = level_1.get_block_state(y);
let block_state2 = level_2.get_block_state(y);

if (!block_state1.of_block(LAVA) || !block_state2.of_block(WATER))
&& (!block_state1.of_block(WATER) || !block_state2.of_block(LAVA))
if (!block_state1.of_block(LAVA_BLOCK.block_id)
|| !block_state2.of_block(WATER_BLOCK.block_id))
&& (!block_state1.of_block(WATER_BLOCK.block_id)
|| !block_state2.of_block(LAVA_BLOCK.block_id))
{
let level_diff = (level_1.max_y - level_2.max_y).abs();
if level_diff == 0 {
Expand Down Expand Up @@ -446,7 +447,10 @@ impl WorldAquiferSampler {
level: i32,
env: &ChunkNoiseState,
) -> BlockState {
if level <= -10 && level != MIN_HEIGHT_CELL && !default_level.state.of_block(LAVA) {
if level <= -10
&& level != MIN_HEIGHT_CELL
&& !default_level.state.of_block(LAVA_BLOCK.block_id)
{
let x = floor_div(block_x, 64);
let y = floor_div(block_y, 40);
let z = floor_div(block_z, 64);
Expand All @@ -456,7 +460,7 @@ impl WorldAquiferSampler {
.sample_mut(&NoisePos::Unblended(UnblendedNoisePos::new(x, y, z)), env);

if sample.abs() > 0.3f64 {
return BlockState::new(LAVA).unwrap();
return *LAVA_BLOCK;
}
}

Expand Down Expand Up @@ -504,8 +508,8 @@ impl AquiferSamplerImpl for WorldAquiferSampler {
let k = pos.z();

let fluid_level = self.fluid_level.get_fluid_level(i, j, k);
if fluid_level.get_block_state(j).of_block(LAVA) {
Some(BlockState::new(LAVA).unwrap())
if fluid_level.get_block_state(j).of_block(LAVA_BLOCK.block_id) {
Some(*LAVA_BLOCK)
} else {
let l = floor_div(i - 5, 16);
let m = floor_div(j + 1, 12);
Expand Down Expand Up @@ -586,12 +590,12 @@ impl AquiferSamplerImpl for WorldAquiferSampler {
if d <= 0f64 {
// TODO: Handle fluid tick
Some(block_state)
} else if block_state.of_block(WATER)
} else if block_state.of_block(WATER_BLOCK.block_id)
&& self
.fluid_level
.get_fluid_level(i, j - 1, k)
.get_block_state(j - 1)
.of_block(LAVA)
.of_block(LAVA_BLOCK.block_id)
{
Some(block_state)
} else {
Expand Down

0 comments on commit 5286d88

Please sign in to comment.