Skip to content

Commit

Permalink
almost everything fixed, just some mutable refrence stuff missing
Browse files Browse the repository at this point in the history
  • Loading branch information
urisinger committed Feb 16, 2025
1 parent 36828f2 commit 0b09f89
Show file tree
Hide file tree
Showing 7 changed files with 73 additions and 143 deletions.
8 changes: 0 additions & 8 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,5 @@ uuid = { version = "1.13", features = ["serde", "v3", "v4"] }
derive_more = { version = "2.0", features = ["full"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
<<<<<<< HEAD
serde_with = "3.12"
=======
<<<<<<< HEAD
>>>>>>> 8d62705 (add biome entries serde and fix search tree)

async-trait = "0.1"
=======
serde_with = "3.12"
>>>>>>> d729080 (add biome entries serde)
28 changes: 19 additions & 9 deletions pumpkin-world/src/biome.rs
Original file line number Diff line number Diff line change
@@ -1,29 +1,37 @@
use std::sync::LazyLock;
use std::{borrow::BorrowMut, cell::RefCell, sync::LazyLock};

use pumpkin_data::chunk::Biome;

use crate::{
coordinates::BlockCoordinates,
generation::{
biome_search_tree::{BiomeEntries, SearchTree},
biome_search_tree::{BiomeEntries, SearchTree, TreeLeafNode},
noise_router::multi_noise_sampler::MultiNoiseSampler,
},
};

pub static BIOME_ENTRIES: LazyLock<BiomeEntries<Biome>> = LazyLock::new(|| {
serde_json::from_str(include_str!("../../assets/multi_noise.json"))
.expect("Could not parse synced_registries.json registry.")
pub static BIOME_ENTRIES: LazyLock<SearchTree<Biome>> = LazyLock::new(|| {
SearchTree::create(
serde_json::from_str::<BiomeEntries>(include_str!("../../assets/multi_noise.json"))
.expect("Could not parse synced_registries.json registry.")
.nodes,
)
.expect("entries cannot be empty")
});

thread_local! {
static LAST_RESULT_NODE: RefCell<Option<TreeLeafNode<Biome>>> = RefCell::new(None);
}

pub trait BiomeSupplier {
fn biome(&self, at: BlockCoordinates) -> Biome;
fn biome(&mut self, at: BlockCoordinates) -> Biome;
}

#[derive(Clone)]
pub struct DebugBiomeSupplier;

impl BiomeSupplier for DebugBiomeSupplier {
fn biome(&self, _at: BlockCoordinates) -> Biome {
fn biome(&mut self, _at: BlockCoordinates) -> Biome {
Biome::Plains
}
}
Expand All @@ -33,7 +41,9 @@ pub struct MultiNoiseBiomeSupplier<'a> {
}

impl BiomeSupplier for MultiNoiseBiomeSupplier<'_> {
fn biome(&self, at: BlockCoordinates) -> Biome {
BIOME_ENTRIES.find_biome(&self.noise.sample(at.x, at.y.0 as i32, at.z))
fn biome(&mut self, at: BlockCoordinates) -> Biome {
let point = self.noise.sample(at.x, at.y.0 as i32, at.z);
LAST_RESULT_NODE
.with_borrow_mut(|last_result| BIOME_ENTRIES.get(&point, last_result).expect("a"))
}
}
23 changes: 13 additions & 10 deletions pumpkin-world/src/generation/biome_search_tree.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::cmp::Ordering;

use pumpkin_data::chunk::Biome;
use serde::{Deserialize, Deserializer};

use super::noise_router::multi_noise_sampler::{to_long, NoiseValuePoint};
Expand Down Expand Up @@ -67,34 +68,36 @@ impl ParameterRange {
}

#[derive(Clone, Deserialize)]
pub struct BiomeEntries<T> {
nodes: Vec<(T, NoiseHypercube)>,
pub struct BiomeEntries {
pub nodes: Vec<(Biome, NoiseHypercube)>,
}

#[derive(Clone)]
pub struct SearchTree<T: Clone> {
root: TreeNode<T>,
last_result_node: Option<TreeLeafNode<T>>,
}

impl<T: Clone> SearchTree<T> {
pub fn create(entries: Vec<(NoiseHypercube, T)>) -> Option<Self> {
pub fn create(entries: Vec<(T, NoiseHypercube)>) -> Option<Self> {
if entries.is_empty() {
return None;
}

let leaves: Vec<TreeNode<T>> = entries
.into_iter()
.map(|(hypercube, value)| TreeNode::new_leaf(value, hypercube.to_parameters()))
.map(|(value, hypercube)| TreeNode::new_leaf(value, hypercube.to_parameters()))
.collect();

Some(SearchTree {
root: create_node(leaves),
last_result_node: None,
})
}

pub fn get(&mut self, point: &NoiseValuePoint) -> Option<T> {
pub fn get(
&self,
point: &NoiseValuePoint,
last_result_node: &mut Option<TreeLeafNode<T>>,
) -> Option<T> {
let point = &[
point.temperature,
point.humidity,
Expand All @@ -104,9 +107,9 @@ impl<T: Clone> SearchTree<T> {
point.weirdness,
0,
];
let result_node = self.root.get_node(point, &self.last_result_node);
let result_node = self.root.get_node(point, last_result_node);
let result = result_node.clone().map(|node| node.value);
self.last_result_node = result_node;
*last_result_node = result_node;
result
}
}
Expand Down Expand Up @@ -248,7 +251,7 @@ pub enum TreeNode<T: Clone> {
}

#[derive(Clone)]
struct TreeLeafNode<T: Clone> {
pub struct TreeLeafNode<T: Clone> {
value: T,
point: [ParameterRange; 7],
}
Expand Down
16 changes: 8 additions & 8 deletions pumpkin-world/src/generation/generator.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use noise::Perlin;
use pumpkin_core::math::vector2::Vector2;
use pumpkin_core::math::vector3::Vector3;
use pumpkin_data::chunk::Biome;
use pumpkin_util::math::vector2::Vector2;
use pumpkin_util::math::vector3::Vector3;

use crate::biome::Biome;
use crate::block::block_state::BlockState;
use crate::chunk::{ChunkBlocks, ChunkData};
use crate::coordinates::{BlockCoordinates, ChunkRelativeBlockCoordinates};
use crate::block::state::BlockState;
use crate::chunk::{ChunkData, Subchunks};
use crate::coordinates::{BlockCoordinates, ChunkRelativeBlockCoordinates, XZBlockCoordinates};
use crate::generation::Seed;

pub trait GeneratorInit {
Expand Down Expand Up @@ -37,12 +37,12 @@ pub(crate) trait PerlinTerrainGenerator: Sync + Send {

fn prepare_chunk(&self, at: &Vector2<i32>, perlin: &Perlin);

/// Dependens on the perlin noise height
/// Depends on the perlin noise height
fn generate_block(
&self,
coordinates: ChunkRelativeBlockCoordinates,
at: BlockCoordinates,
blocks: &mut ChunkBlocks,
subchunks: &mut Subchunks,
chunk_height: i16,
biome: Biome,
);
Expand Down
10 changes: 8 additions & 2 deletions pumpkin-world/src/generation/implementation/superflat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@ use pumpkin_data::chunk::Biome;
use pumpkin_util::math::vector2::Vector2;

use crate::{
biome::SuperflatBiomeGenerator,
block::state::BlockState,
coordinates::XZBlockCoordinates,
generation::{
generator::{GeneratorInit, TerrainGenerator},
generic_generator::GenericGenerator,
Expand All @@ -15,6 +13,14 @@ use crate::{
#[expect(dead_code)]
pub type SuperflatGenerator = GenericGenerator<SuperflatBiomeGenerator, SuperflatTerrainGenerator>;

pub(crate) struct SuperflatBiomeGenerator {}

impl GeneratorInit for SuperflatBiomeGenerator {
fn new(_: Seed) -> Self {
Self {}
}
}

pub(crate) struct SuperflatTerrainGenerator {}

impl GeneratorInit for SuperflatTerrainGenerator {
Expand Down
129 changes: 24 additions & 105 deletions pumpkin-world/src/generation/implementation/test.rs
Original file line number Diff line number Diff line change
@@ -1,60 +1,41 @@
use std::{
num::Wrapping,
ops::{AddAssign, SubAssign},
};

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

use crate::{
biome::{Biome, BiomeSupplierImpl},
block::block_state::BlockState,
chunk::{ChunkBlocks, ChunkData},
coordinates::{
ChunkRelativeBlockCoordinates, ChunkRelativeXZBlockCoordinates, XZBlockCoordinates,
},
chunk::{ChunkData, Subchunks},
coordinates::ChunkRelativeBlockCoordinates,
generation::{
generator::{GeneratorInit, TerrainGenerator},
proto_chunk::ProtoChunk,
Seed, WorldGenerator,
generator::GeneratorInit, noise_router::proto_noise_router::GlobalProtoNoiseRouter,
proto_chunk::ProtoChunk, GlobalRandomConfig, Seed, WorldGenerator,
},
noise_router::NOISE_ROUTER_ASTS,
WORLD_LOWEST_Y, WORLD_MAX_Y,
};

pub struct TestGenerator<B: BiomeSupplierImpl + Send + Sync, T: TerrainGenerator> {
biome_generator: B,
terrain_generator: T,
pub struct TestGenerator {
random_config: GlobalRandomConfig,
base_router: GlobalProtoNoiseRouter,
}

impl<B: BiomeSupplierImpl + GeneratorInit + Send + Sync, T: TerrainGenerator + GeneratorInit>
GeneratorInit for TestGenerator<B, T>
{
impl GeneratorInit for TestGenerator {
fn new(seed: Seed) -> Self {
let random_config = GlobalRandomConfig::new(seed.0);
let base_router =
GlobalProtoNoiseRouter::generate(&NOISE_ROUTER_ASTS.overworld, &random_config);
Self {
biome_generator: B::new(seed),
terrain_generator: T::new(seed),
random_config,
base_router,
}
}
}

impl<B: BiomeSupplierImpl + Send + Sync, T: TerrainGenerator> WorldGenerator
for TestGenerator<B, T>
{
impl WorldGenerator for TestGenerator {
fn generate_chunk(&self, at: Vector2<i32>) -> ChunkData {
let mut blocks = ChunkBlocks::default();
self.terrain_generator.prepare_chunk(&at);
let mut subchunks = Subchunks::Single(0);
let mut proto_chunk = ProtoChunk::new(at, &self.base_router, &self.random_config);
proto_chunk.populate_noise();

for x in 0..16u8 {
for z in 0..16u8 {
let biome = self.biome_generator.generate_biome(
ChunkRelativeXZBlockCoordinates {
x: x.into(),
z: z.into(),
}
.with_chunk_coordinates(at),
);

// TODO: This can be chunk specific
for y in (WORLD_LOWEST_Y..WORLD_MAX_Y).rev() {
let coordinates = ChunkRelativeBlockCoordinates {
Expand All @@ -63,81 +44,19 @@ impl<B: BiomeSupplierImpl + Send + Sync, T: TerrainGenerator> WorldGenerator
z: z.into(),
};

let block = self.terrain_generator.generate_block(
&at,
Vector3::new(x.into(), y.into(), z.into()),
biome,
);
let block =
proto_chunk.get_block_state(&Vector3::new(x.into(), y.into(), z.into()));

//println!("{:?}: {:?}", coordinates, block);
blocks.set_block(coordinates, block.state_id);
subchunks.set_block(coordinates, block.state_id);
}
}
}

self.terrain_generator.clean_chunk(&at);
ChunkData {
blocks,
subchunks,
heightmap: Default::default(),
position: at,
}
}
}

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

impl GeneratorInit for TestTerrainGenerator {
fn new(seed: Seed) -> Self {
Self {
chunks: DashMap::new(),
seed,
}
}
}

impl TerrainGenerator for TestTerrainGenerator {
fn prepare_chunk(&self, at: &Vector2<i32>) {
let entry = self.chunks.entry(*at);
match entry {
Entry::Vacant(entry) => {
let mut proto_chunk = ProtoChunk::new(*at, self.seed.0);
//let inst = std::time::Instant::now();
//println!("Populating chunk: {:?}", at);
proto_chunk.populate_noise();
//println!("Done populating chunk: {:?} ({:?})", at, inst.elapsed());
entry.insert((proto_chunk, Wrapping(1)));
}
Entry::Occupied(mut entry) => {
let (_, count) = entry.get_mut();
count.add_assign(1);
}
}
}

fn clean_chunk(&self, at: &Vector2<i32>) {
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.
fn generate_block(
&self,
chunk_pos: &Vector2<i32>,
local_pos: Vector3<i32>,
_: Biome,
) -> BlockState {
if let Some(entry) = self.chunks.get(chunk_pos) {
entry.0.get_block_state(&local_pos)
} else {
panic!("Chunk needs to exist")
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ pub struct MultiNoiseSampler<'a> {
}

impl<'a> MultiNoiseSampler<'a> {
pub fn sample(&mut self, biome_x: i32, biome_y: i32, biome_z: i32) -> NoiseValuePoint {
pub fn sample(&self, biome_x: i32, biome_y: i32, biome_z: i32) -> NoiseValuePoint {
let block_x = biome_coords::to_block(biome_x);
let block_y = biome_coords::to_block(biome_y);
let block_z = biome_coords::to_block(biome_z);
Expand Down

0 comments on commit 0b09f89

Please sign in to comment.