0
0
mirror of https://github.com/Pumpkin-MC/Pumpkin synced 2025-04-15 18:45:35 +00:00

change biomes parsing (#683)

* change biomes parsing

now we have more infos

* add temperature_modifier

* add ids
This commit is contained in:
Alexander Medvedev
2025-03-29 18:45:35 +00:00
committed by GitHub
parent 04ae9654a2
commit ce60881132
6 changed files with 11451 additions and 85 deletions
assets
pumpkin-data/build
pumpkin-world/src
biome
generation

File diff suppressed because it is too large Load Diff

@ -1,26 +1,147 @@
use heck::ToPascalCase;
use proc_macro2::TokenStream;
use std::collections::HashMap;
use heck::ToShoutySnakeCase;
use proc_macro2::{Span, TokenStream};
use quote::{format_ident, quote};
use serde::Deserialize;
use syn::LitInt;
#[derive(Deserialize)]
pub struct Biome {
has_precipitation: bool,
temperature: f32,
downfall: f32,
temperature_modifier: Option<TemperatureModifier>,
//carvers: Vec<String>,
features: Vec<Vec<String>>,
}
#[derive(Deserialize, Clone)]
#[serde(rename_all = "snake_case")]
pub enum TemperatureModifier {
None,
Frozen,
}
pub(crate) fn build() -> TokenStream {
println!("cargo:rerun-if-changed=../assets/biome.json");
let biomes: Vec<String> = serde_json::from_str(include_str!("../../assets/biome.json"))
.expect("Failed to parse biome.json");
let biomes: HashMap<String, Biome> =
serde_json::from_str(include_str!("../../assets/biome.json"))
.expect("Failed to parse biome.json");
let mut variants = TokenStream::new();
let mut type_to_name = TokenStream::new();
let mut name_to_type = TokenStream::new();
let mut type_to_id = TokenStream::new();
let mut id_to_type = TokenStream::new();
for (i, (name, biome)) in biomes.iter().enumerate() {
// let full_name = format!("minecraft:{name}");
let format_name = format_ident!("{}", name.to_shouty_snake_case());
let has_precipitation = biome.has_precipitation;
let temperature = biome.temperature;
let downfall = biome.downfall;
// let carvers = &biome.carvers;
let features = &biome.features;
let temperature_modifier = biome
.temperature_modifier
.clone()
.unwrap_or(TemperatureModifier::None);
let temperature_modifier = match temperature_modifier {
TemperatureModifier::Frozen => quote! { TemperatureModifier::Frozen },
TemperatureModifier::None => quote! { TemperatureModifier::None },
};
let index = LitInt::new(&i.to_string(), Span::call_site());
for status in biomes.iter() {
let full_name = format!("minecraft:{status}");
let name = format_ident!("{}", status.to_pascal_case());
variants.extend([quote! {
#[serde(rename = #full_name)]
#name,
pub const #format_name: Biome = Biome {
index: #index,
has_precipitation: #has_precipitation,
temperature: #temperature,
temperature_modifier: #temperature_modifier,
downfall: #downfall,
features: &[#(&[#(#features),*]),*]
};
}]);
type_to_name.extend(quote! { Self::#format_name => #name, });
name_to_type.extend(quote! { #name => Some(Self::#format_name), });
type_to_id.extend(quote! { Self::#format_name => #index, });
id_to_type.extend(quote! { #index => Some(Self::#format_name), });
}
quote! {
#[derive(Clone, Deserialize, Copy, Hash, PartialEq, Eq, Debug)]
pub enum Biome {
use serde::{de, Deserializer};
use std::fmt;
#[derive(Clone, Copy, PartialEq, Debug)]
pub struct Biome {
pub index: u8,
pub has_precipitation: bool,
pub temperature: f32,
pub temperature_modifier: TemperatureModifier,
pub downfall: f32,
// carvers: &'static [&str],
pub features: &'static [&'static [&'static str]]
}
impl<'de> Deserialize<'de> for Biome {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct BiomeVisitor;
impl de::Visitor<'_> for BiomeVisitor {
type Value = Biome;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a biome name as a string")
}
fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
self.visit_str(&v)
}
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
let biome = Biome::from_name(&value.replace("minecraft:", ""));
biome.ok_or_else(|| E::unknown_variant(value, &["unknown biome"]))
}
}
deserializer.deserialize_str(BiomeVisitor)
}
}
#[derive(Clone, Copy, PartialEq, Debug)]
pub enum TemperatureModifier {
None,
Frozen
}
impl Biome {
#variants
pub fn from_name(name: &str) -> Option<Self> {
match name {
#name_to_type
_ => None
}
}
pub const fn from_id(id: u16) -> Option<Self> {
match id {
#id_to_type
_ => None
}
}
}
}
}

@ -98,6 +98,6 @@ mod test {
&pumpkin_util::math::vector3::Vector3 { x: -24, y: 1, z: 8 },
&mut sampler,
);
assert_eq!(biome, Biome::Desert)
assert_eq!(biome, Biome::DESERT)
}
}

@ -25,7 +25,7 @@ impl GeneratorInit for SuperflatBiomeGenerator {
impl BiomeGenerator for SuperflatBiomeGenerator {
// TODO make generic over Biome and allow changing the Biome in the config.
fn generate_biome(&self, _: XZBlockCoordinates) -> Biome {
Biome::Plains
Biome::PLAINS
}
}

@ -166,7 +166,7 @@ impl<'a> ProtoChunk<'a> {
flat_block_map: vec![ChunkBlockState::AIR; CHUNK_AREA * height as usize]
.into_boxed_slice(),
flat_biome_map: vec![
Biome::Plains;
Biome::PLAINS;
biome_coords::from_block(CHUNK_DIM as usize)
* biome_coords::from_block(CHUNK_DIM as usize)
* biome_coords::from_block(height as usize)
@ -242,7 +242,7 @@ impl<'a> ProtoChunk<'a> {
if local_pos.y < 0
|| local_pos.y >= biome_coords::from_block(self.noise_sampler.height() as i32)
{
Biome::Plains
Biome::PLAINS
} else {
self.flat_biome_map[self.local_biome_pos_to_biome_index(&local_pos)]
}
@ -431,7 +431,7 @@ impl<'a> ProtoChunk<'a> {
};
let this_biome = self.get_biome_for_terrain_gen(&Vector3::new(x, biome_y, z));
if this_biome == Biome::ErodedBadlands {
if this_biome == Biome::ERODED_BADLANDS {
terrain_builder.place_badlands_pillar(
self,
x,
@ -495,7 +495,7 @@ impl<'a> ProtoChunk<'a> {
}
}
}
if this_biome == Biome::FrozenOcean || this_biome == Biome::DeepFrozenOcean {
if this_biome == Biome::FROZEN_OCEAN || this_biome == Biome::DEEP_FROZEN_OCEAN {
let min_y = estimate_surface_height(
&mut context,
&mut self.surface_height_estimate_sampler,

@ -4,6 +4,7 @@ use pumpkin_util::{
random::RandomDeriver,
};
use serde::Deserialize;
use terrain::SurfaceTerrainBuilder;
use crate::generation::{positions::chunk_pos, section_coords};
@ -65,7 +66,7 @@ impl<'a> MaterialRuleContext<'a> {
terrain_builder,
fluid_height: 0,
block_pos: Vector3::new(0, 0, 0),
biome: Biome::Plains,
biome: Biome::PLAINS,
run_depth: 0,
secondary_depth: 0.0,
surface_noise: noise_builder.get_noise_sampler_for_id("surface"),