ci: add Windows Arm and macOS Intel

This commit is contained in:
Alexander Medvedev 2025-12-09 19:29:57 +01:00
parent 92fe87e921
commit fba4d405ac
64 changed files with 716 additions and 786 deletions

View File

@ -41,7 +41,7 @@ jobs:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
strategy: strategy:
matrix: matrix:
os: [ubuntu-latest, windows-latest, macos-latest, ubuntu-24.04-arm] os: [ubuntu-latest, ubuntu-24.04-arm, windows-latest, windows-11-arm, macos-latest, macos-15-intel]
toolchain: toolchain:
- stable - stable
steps: steps:
@ -55,7 +55,7 @@ jobs:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
strategy: strategy:
matrix: matrix:
os: [ubuntu-latest, windows-latest, macos-latest, ubuntu-24.04-arm] os: [ubuntu-latest, ubuntu-24.04-arm, windows-latest, windows-11-arm, macos-latest, macos-15-intel]
toolchain: toolchain:
- stable - stable
steps: steps:

View File

@ -886,9 +886,8 @@ pub(crate) fn build() -> TokenStream {
matches!(state_id, #random_tick_state_ids) matches!(state_id, #random_tick_state_ids)
} }
pub fn blocks_movement(block_state: &BlockState) -> bool { pub fn blocks_movement(block_state: &BlockState, block: &Block) -> bool {
if block_state.is_solid() { if block_state.is_solid() {
let block = Block::from_state_id(block_state.id);
return block != &Block::COBWEB && block != &Block::BAMBOO_SAPLING; return block != &Block::COBWEB && block != &Block::BAMBOO_SAPLING;
} }
false false

View File

@ -22,8 +22,8 @@ pub struct CLevelChunk<'a> {
impl<'a> PacketWrite for CLevelChunk<'a> { impl<'a> PacketWrite for CLevelChunk<'a> {
fn write<W: Write>(&self, writer: &mut W) -> Result<(), Error> { fn write<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
VarInt(self.chunk.position.x).write(writer)?; VarInt(self.chunk.x).write(writer)?;
VarInt(self.chunk.position.y).write(writer)?; VarInt(self.chunk.z).write(writer)?;
VarInt(self.dimension).write(writer)?; VarInt(self.dimension).write(writer)?;
let sub_chunk_count = self.chunk.section.sections.len() as u32; let sub_chunk_count = self.chunk.section.sections.len() as u32;

View File

@ -134,7 +134,7 @@ impl UDPNetworkDecoder {
err => PacketDecodeError::MalformedLength(err.to_string()), err => PacketDecodeError::MalformedLength(err.to_string()),
})?; })?;
let packet_len = packet_len.0 as u64; let packet_len = packet_len.0 as usize;
let var_header = VarUInt::decode(&mut reader)?; let var_header = VarUInt::decode(&mut reader)?;
@ -157,7 +157,7 @@ impl UDPNetworkDecoder {
let gamepacket_id = (header & 0x3FF) as u16; // 0x3FF is 10 bits set to 1 let gamepacket_id = (header & 0x3FF) as u16; // 0x3FF is 10 bits set to 1
let payload = reader let payload = reader
.read_boxed_slice(packet_len as usize - var_header.written_size()) .read_boxed_slice(packet_len - var_header.written_size())
.map_err(|err| PacketDecodeError::FailedDecompression(err.to_string()))?; .map_err(|err| PacketDecodeError::FailedDecompression(err.to_string()))?;
Ok(RawPacket { Ok(RawPacket {

View File

@ -17,9 +17,9 @@ impl ClientPacket for CChunkData<'_> {
let mut write = write; let mut write = write;
// Chunk X // Chunk X
write.write_i32_be(self.0.position.x)?; write.write_i32_be(self.0.x)?;
// Chunk Z // Chunk Z
write.write_i32_be(self.0.position.y)?; write.write_i32_be(self.0.z)?;
let heightmaps = &self.0.heightmap; let heightmaps = &self.0.heightmap;
write.write_var_int(&VarInt(3))?; // Map size write.write_var_int(&VarInt(3))?; // Map size

View File

@ -43,7 +43,7 @@ impl Serialize for CMultiBlockUpdate {
))?; ))?;
for (position, state_id) in &self.positions_to_state_ids { for (position, state_id) in &self.positions_to_state_ids {
let long = ((*state_id as u64) << 12) | (*position as u64); let long = (*state_id as u64) << 12 | (*position as u64);
let var_long = VarLong::from(long as i64); let var_long = VarLong::from(long as i64);
tuple.serialize_element(&var_long)?; tuple.serialize_element(&var_long)?;
} }

View File

@ -2,10 +2,7 @@ use std::sync::LazyLock;
use serde::Deserialize; use serde::Deserialize;
use crate::{ use crate::{noise::simplex::OctaveSimplexNoiseSampler, random::legacy_rand::LegacyRand};
math::vector3::Vector3, noise::simplex::OctaveSimplexNoiseSampler,
random::legacy_rand::LegacyRand,
};
pub static TEMPERATURE_NOISE: LazyLock<OctaveSimplexNoiseSampler> = LazyLock::new(|| { pub static TEMPERATURE_NOISE: LazyLock<OctaveSimplexNoiseSampler> = LazyLock::new(|| {
let mut rand = LegacyRand::from_seed(1234); let mut rand = LegacyRand::from_seed(1234);
@ -30,20 +27,17 @@ pub enum TemperatureModifier {
} }
impl TemperatureModifier { impl TemperatureModifier {
pub fn convert_temperature(&self, pos: &Vector3<i32>, temperature: f32) -> f32 { pub fn convert_temperature(&self, x: f64, z: f64, temperature: f32) -> f32 {
match self { match self {
TemperatureModifier::None => temperature, TemperatureModifier::None => temperature,
TemperatureModifier::Frozen => { TemperatureModifier::Frozen => {
let frozen_ocean_sample = let frozen_ocean_sample =
FROZEN_OCEAN_NOISE.sample(pos.x as f64 * 0.05, pos.z as f64 * 0.05, false) FROZEN_OCEAN_NOISE.sample(x * 0.05, z * 0.05, false) * 7.0;
* 7.0; let foliage_sample = FOLIAGE_NOISE.sample(x * 0.2, z * 0.2, false);
let foliage_sample =
FOLIAGE_NOISE.sample(pos.x as f64 * 0.2, pos.z as f64 * 0.2, false);
let threshold = frozen_ocean_sample + foliage_sample; let threshold = frozen_ocean_sample + foliage_sample;
if threshold < 0.3 { if threshold < 0.3 {
let foliage_sample = let foliage_sample = FOLIAGE_NOISE.sample(x * 0.09, z * 0.09, false);
FOLIAGE_NOISE.sample(pos.x as f64 * 0.09, pos.z as f64 * 0.09, false);
if foliage_sample < 0.8 { if foliage_sample < 0.8 {
return 0.2f32; return 0.2f32;
} }
@ -81,19 +75,18 @@ impl Weather {
} }
/// This is an expensive function and should be cached /// This is an expensive function and should be cached
pub fn compute_temperature(&self, pos: &Vector3<i32>, sea_level: i32) -> f32 { pub fn compute_temperature(&self, x: f64, y: i32, z: f64, sea_level: i32) -> f32 {
let modified_temperature = self let modified_temperature =
.temperature_modifier self.temperature_modifier
.convert_temperature(pos, self.temperature); .convert_temperature(x, z, self.temperature);
let offset_sea_level = sea_level + 17; let offset_sea_level = sea_level + 17;
if pos.y > offset_sea_level { if y > offset_sea_level {
let temperature_noise = let temperature_noise =
(TEMPERATURE_NOISE.sample(pos.x as f64 / 8.0, pos.z as f64 / 8.0, false) * 8.0) (TEMPERATURE_NOISE.sample(x / 8.0, z / 8.0, false) * 8.0) as f32;
as f32;
modified_temperature modified_temperature
- (temperature_noise + pos.y as f32 - offset_sea_level as f32) * 0.05f32 / 40.0f32 - (temperature_noise + y as f32 - offset_sea_level as f32) * 0.05f32 / 40.0f32
} else { } else {
modified_temperature modified_temperature
} }

View File

@ -71,13 +71,7 @@ pub const fn floor_log2(value: u32) -> u8 {
} }
pub const fn smallest_encompassing_power_of_two(value: u32) -> u32 { pub const fn smallest_encompassing_power_of_two(value: u32) -> u32 {
let mut i = value - 1; value.next_power_of_two()
i |= i >> 1;
i |= i >> 2;
i |= i >> 4;
i |= i >> 8;
i |= i >> 16;
i + 1
} }
#[inline] #[inline]

View File

@ -82,7 +82,7 @@ pub struct TextComponentBase {
/// Style of the text. Bold, Italic, underline, Color... /// Style of the text. Bold, Italic, underline, Color...
/// Also has `ClickEvent /// Also has `ClickEvent
#[serde(flatten)] #[serde(flatten)]
pub style: Style, pub style: Box<Style>,
#[serde(default, skip_serializing_if = "Vec::is_empty")] #[serde(default, skip_serializing_if = "Vec::is_empty")]
/// Extra text components /// Extra text components
pub extra: Vec<TextComponentBase>, pub extra: Vec<TextComponentBase>,
@ -144,7 +144,7 @@ impl TextComponentBase {
// Divide the translation into slices and inserts the substitutions // Divide the translation into slices and inserts the substitutions
let component = match self.content { let component = match self.content {
TextContent::Custom { key, with, locale } => { TextContent::Custom { key, with, locale } => {
let translation = get_translation(key, locale); let translation = get_translation(&key, locale);
let mut translation_parent = translation.clone(); let mut translation_parent = translation.clone();
let mut translation_slices = vec![]; let mut translation_slices = vec![];
@ -171,7 +171,7 @@ impl TextComponentBase {
) )
}, },
}, },
style: Style::default(), style: Box::new(Style::default()),
extra: vec![], extra: vec![],
}); });
} }
@ -242,7 +242,7 @@ impl TextComponent {
pub fn text<P: Into<Cow<'static, str>>>(plain: P) -> Self { pub fn text<P: Into<Cow<'static, str>>>(plain: P) -> Self {
Self(TextComponentBase { Self(TextComponentBase {
content: TextContent::Text { text: plain.into() }, content: TextContent::Text { text: plain.into() },
style: Style::default(), style: Box::new(Style::default()),
extra: vec![], extra: vec![],
}) })
} }
@ -256,7 +256,7 @@ impl TextComponent {
translate: key.into(), translate: key.into(),
with: with.into().into_iter().map(|x| x.0).collect(), with: with.into().into_iter().map(|x| x.0).collect(),
}, },
style: Style::default(), style: Box::new(Style::default()),
extra: vec![], extra: vec![],
}) })
} }
@ -275,7 +275,7 @@ impl TextComponent {
locale, locale,
with: with.into().into_iter().map(|x| x.0).collect(), with: with.into().into_iter().map(|x| x.0).collect(),
}, },
style: Style::default(), style: Box::new(Style::default()),
extra: vec![], extra: vec![],
}) })
} }
@ -288,7 +288,7 @@ impl TextComponent {
pub fn from_content(content: TextContent) -> Self { pub fn from_content(content: TextContent) -> Self {
Self(TextComponentBase { Self(TextComponentBase {
content, content,
style: Style::default(), style: Box::new(Style::default()),
extra: vec![], extra: vec![],
}) })
} }
@ -296,7 +296,7 @@ impl TextComponent {
pub fn add_text<P: Into<Cow<'static, str>>>(mut self, text: P) -> Self { pub fn add_text<P: Into<Cow<'static, str>>>(mut self, text: P) -> Self {
self.0.extra.push(TextComponentBase { self.0.extra.push(TextComponentBase {
content: TextContent::Text { text: text.into() }, content: TextContent::Text { text: text.into() },
style: Style::default(), style: Box::new(Style::default()),
extra: vec![], extra: vec![],
}); });
self self
@ -317,7 +317,7 @@ impl TextComponent {
content: TextContent::Text { content: TextContent::Text {
text: Cow::Owned(with_resolved_fields), text: Cow::Owned(with_resolved_fields),
}, },
style: Style::default(), style: Box::new(Style::default()),
extra: vec![], extra: vec![],
}) })
} }

View File

@ -57,9 +57,9 @@ pub fn add_translation_file<P: Into<String>>(namespace: P, file_path: P, locale:
} }
} }
pub fn get_translation<P: Into<String>>(key: P, locale: Locale) -> String { pub fn get_translation(key: &str, locale: Locale) -> String {
let translations = TRANSLATIONS.lock().unwrap(); let translations = TRANSLATIONS.lock().unwrap();
let key = key.into().to_lowercase(); let key = key.to_lowercase();
match translations[locale as usize].get(&key) { match translations[locale as usize].get(&key) {
Some(translation) => translation.clone(), Some(translation) => translation.clone(),
None => match translations[Locale::EnUs as usize].get(&key) { None => match translations[Locale::EnUs as usize].get(&key) {
@ -96,7 +96,7 @@ pub fn reorder_substitutions(
.iter() .iter()
.map(|_| TextComponentBase { .map(|_| TextComponentBase {
content: TextContent::Text { text: "".into() }, content: TextContent::Text { text: "".into() },
style: Style::default(), style: Box::new(Style::default()),
extra: vec![], extra: vec![],
}) })
.collect(); .collect();
@ -138,7 +138,7 @@ pub fn translation_to_pretty<P: Into<Cow<'static, str>>>(
locale: Locale, locale: Locale,
with: Vec<TextComponentBase>, with: Vec<TextComponentBase>,
) -> String { ) -> String {
let mut translation = get_translation(namespaced_key.into(), locale); let mut translation = get_translation(&namespaced_key.into(), locale);
if with.is_empty() || !translation.contains('%') { if with.is_empty() || !translation.contains('%') {
return translation; return translation;
} }
@ -162,7 +162,7 @@ pub fn get_translation_text<P: Into<Cow<'static, str>>>(
locale: Locale, locale: Locale,
with: Vec<TextComponentBase>, with: Vec<TextComponentBase>,
) -> String { ) -> String {
let mut translation = get_translation(namespaced_key.into(), locale); let mut translation = get_translation(&namespaced_key.into(), locale);
if with.is_empty() || !translation.contains('%') { if with.is_empty() || !translation.contains('%') {
return translation; return translation;
} }

View File

@ -1,5 +1,4 @@
use pumpkin_data::chunk::Biome; use pumpkin_data::chunk::Biome;
use pumpkin_util::math::vector3::Vector3;
use crate::{ use crate::{
biome::BiomeSupplier, biome::BiomeSupplier,
@ -21,13 +20,15 @@ impl TheEndBiomeSupplier {
impl BiomeSupplier for TheEndBiomeSupplier { impl BiomeSupplier for TheEndBiomeSupplier {
fn biome( fn biome(
global_biome_pos: &Vector3<i32>, x: i32,
y: i32,
z: i32,
noise: &mut MultiNoiseSampler<'_>, noise: &mut MultiNoiseSampler<'_>,
_dimension: Dimension, _dimension: Dimension,
) -> &'static Biome { ) -> &'static Biome {
let x = biome_coords::to_block(global_biome_pos.x); let x = biome_coords::to_block(x);
let y = biome_coords::to_block(global_biome_pos.y); let y = biome_coords::to_block(y);
let z = biome_coords::to_block(global_biome_pos.z); let z = biome_coords::to_block(z);
let section_x = section_coords::block_to_section(x); let section_x = section_coords::block_to_section(x);
let section_z = section_coords::block_to_section(z); let section_z = section_coords::block_to_section(z);
if section_x * section_x + section_z * section_z <= 4096 { if section_x * section_x + section_z * section_z <= 4096 {

View File

@ -3,7 +3,6 @@ use std::cell::RefCell;
use enum_dispatch::enum_dispatch; use enum_dispatch::enum_dispatch;
use pumpkin_data::chunk::{Biome, BiomeTree, NETHER_BIOME_SOURCE, OVERWORLD_BIOME_SOURCE}; use pumpkin_data::chunk::{Biome, BiomeTree, NETHER_BIOME_SOURCE, OVERWORLD_BIOME_SOURCE};
use pumpkin_util::math::vector3::Vector3;
use crate::{ use crate::{
dimension::Dimension, generation::noise::router::multi_noise_sampler::MultiNoiseSampler, dimension::Dimension, generation::noise::router::multi_noise_sampler::MultiNoiseSampler,
@ -19,7 +18,9 @@ thread_local! {
#[enum_dispatch] #[enum_dispatch]
pub trait BiomeSupplier { pub trait BiomeSupplier {
fn biome( fn biome(
at: &Vector3<i32>, x: i32,
y: i32,
z: i32,
noise: &mut MultiNoiseSampler<'_>, noise: &mut MultiNoiseSampler<'_>,
dimension: Dimension, dimension: Dimension,
) -> &'static Biome; ) -> &'static Biome;
@ -29,7 +30,9 @@ pub struct MultiNoiseBiomeSupplier;
impl BiomeSupplier for MultiNoiseBiomeSupplier { impl BiomeSupplier for MultiNoiseBiomeSupplier {
fn biome( fn biome(
global_biome_pos: &Vector3<i32>, x: i32,
y: i32,
z: i32,
noise: &mut MultiNoiseSampler<'_>, noise: &mut MultiNoiseSampler<'_>,
dimension: Dimension, dimension: Dimension,
) -> &'static Biome { ) -> &'static Biome {
@ -38,7 +41,7 @@ impl BiomeSupplier for MultiNoiseBiomeSupplier {
Dimension::Nether => &NETHER_BIOME_SOURCE, Dimension::Nether => &NETHER_BIOME_SOURCE,
Dimension::End => unreachable!(), // Use TheEndBiomeSupplier Dimension::End => unreachable!(), // Use TheEndBiomeSupplier
}; };
let point = noise.sample(global_biome_pos.x, global_biome_pos.y, global_biome_pos.z); let point = noise.sample(x, y, z);
let point_list = point.convert_to_list(); let point_list = point.convert_to_list();
LAST_RESULT_NODE.with_borrow_mut(|last_result| source.get(&point_list, last_result)) LAST_RESULT_NODE.with_borrow_mut(|last_result| source.get(&point_list, last_result))
} }
@ -54,10 +57,7 @@ pub fn hash_seed(seed: u64) -> i64 {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use pumpkin_data::{chunk::Biome, noise_router::OVERWORLD_BASE_NOISE_ROUTER}; use pumpkin_data::{chunk::Biome, noise_router::OVERWORLD_BASE_NOISE_ROUTER};
use pumpkin_util::{ use pumpkin_util::read_data_from_file;
math::{vector2::Vector2, vector3::Vector3},
read_data_from_file,
};
use serde::Deserialize; use serde::Deserialize;
use crate::{ use crate::{
@ -84,11 +84,7 @@ mod test {
let multi_noise_config = MultiNoiseSamplerBuilderOptions::new(1, 1, 1); let multi_noise_config = MultiNoiseSamplerBuilderOptions::new(1, 1, 1);
let mut sampler = let mut sampler =
MultiNoiseSampler::generate(&noise_router.multi_noise, &multi_noise_config); MultiNoiseSampler::generate(&noise_router.multi_noise, &multi_noise_config);
let biome = MultiNoiseBiomeSupplier::biome( let biome = MultiNoiseBiomeSupplier::biome(-24, 1, 8, &mut sampler, Dimension::Overworld);
&pumpkin_util::math::vector3::Vector3 { x: -24, y: 1, z: 8 },
&mut sampler,
Dimension::Overworld,
);
assert_eq!(biome, &Biome::DESERT) assert_eq!(biome, &Biome::DESERT)
} }
@ -115,14 +111,20 @@ mod test {
let default_block = surface_settings.default_block.get_state(); let default_block = surface_settings.default_block.get_state();
for data in expected_data.into_iter() { for data in expected_data.into_iter() {
let chunk_pos = Vector2::new(data.x, data.z); let chunk_x = data.x;
let chunk_z = data.z;
// Calculate biome mixer seed // Calculate biome mixer seed
use crate::biome::hash_seed; use crate::biome::hash_seed;
let biome_mixer_seed = hash_seed(random_config.seed); let biome_mixer_seed = hash_seed(random_config.seed);
let mut chunk = let mut chunk = ProtoChunk::new(
ProtoChunk::new(chunk_pos, surface_settings, default_block, biome_mixer_seed); chunk_x,
chunk_z,
surface_settings,
default_block,
biome_mixer_seed,
);
// Create MultiNoiseSampler for populate_biomes // Create MultiNoiseSampler for populate_biomes
use crate::generation::noise::router::multi_noise_sampler::{ use crate::generation::noise::router::multi_noise_sampler::{
@ -130,16 +132,13 @@ mod test {
}; };
use crate::generation::{biome_coords, positions::chunk_pos}; use crate::generation::{biome_coords, positions::chunk_pos};
let start_x = chunk_pos::start_block_x(&chunk_pos); let start_x = chunk_pos::start_block_x(chunk_x);
let start_z = chunk_pos::start_block_z(&chunk_pos); let start_z = chunk_pos::start_block_z(chunk_z);
let biome_pos = Vector2::new(
biome_coords::from_block(start_x),
biome_coords::from_block(start_z),
);
let horizontal_biome_end = biome_coords::from_block(16); let horizontal_biome_end = biome_coords::from_block(16);
let multi_noise_config = MultiNoiseSamplerBuilderOptions::new( let multi_noise_config = MultiNoiseSamplerBuilderOptions::new(
biome_pos.x, biome_coords::from_block(start_x),
biome_pos.y, biome_coords::from_block(start_z),
horizontal_biome_end as usize, horizontal_biome_end as usize,
); );
let mut multi_noise_sampler = let mut multi_noise_sampler =
@ -148,8 +147,7 @@ mod test {
chunk.populate_biomes(Dimension::Overworld, &mut multi_noise_sampler); chunk.populate_biomes(Dimension::Overworld, &mut multi_noise_sampler);
for (biome_x, biome_y, biome_z, biome_id) in data.data { for (biome_x, biome_y, biome_z, biome_id) in data.data {
let global_biome_pos = Vector3::new(biome_x, biome_y, biome_z); let calculated_biome = chunk.get_biome(biome_x, biome_y, biome_z);
let calculated_biome = chunk.get_biome(&global_biome_pos);
assert_eq!( assert_eq!(
biome_id, biome_id,

View File

@ -31,10 +31,7 @@ impl NoiseValuePoint {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use pumpkin_data::{chunk::Biome, noise_router::OVERWORLD_BASE_NOISE_ROUTER}; use pumpkin_data::{chunk::Biome, noise_router::OVERWORLD_BASE_NOISE_ROUTER};
use pumpkin_util::{ use pumpkin_util::read_data_from_file;
math::{vector2::Vector2, vector3::Vector3},
read_data_from_file,
};
use crate::{ use crate::{
GENERATION_SETTINGS, GeneratorSetting, GlobalRandomConfig, ProtoChunk, GENERATION_SETTINGS, GeneratorSetting, GlobalRandomConfig, ProtoChunk,
@ -56,7 +53,9 @@ mod test {
read_data_from_file!("../../assets/multi_noise_sample_no_blend_no_beard_0_0_0.json"); read_data_from_file!("../../assets/multi_noise_sample_no_blend_no_beard_0_0_0.json");
let seed = 0; let seed = 0;
let chunk_pos = Vector2::new(0, 0); let chunk_x = 0;
let chunk_z = 0;
let random_config = GlobalRandomConfig::new(seed, false); let random_config = GlobalRandomConfig::new(seed, false);
let noise_router = let noise_router =
ProtoNoiseRouters::generate(&OVERWORLD_BASE_NOISE_ROUTER, &random_config); ProtoNoiseRouters::generate(&OVERWORLD_BASE_NOISE_ROUTER, &random_config);
@ -70,7 +69,8 @@ mod test {
let biome_mixer_seed = hash_seed(random_config.seed); let biome_mixer_seed = hash_seed(random_config.seed);
let _chunk = ProtoChunk::new( let _chunk = ProtoChunk::new(
chunk_pos, chunk_x,
chunk_z,
surface_config, surface_config,
surface_config.default_block.get_state(), surface_config.default_block.get_state(),
biome_mixer_seed, biome_mixer_seed,
@ -82,16 +82,12 @@ mod test {
}; };
use crate::generation::{biome_coords, positions::chunk_pos}; use crate::generation::{biome_coords, positions::chunk_pos};
let start_x = chunk_pos::start_block_x(&chunk_pos); let start_x = chunk_pos::start_block_x(chunk_x);
let start_z = chunk_pos::start_block_z(&chunk_pos); let start_z = chunk_pos::start_block_z(chunk_z);
let biome_pos = Vector2::new(
biome_coords::from_block(start_x),
biome_coords::from_block(start_z),
);
let horizontal_biome_end = biome_coords::from_block(16); let horizontal_biome_end = biome_coords::from_block(16);
let multi_noise_config = MultiNoiseSamplerBuilderOptions::new( let multi_noise_config = MultiNoiseSamplerBuilderOptions::new(
biome_pos.x, biome_coords::from_block(start_x),
biome_pos.y, biome_coords::from_block(start_z),
horizontal_biome_end as usize, horizontal_biome_end as usize,
); );
let mut multi_noise_sampler = let mut multi_noise_sampler =
@ -124,12 +120,8 @@ mod test {
); );
for (x, y, z, biome_id) in expected_data { for (x, y, z, biome_id) in expected_data {
let global_biome_pos = Vector3::new(x, y, z); let calculated_biome =
let calculated_biome = MultiNoiseBiomeSupplier::biome( MultiNoiseBiomeSupplier::biome(x, y, z, &mut sampler, Dimension::Overworld);
&global_biome_pos,
&mut sampler,
Dimension::Overworld,
);
assert_eq!( assert_eq!(
biome_id, biome_id,

View File

@ -342,9 +342,9 @@ impl<S: SingleChunkDataSerializer> AnvilChunkFile<S> {
(at.x >> SUBREGION_BITS, at.y >> SUBREGION_BITS) (at.x >> SUBREGION_BITS, at.y >> SUBREGION_BITS)
} }
pub const fn get_chunk_index(pos: &Vector2<i32>) -> usize { pub const fn get_chunk_index(x: i32, z: i32) -> usize {
let local_x = pos.x & SUBREGION_AND; let local_x = x & SUBREGION_AND;
let local_z = pos.y & SUBREGION_AND; let local_z = z & SUBREGION_AND;
let index = (local_z << SUBREGION_BITS) + local_x; let index = (local_z << SUBREGION_BITS) + local_x;
index as usize index as usize
} }
@ -518,7 +518,7 @@ pub trait SingleChunkDataSerializer: Send + Sync + Sized + Dirtiable {
&self, &self,
) -> Pin<Box<dyn Future<Output = Result<Bytes, ChunkSerializingError>> + Send + '_>>; ) -> Pin<Box<dyn Future<Output = Result<Bytes, ChunkSerializingError>> + Send + '_>>;
fn from_bytes(bytes: &Bytes, pos: Vector2<i32>) -> Result<Self, ChunkReadingError>; fn from_bytes(bytes: &Bytes, pos: Vector2<i32>) -> Result<Self, ChunkReadingError>;
fn position(&self) -> &Vector2<i32>; fn position(&self) -> (i32, i32);
} }
impl<S: SingleChunkDataSerializer> ChunkSerializer for AnvilChunkFile<S> { impl<S: SingleChunkDataSerializer> ChunkSerializer for AnvilChunkFile<S> {
@ -629,7 +629,7 @@ impl<S: SingleChunkDataSerializer> ChunkSerializer for AnvilChunkFile<S> {
.unwrap() .unwrap()
.as_secs() as u32; .as_secs() as u32;
let index = AnvilChunkFile::<S>::get_chunk_index(chunk.position()); let index = AnvilChunkFile::<S>::get_chunk_index(chunk.position().0, chunk.position().1);
// Default to the compression type read from the file // Default to the compression type read from the file
let compression_type = self.chunks_data[index] let compression_type = self.chunks_data[index]
.as_ref() .as_ref()
@ -797,13 +797,13 @@ impl<S: SingleChunkDataSerializer> ChunkSerializer for AnvilChunkFile<S> {
async fn get_chunks( async fn get_chunks(
&self, &self,
chunks: &[Vector2<i32>], chunks: Vec<Vector2<i32>>,
stream: tokio::sync::mpsc::Sender<LoadedData<Self::Data, ChunkReadingError>>, stream: tokio::sync::mpsc::Sender<LoadedData<Self::Data, ChunkReadingError>>,
) { ) {
// Don't par iter here so we can prevent backpressure with the await in the async // Don't par iter here so we can prevent backpressure with the await in the async
// runtime // runtime
for chunk in chunks.iter().cloned() { for chunk in chunks.into_iter() {
let index = AnvilChunkFile::<S>::get_chunk_index(&chunk); let index = AnvilChunkFile::<S>::get_chunk_index(chunk.x, chunk.y);
let is_ok = match &self.chunks_data[index] { let is_ok = match &self.chunks_data[index] {
None => stream.send(LoadedData::Missing(chunk)).await.is_ok(), None => stream.send(LoadedData::Missing(chunk)).await.is_ok(),
Some(chunk_metadata) => { Some(chunk_metadata) => {

View File

@ -139,8 +139,8 @@ impl LinearFileHeader {
} }
impl<S: SingleChunkDataSerializer> LinearFile<S> { impl<S: SingleChunkDataSerializer> LinearFile<S> {
const fn get_chunk_index(at: &Vector2<i32>) -> usize { const fn get_chunk_index(x: i32, z: i32) -> usize {
AnvilChunkFile::<S>::get_chunk_index(at) AnvilChunkFile::<S>::get_chunk_index(x, z)
} }
fn check_signature(bytes: &[u8]) -> Result<(), ChunkReadingError> { fn check_signature(bytes: &[u8]) -> Result<(), ChunkReadingError> {
@ -327,7 +327,7 @@ impl<S: SingleChunkDataSerializer> ChunkSerializer for LinearFile<S> {
chunk: &Self::Data, chunk: &Self::Data,
_chunk_config: &Self::ChunkConfig, _chunk_config: &Self::ChunkConfig,
) -> Result<(), ChunkWritingError> { ) -> Result<(), ChunkWritingError> {
let index = LinearFile::<S>::get_chunk_index(chunk.position()); let index = LinearFile::<S>::get_chunk_index(chunk.position().0, chunk.position().1);
let chunk_raw: Bytes = chunk let chunk_raw: Bytes = chunk
.to_bytes() .to_bytes()
.await .await
@ -348,13 +348,13 @@ impl<S: SingleChunkDataSerializer> ChunkSerializer for LinearFile<S> {
async fn get_chunks( async fn get_chunks(
&self, &self,
chunks: &[Vector2<i32>], chunks: Vec<Vector2<i32>>,
stream: tokio::sync::mpsc::Sender<LoadedData<Self::Data, ChunkReadingError>>, stream: tokio::sync::mpsc::Sender<LoadedData<Self::Data, ChunkReadingError>>,
) { ) {
// Don't par iter here so we can prevent backpressure with the await in the async // Don't par iter here so we can prevent backpressure with the await in the async
// runtime // runtime
for chunk in chunks.iter().cloned() { for chunk in chunks.into_iter() {
let index = LinearFile::<S>::get_chunk_index(&chunk); let index = LinearFile::<S>::get_chunk_index(chunk.x, chunk.y);
let linear_chunk_data = &self.chunks_data[index]; let linear_chunk_data = &self.chunks_data[index];
let result = if let Some(data) = linear_chunk_data { let result = if let Some(data) = linear_chunk_data {

View File

@ -43,8 +43,8 @@ impl SingleChunkDataSerializer for ChunkData {
} }
#[inline] #[inline]
fn position(&self) -> &Vector2<i32> { fn position(&self) -> (i32, i32) {
&self.position (self.x, self.z)
} }
} }
@ -163,7 +163,8 @@ impl ChunkData {
Ok(ChunkData { Ok(ChunkData {
section, section,
heightmap: chunk_data.heightmaps, heightmap: chunk_data.heightmaps,
position, x: position.x,
z: position.y,
// This chunk is read from disk, so it has not been modified // This chunk is read from disk, so it has not been modified
dirty: false, dirty: false,
block_ticks: ChunkTickScheduler::from_vec(&chunk_data.block_ticks), block_ticks: ChunkTickScheduler::from_vec(&chunk_data.block_ticks),
@ -206,8 +207,8 @@ impl ChunkData {
let nbt = ChunkNbt { let nbt = ChunkNbt {
data_version: WORLD_DATA_VERSION, data_version: WORLD_DATA_VERSION,
x_pos: self.position.x, x_pos: self.x,
z_pos: self.position.y, z_pos: self.z,
min_y_section: section_coords::block_to_section(self.section.min_y), min_y_section: section_coords::block_to_section(self.section.min_y),
status: self.status, status: self.status,
heightmaps: self.heightmap.clone(), heightmaps: self.heightmap.clone(),
@ -264,8 +265,8 @@ impl SingleChunkDataSerializer for ChunkEntityData {
} }
#[inline] #[inline]
fn position(&self) -> &Vector2<i32> { fn position(&self) -> (i32, i32) {
&self.chunk_position (self.x, self.z)
} }
} }
@ -310,7 +311,8 @@ impl ChunkEntityData {
} }
Ok(ChunkEntityData { Ok(ChunkEntityData {
chunk_position: position, x: position.x,
z: position.y,
data: map, data: map,
dirty: false, dirty: false,
}) })
@ -319,7 +321,7 @@ impl ChunkEntityData {
fn internal_to_bytes(&self) -> Result<Bytes, ChunkSerializingError> { fn internal_to_bytes(&self) -> Result<Bytes, ChunkSerializingError> {
let nbt = EntityNbt { let nbt = EntityNbt {
data_version: WORLD_DATA_VERSION, data_version: WORLD_DATA_VERSION,
position: [self.chunk_position.x, self.chunk_position.y], position: [self.x, self.z],
entities: self.data.values().cloned().collect(), entities: self.data.values().cloned().collect(),
}; };

View File

@ -273,7 +273,7 @@ where
// This minimizes the time we block other operations // This minimizes the time we block other operations
let reader = async move { let reader = async move {
let serializer = chunk_serializer.read().await; let serializer = chunk_serializer.read().await;
serializer.get_chunks(&chunks, send).await; serializer.get_chunks(chunks, send).await;
}; };
join!(intermediary, reader); join!(intermediary, reader);

View File

@ -125,7 +125,7 @@ pub trait ChunkSerializer: Send + Sync + Default {
/// Get the chunks data from the serializer /// Get the chunks data from the serializer
fn get_chunks( fn get_chunks(
&self, &self,
chunks: &[Vector2<i32>], chunks: Vec<Vector2<i32>>,
stream: tokio::sync::mpsc::Sender<LoadedData<Self::Data, ChunkReadingError>>, stream: tokio::sync::mpsc::Sender<LoadedData<Self::Data, ChunkReadingError>>,
) -> impl Future<Output = ()> + Send; ) -> impl Future<Output = ()> + Send;
} }

View File

@ -11,7 +11,7 @@ use pumpkin_data::tag::Taggable;
use pumpkin_data::{Block, BlockState}; use pumpkin_data::{Block, BlockState};
use pumpkin_nbt::compound::NbtCompound; use pumpkin_nbt::compound::NbtCompound;
use pumpkin_nbt::nbt_long_array; use pumpkin_nbt::nbt_long_array;
use pumpkin_util::math::{position::BlockPos, vector2::Vector2}; use pumpkin_util::math::position::BlockPos;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::ops::{BitAnd, BitOr}; use std::ops::{BitAnd, BitOr};
use std::{collections::HashMap, sync::Arc}; use std::{collections::HashMap, sync::Arc};
@ -72,7 +72,8 @@ pub struct ChunkData {
pub section: ChunkSections, pub section: ChunkSections,
/// See `https://minecraft.wiki/w/Heightmap` for more info /// See `https://minecraft.wiki/w/Heightmap` for more info
pub heightmap: ChunkHeightmaps, pub heightmap: ChunkHeightmaps,
pub position: Vector2<i32>, pub x: i32,
pub z: i32,
pub block_ticks: ChunkTickScheduler<&'static Block>, pub block_ticks: ChunkTickScheduler<&'static Block>,
pub fluid_ticks: ChunkTickScheduler<&'static Fluid>, pub fluid_ticks: ChunkTickScheduler<&'static Fluid>,
pub block_entities: HashMap<BlockPos, Arc<dyn BlockEntity>>, pub block_entities: HashMap<BlockPos, Arc<dyn BlockEntity>>,
@ -83,7 +84,10 @@ pub struct ChunkData {
#[derive(Clone)] #[derive(Clone)]
pub struct ChunkEntityData { pub struct ChunkEntityData {
pub chunk_position: Vector2<i32>, /// Chunk X
pub x: i32,
/// Chunk Z
pub z: i32,
pub data: HashMap<uuid::Uuid, NbtCompound>, pub data: HashMap<uuid::Uuid, NbtCompound>,
pub dirty: bool, pub dirty: bool,
@ -528,7 +532,7 @@ impl ChunkData {
has_found[ChunkHeightmapType::WorldSurface as usize] = true; has_found[ChunkHeightmapType::WorldSurface as usize] = true;
} }
let is_motion_blocking = blocks_movement(block_state) let is_motion_blocking = blocks_movement(block_state, block)
|| Fluid::from_registry_key(block.registry_key()) || Fluid::from_registry_key(block.registry_key())
.is_some_and(|fluid| !fluid.states.is_empty()); .is_some_and(|fluid| !fluid.states.is_empty());

View File

@ -779,8 +779,7 @@ impl Chunk {
let absolute_y = let absolute_y =
biome_coords::from_block(generation_settings.shape.min_y as i32) biome_coords::from_block(generation_settings.shape.min_y as i32)
+ y as i32; + y as i32;
let biome = let biome = proto_chunk.get_biome(x as i32, absolute_y, z as i32);
proto_chunk.get_biome(&Vector3::new(x as i32, absolute_y, z as i32));
section.biomes.set(x, relative_y, z, biome.id); section.biomes.set(x, relative_y, z, biome.id);
} }
} }
@ -793,8 +792,7 @@ impl Chunk {
if let Some(section) = sections.sections.get_mut(section_index) { if let Some(section) = sections.sections.get_mut(section_index) {
for z in 0..BlockPalette::SIZE { for z in 0..BlockPalette::SIZE {
for x in 0..BlockPalette::SIZE { for x in 0..BlockPalette::SIZE {
let block = proto_chunk let block = proto_chunk.get_block_state_raw(x as i32, y as i32, z as i32);
.get_block_state_raw(&Vector3::new(x as i32, y as i32, z as i32));
section.block_states.set(x, relative_y, z, block); section.block_states.set(x, relative_y, z, block);
} }
} }
@ -811,7 +809,8 @@ impl Chunk {
}, },
section: sections, section: sections,
heightmap: Default::default(), heightmap: Default::default(),
position: proto_chunk.chunk_pos, x: proto_chunk.x,
z: proto_chunk.z,
dirty: true, dirty: true,
block_ticks: Default::default(), block_ticks: Default::default(),
fluid_ticks: Default::default(), fluid_ticks: Default::default(),
@ -971,22 +970,22 @@ impl GenerationCache for Cache {
} }
} }
fn get_top_y(&self, heightmap: &HeightMap, pos: &Vector2<i32>) -> i32 { fn get_top_y(&self, heightmap: &HeightMap, x: i32, z: i32) -> i32 {
match heightmap { match heightmap {
HeightMap::WorldSurfaceWg => self.top_block_height_exclusive(pos), HeightMap::WorldSurfaceWg => self.top_block_height_exclusive(x, z),
HeightMap::WorldSurface => self.top_block_height_exclusive(pos), HeightMap::WorldSurface => self.top_block_height_exclusive(x, z),
HeightMap::OceanFloorWg => self.ocean_floor_height_exclusive(pos), HeightMap::OceanFloorWg => self.ocean_floor_height_exclusive(x, z),
HeightMap::OceanFloor => self.ocean_floor_height_exclusive(pos), HeightMap::OceanFloor => self.ocean_floor_height_exclusive(x, z),
HeightMap::MotionBlocking => self.top_motion_blocking_block_height_exclusive(pos), HeightMap::MotionBlocking => self.top_motion_blocking_block_height_exclusive(x, z),
HeightMap::MotionBlockingNoLeaves => { HeightMap::MotionBlockingNoLeaves => {
self.top_motion_blocking_block_no_leaves_height_exclusive(pos) self.top_motion_blocking_block_no_leaves_height_exclusive(x, z)
} }
} }
} }
fn top_motion_blocking_block_height_exclusive(&self, pos: &Vector2<i32>) -> i32 { fn top_motion_blocking_block_height_exclusive(&self, x: i32, z: i32) -> i32 {
let dx = (pos.x >> 4) - self.x; let dx = (x >> 4) - self.x;
let dy = (pos.y >> 4) - self.y; let dy = (z >> 4) - self.y;
debug_assert!(dx < self.size && dy < self.size); debug_assert!(dx < self.size && dy < self.size);
debug_assert!(dx >= 0 && dy >= 0); debug_assert!(dx >= 0 && dy >= 0);
match &self.chunks[(dx * self.size + dy) as usize] { match &self.chunks[(dx * self.size + dy) as usize] {
@ -994,18 +993,18 @@ impl GenerationCache for Cache {
let chunk = data.blocking_read(); let chunk = data.blocking_read();
chunk.heightmap.get_height( chunk.heightmap.get_height(
ChunkHeightmapType::MotionBlocking, ChunkHeightmapType::MotionBlocking,
pos.x, x,
pos.y, z,
chunk.section.min_y, chunk.section.min_y,
) )
} }
Chunk::Proto(data) => data.top_motion_blocking_block_height_exclusive(pos), Chunk::Proto(data) => data.top_motion_blocking_block_height_exclusive(x, z),
} }
} }
fn top_motion_blocking_block_no_leaves_height_exclusive(&self, pos: &Vector2<i32>) -> i32 { fn top_motion_blocking_block_no_leaves_height_exclusive(&self, x: i32, z: i32) -> i32 {
let dx = (pos.x >> 4) - self.x; let dx = (x >> 4) - self.x;
let dy = (pos.y >> 4) - self.y; let dy = (z >> 4) - self.y;
debug_assert!(dx < self.size && dy < self.size); debug_assert!(dx < self.size && dy < self.size);
debug_assert!(dx >= 0 && dy >= 0); debug_assert!(dx >= 0 && dy >= 0);
match &self.chunks[(dx * self.size + dy) as usize] { match &self.chunks[(dx * self.size + dy) as usize] {
@ -1013,18 +1012,18 @@ impl GenerationCache for Cache {
let chunk = data.blocking_read(); let chunk = data.blocking_read();
chunk.heightmap.get_height( chunk.heightmap.get_height(
ChunkHeightmapType::MotionBlockingNoLeaves, ChunkHeightmapType::MotionBlockingNoLeaves,
pos.x, x,
pos.y, z,
chunk.section.min_y, chunk.section.min_y,
) )
} }
Chunk::Proto(data) => data.top_motion_blocking_block_no_leaves_height_exclusive(pos), Chunk::Proto(data) => data.top_motion_blocking_block_no_leaves_height_exclusive(x, z),
} }
} }
fn top_block_height_exclusive(&self, pos: &Vector2<i32>) -> i32 { fn top_block_height_exclusive(&self, x: i32, z: i32) -> i32 {
let dx = (pos.x >> 4) - self.x; let dx = (x >> 4) - self.x;
let dy = (pos.y >> 4) - self.y; let dy = (z >> 4) - self.y;
debug_assert!(dx < self.size && dy < self.size); debug_assert!(dx < self.size && dy < self.size);
debug_assert!(dx >= 0 && dy >= 0); debug_assert!(dx >= 0 && dy >= 0);
match &self.chunks[(dx * self.size + dy) as usize] { match &self.chunks[(dx * self.size + dy) as usize] {
@ -1032,31 +1031,31 @@ impl GenerationCache for Cache {
let chunk = data.blocking_read(); let chunk = data.blocking_read();
chunk.heightmap.get_height( chunk.heightmap.get_height(
ChunkHeightmapType::WorldSurface, ChunkHeightmapType::WorldSurface,
pos.x, x,
pos.y, z,
chunk.section.min_y, chunk.section.min_y,
) // can we return this? ) // can we return this?
} }
Chunk::Proto(data) => data.top_block_height_exclusive(pos), Chunk::Proto(data) => data.top_block_height_exclusive(x, z),
} }
} }
fn ocean_floor_height_exclusive(&self, pos: &Vector2<i32>) -> i32 { fn ocean_floor_height_exclusive(&self, x: i32, z: i32) -> i32 {
let dx = (pos.x >> 4) - self.x; let dx = (x >> 4) - self.x;
let dy = (pos.y >> 4) - self.y; let dy = (z >> 4) - self.y;
debug_assert!(dx < self.size && dy < self.size); debug_assert!(dx < self.size && dy < self.size);
debug_assert!(dx >= 0 && dy >= 0); debug_assert!(dx >= 0 && dy >= 0);
match &self.chunks[(dx * self.size + dy) as usize] { match &self.chunks[(dx * self.size + dy) as usize] {
Chunk::Level(_data) => { Chunk::Level(_data) => {
0 // todo missing 0 // todo missing
} }
Chunk::Proto(data) => data.ocean_floor_height_exclusive(pos), Chunk::Proto(data) => data.ocean_floor_height_exclusive(x, z),
} }
} }
fn get_biome_for_terrain_gen(&self, global_block_pos: &Vector3<i32>) -> &'static Biome { fn get_biome_for_terrain_gen(&self, x: i32, y: i32, z: i32) -> &'static Biome {
let dx = (global_block_pos.x >> 4) - self.x; let dx = (x >> 4) - self.x;
let dy = (global_block_pos.z >> 4) - self.y; let dy = (z >> 4) - self.y;
debug_assert!(dx < self.size && dy < self.size); debug_assert!(dx < self.size && dy < self.size);
debug_assert!(dx >= 0 && dy >= 0); debug_assert!(dx >= 0 && dy >= 0);
match &self.chunks[(dx * self.size + dy) as usize] { match &self.chunks[(dx * self.size + dy) as usize] {
@ -1065,16 +1064,12 @@ impl GenerationCache for Cache {
Biome::from_id( Biome::from_id(
data.blocking_read() data.blocking_read()
.section .section
.get_rough_biome_absolute_y( .get_rough_biome_absolute_y((x & 15) as usize, y, (z & 15) as usize)
(global_block_pos.x & 15) as usize,
global_block_pos.y,
(global_block_pos.z & 15) as usize,
)
.unwrap_or(0), .unwrap_or(0),
) )
.unwrap() .unwrap()
} }
Chunk::Proto(data) => data.get_biome_for_terrain_gen(global_block_pos), Chunk::Proto(data) => data.get_biome_for_terrain_gen(x, y, z),
} }
} }
@ -1616,7 +1611,8 @@ impl GenerationSchedule {
.send(( .send((
pos, pos,
RecvChunk::IO(Proto(Box::new(ProtoChunk::new( RecvChunk::IO(Proto(Box::new(ProtoChunk::new(
pos, pos.x,
pos.y,
generation_setting, generation_setting,
level.world_gen.default_block, level.world_gen.default_block,
biome_mixer_seed, biome_mixer_seed,

View File

@ -1,7 +1,7 @@
use enum_dispatch::enum_dispatch; use enum_dispatch::enum_dispatch;
use pumpkin_data::{Block, BlockState}; use pumpkin_data::{Block, BlockState};
use pumpkin_util::{ use pumpkin_util::{
math::{clamped_map, floor_div, vector2::Vector2, vector3::Vector3}, math::{clamped_map, floor_div, vector3::Vector3},
random::{RandomDeriver, RandomDeriverImpl, RandomImpl}, random::{RandomDeriver, RandomDeriverImpl, RandomImpl},
}; };
@ -45,7 +45,7 @@ impl FluidLevel {
#[enum_dispatch(FluidLevelSamplerImpl)] #[enum_dispatch(FluidLevelSamplerImpl)]
pub enum FluidLevelSampler { pub enum FluidLevelSampler {
Static(StaticFluidLevelSampler), Static(StaticFluidLevelSampler),
Chunk(Box<StandardChunkFluidLevelSampler>), Chunk(StandardChunkFluidLevelSampler),
} }
impl FluidLevelSamplerImpl for FluidLevelSampler { impl FluidLevelSamplerImpl for FluidLevelSampler {
@ -106,7 +106,7 @@ macro_rules! local_y {
pub struct WorldAquiferSampler { pub struct WorldAquiferSampler {
fluid_level_sampler: FluidLevelSampler, fluid_level_sampler: FluidLevelSampler,
start_x: i32, start_x: i32,
start_y: i8, start_y: i32,
start_z: i32, start_z: i32,
size_y: usize, size_y: usize,
size_z: usize, size_z: usize,
@ -115,40 +115,40 @@ pub struct WorldAquiferSampler {
} }
impl WorldAquiferSampler { impl WorldAquiferSampler {
const CHUNK_POS_OFFSETS: [Vector2<i8>; 13] = [ const CHUNK_POS_OFFSETS: [(i8, i8); 13] = [
Vector2::new(0, 0), (0, 0),
Vector2::new(-2, -1), (-2, -1),
Vector2::new(-1, -1), (-1, -1),
Vector2::new(0, -1), (0, -1),
Vector2::new(1, -1), (1, -1),
Vector2::new(-3, 0), (-3, 0),
Vector2::new(-2, 0), (-2, 0),
Vector2::new(-1, 0), (-1, 0),
Vector2::new(1, 0), (1, 0),
Vector2::new(-2, 1), (-2, 1),
Vector2::new(-1, 1), (-1, 1),
Vector2::new(0, 1), (0, 1),
Vector2::new(1, 1), (1, 1),
]; ];
#[allow(clippy::too_many_arguments)]
pub fn new( pub fn new(
chunk_pos: Vector2<i32>, chunk_x: i32,
chunk_z: i32,
random_deriver: &RandomDeriver, random_deriver: &RandomDeriver,
minimum_y: i8, minimum_y: i8,
height: u16, height: u16,
fluid_level: FluidLevelSampler, fluid_level: FluidLevelSampler,
) -> Self { ) -> Self {
let start_x = local_xz!(chunk_pos::start_block_x(&chunk_pos)) - 1; let start_x = local_xz!(chunk_pos::start_block_x(chunk_x)) - 1;
let end_x = local_xz!(chunk_pos::end_block_x(&chunk_pos)) + 1; let end_x = local_xz!(chunk_pos::end_block_x(chunk_x)) + 1;
let size_x = (end_x - start_x) as usize + 1; let size_x = (end_x - start_x) as usize + 1;
let start_y = local_y!(minimum_y) - 1; let start_y = local_y!(minimum_y) - 1;
let end_y = local_y!(minimum_y as i32 + height as i32) + 1; let end_y = local_y!(minimum_y as i32 + height as i32) + 1;
let size_y = (end_y - start_y as i32) as usize + 1; let size_y = (end_y - start_y as i32) as usize + 1;
let start_z = local_xz!(chunk_pos::start_block_z(&chunk_pos)) - 1; let start_z = local_xz!(chunk_pos::start_block_z(chunk_z)) - 1;
let end_z = local_xz!(chunk_pos::end_block_z(&chunk_pos)) + 1; let end_z = local_xz!(chunk_pos::end_block_z(chunk_z)) + 1;
let size_z = (end_z - start_z) as usize + 1; let size_z = (end_z - start_z) as usize + 1;
let cache_size = size_x * size_y * size_z; let cache_size = size_x * size_y * size_z;
@ -178,7 +178,7 @@ impl WorldAquiferSampler {
Self { Self {
fluid_level_sampler: fluid_level, fluid_level_sampler: fluid_level,
start_x, start_x,
start_y, start_y: start_y as i32,
start_z, start_z,
size_y, size_y,
size_z, size_z,
@ -189,7 +189,7 @@ impl WorldAquiferSampler {
fn packed_position_index(&self, x: i32, y: i32, z: i32) -> usize { fn packed_position_index(&self, x: i32, y: i32, z: i32) -> usize {
let local_x = (x - self.start_x) as usize; let local_x = (x - self.start_x) as usize;
let local_y = (y - self.start_y as i32) as usize; let local_y = (y - self.start_y) as usize;
let local_z = (z - self.start_z) as usize; let local_z = (z - self.start_z) as usize;
packed_position_index!(local_x, local_y, local_z, self.size_y, self.size_z) packed_position_index!(local_x, local_y, local_z, self.size_y, self.size_z)
@ -288,10 +288,8 @@ impl WorldAquiferSampler {
let local_z = local_xz!(z); let local_z = local_xz!(z);
let index = self.packed_position_index(local_x, local_y, local_z); let index = self.packed_position_index(local_x, local_y, local_z);
let entry = self let entry = &mut self.levels[index];
.levels
.get_mut(index)
.expect("Index calculated by packed_position_index is out of bounds for self.levels");
let fluid_level = &self.fluid_level_sampler; let fluid_level = &self.fluid_level_sampler;
entry.get_or_insert_with(|| { entry.get_or_insert_with(|| {
Self::get_fluid_level( Self::get_fluid_level(
@ -321,13 +319,13 @@ impl WorldAquiferSampler {
let mut bl = false; let mut bl = false;
let mut min_surface_estimate = i32::MAX; let mut min_surface_estimate = i32::MAX;
for offset in Self::CHUNK_POS_OFFSETS { for (offset_x, offset_z) in Self::CHUNK_POS_OFFSETS {
let x = block_x + section_coords::section_to_block(offset.x as i32); let x = block_x + section_coords::section_to_block(offset_x as i32);
let z = block_z + section_coords::section_to_block(offset.y as i32); let z = block_z + section_coords::section_to_block(offset_z as i32);
let n = height_estimator.estimate_height(x, z); let n = height_estimator.estimate_height(x, z);
let o = n + 8; let o = n + 8;
let bl2 = offset.x == 0 && offset.y == 0; let bl2 = offset_x == 0 && offset_z == 0;
if bl2 && k > o { if bl2 && k > o {
return fluid_level.clone(); return fluid_level.clone();
@ -691,7 +689,6 @@ mod random_positions_and_hypot {
use std::{mem, sync::LazyLock}; use std::{mem, sync::LazyLock};
use pumpkin_data::noise_router::OVERWORLD_BASE_NOISE_ROUTER; use pumpkin_data::noise_router::OVERWORLD_BASE_NOISE_ROUTER;
use pumpkin_util::math::vector2::Vector2;
use crate::{ use crate::{
block::RawBlockState, block::RawBlockState,
@ -738,18 +735,20 @@ mod random_positions_and_hypot {
.get(&GeneratorSetting::Overworld) .get(&GeneratorSetting::Overworld)
.unwrap(); .unwrap();
let shape = &surface_config.shape; let shape = &surface_config.shape;
let chunk_pos = Vector2::new(7, 4); let chunk_x = 7;
let sampler = FluidLevelSampler::Chunk(Box::new(StandardChunkFluidLevelSampler::new( let chunk_z = 4;
let sampler = FluidLevelSampler::Chunk(StandardChunkFluidLevelSampler::new(
FluidLevel::new(63, &WATER_BLOCK), FluidLevel::new(63, &WATER_BLOCK),
FluidLevel::new(-54, &LAVA_BLOCK), FluidLevel::new(-54, &LAVA_BLOCK),
))); ));
const CHUNK_WIDTH: usize = 16; const CHUNK_WIDTH: usize = 16;
let noise = ChunkNoiseGenerator::new( let noise = ChunkNoiseGenerator::new(
&base_router.noise, &base_router.noise,
&RANDOM_CONFIG, &RANDOM_CONFIG,
CHUNK_WIDTH / shape.horizontal_cell_block_count() as usize, CHUNK_WIDTH / shape.horizontal_cell_block_count() as usize,
chunk_pos::start_block_x(&chunk_pos), chunk_pos::start_block_x(chunk_x),
chunk_pos::start_block_z(&chunk_pos), chunk_pos::start_block_z(chunk_z),
shape, shape,
sampler, sampler,
true, true,
@ -771,7 +770,7 @@ mod random_positions_and_hypot {
BlockStateSampler::Aquifer(aquifer) => aquifer, BlockStateSampler::Aquifer(aquifer) => aquifer,
_ => unreachable!(), _ => unreachable!(),
}; };
let aquifer = match *sampler { let aquifer = match sampler {
AquiferSampler::Aquifer(aquifer) => aquifer, AquiferSampler::Aquifer(aquifer) => aquifer,
_ => unreachable!(), _ => unreachable!(),
}; };
@ -783,8 +782,8 @@ mod random_positions_and_hypot {
); );
let surface_height_estimator_options = SurfaceHeightSamplerBuilderOptions::new( let surface_height_estimator_options = SurfaceHeightSamplerBuilderOptions::new(
chunk_pos.x, chunk_x,
chunk_pos.y, chunk_z,
horizontal_biome_end, horizontal_biome_end,
shape.min_y as i32, shape.min_y as i32,
shape.max_y() as i32, shape.max_y() as i32,

View File

@ -7,12 +7,14 @@ pub fn get_biome_blend(
bottom_y: i8, bottom_y: i8,
height: u16, height: u16,
seed: i64, seed: i64,
global_block_pos: &Vector3<i32>, x: i32,
y: i32,
z: i32,
) -> Vector3<i32> { ) -> Vector3<i32> {
// This is the "left" side of the biome boundary // This is the "left" side of the biome boundary
let offset_x = global_block_pos.x - 2; let offset_x = x - 2;
let offset_y = global_block_pos.y - 2; let offset_y = y - 2;
let offset_z = global_block_pos.z - 2; let offset_z = z - 2;
let biome_x = biome_coords::from_block(offset_x); let biome_x = biome_coords::from_block(offset_x);
let biome_y = biome_coords::from_block(offset_y); let biome_y = biome_coords::from_block(offset_y);
let biome_z = biome_coords::from_block(offset_z); let biome_z = biome_coords::from_block(offset_z);
@ -174,7 +176,7 @@ mod test {
#[test] #[test]
fn test_biome_blend() { fn test_biome_blend() {
let biome_pos = get_biome_blend(-64, 384, 1234567890, &Vector3::new(123, 123, 123)); let biome_pos = get_biome_blend(-64, 384, 1234567890, 123, 123, 123);
assert_eq!(biome_pos, Vector3::new(31, 30, 30)); assert_eq!(biome_pos, Vector3::new(31, 30, 30));
} }
@ -191,7 +193,7 @@ mod test {
let seed = hash_seed((-777i64) as u64); let seed = hash_seed((-777i64) as u64);
for (i, (x, y, z, result_x, result_y, result_z)) in data.into_iter().enumerate() { for (i, (x, y, z, result_x, result_y, result_z)) in data.into_iter().enumerate() {
let result = get_biome_blend(i8::MIN, u16::MAX, seed, &Vector3::new(x, y, z)); let result = get_biome_blend(i8::MIN, u16::MAX, seed, x, y, z);
let expected = Vector3::new(result_x, result_y, result_z); let expected = Vector3::new(result_x, result_y, result_z);
assert_eq!( assert_eq!(
result, expected, result, expected,

View File

@ -6,7 +6,6 @@ use pumpkin_util::{
int_provider::IntProvider, int_provider::IntProvider,
pool::{Pool, Weighted}, pool::{Pool, Weighted},
position::BlockPos, position::BlockPos,
vector3::Vector3,
}, },
random::{RandomGenerator, RandomImpl, legacy_rand::LegacyRand}, random::{RandomGenerator, RandomImpl, legacy_rand::LegacyRand},
}; };
@ -81,7 +80,7 @@ pub struct DualNoiseBlockStateProvider {
base: NoiseBlockStateProvider, base: NoiseBlockStateProvider,
variety: [u32; 2], variety: [u32; 2],
slow_noise: DoublePerlinNoiseParametersCodec, slow_noise: DoublePerlinNoiseParametersCodec,
slow_scale: f32, slow_scale: f64,
} }
impl DualNoiseBlockStateProvider { impl DualNoiseBlockStateProvider {
@ -92,7 +91,8 @@ impl DualNoiseBlockStateProvider {
&noise, &noise,
false, false,
); );
let slow_noise = self.get_slow_noise(&pos, &sampler); let slow_noise =
self.get_slow_noise(pos.0.x as f64, pos.0.y as f64, pos.0.z as f64, &sampler);
let mapped = clamped_map( let mapped = clamped_map(
slow_noise, slow_noise,
-1.0, -1.0,
@ -102,10 +102,7 @@ impl DualNoiseBlockStateProvider {
) as i32; ) as i32;
let mut list = Vec::with_capacity(mapped as usize); let mut list = Vec::with_capacity(mapped as usize);
for i in 0..mapped { for i in 0..mapped {
let value = self.get_slow_noise( let value = self.get_slow_noise(i as f64 * 54545.0, 0.0, i as f64 * 34234.0, &sampler);
&BlockPos(pos.0.add(&Vector3::new(i * 54545, 0, i * 34234))),
&sampler,
);
list.push( list.push(
self.base self.base
.get_state_by_value(&self.base.states, value) .get_state_by_value(&self.base.states, value)
@ -116,11 +113,11 @@ impl DualNoiseBlockStateProvider {
self.base.get_state_by_value(&list, value).get_state() self.base.get_state_by_value(&list, value).get_state()
} }
fn get_slow_noise(&self, pos: &BlockPos, sampler: &DoublePerlinNoiseSampler) -> f64 { fn get_slow_noise(&self, x: f64, y: f64, z: f64, sampler: &DoublePerlinNoiseSampler) -> f64 {
sampler.sample( sampler.sample(
pos.0.x as f64 * self.slow_scale as f64, x * self.slow_scale,
pos.0.y as f64 * self.slow_scale as f64, y * self.slow_scale,
pos.0.z as f64 * self.slow_scale as f64, z * self.slow_scale,
) )
} }
} }

View File

@ -1,5 +1,5 @@
use pumpkin_data::{Block, BlockState}; use pumpkin_data::{Block, BlockState};
use pumpkin_util::math::{floor_div, floor_mod, vector2::Vector2, vector3::Vector3}; use pumpkin_util::math::{floor_div, floor_mod, vector2::Vector2};
use crate::generation::section_coords; use crate::generation::section_coords;
@ -30,7 +30,7 @@ pub const WATER_BLOCK: Block = Block::WATER;
pub const CHUNK_DIM: u8 = 16; pub const CHUNK_DIM: u8 = 16;
pub enum BlockStateSampler { pub enum BlockStateSampler {
Aquifer(Box<AquiferSampler>), Aquifer(AquiferSampler),
Ore(OreVeinSampler), Ore(OreVeinSampler),
Chained(ChainedBlockStateSampler), Chained(ChainedBlockStateSampler),
} }
@ -142,7 +142,8 @@ impl IndexToNoisePos for ChunkIndexMapper {
pub struct ChunkNoiseGenerator<'a> { pub struct ChunkNoiseGenerator<'a> {
pub state_sampler: BlockStateSampler, pub state_sampler: BlockStateSampler,
generation_shape: &'a GenerationShapeConfig, generation_shape: &'a GenerationShapeConfig,
start_cell_pos: Vector2<i32>, start_cell_pos_x: i32,
start_cell_pos_z: i32,
vertical_cell_count: usize, vertical_cell_count: usize,
minimum_cell_y: i32, minimum_cell_y: i32,
@ -166,15 +167,13 @@ impl<'a> ChunkNoiseGenerator<'a> {
aquifers: bool, aquifers: bool,
ore_veins: bool, ore_veins: bool,
) -> Self { ) -> Self {
let start_cell_pos = Vector2::new( let start_cell_pos_x = floor_div(
floor_div( start_block_x,
start_block_x, generation_shape.horizontal_cell_block_count() as i32,
generation_shape.horizontal_cell_block_count() as i32, );
), let start_cell_pos_z = floor_div(
floor_div( start_block_z,
start_block_z, generation_shape.horizontal_cell_block_count() as i32,
generation_shape.horizontal_cell_block_count() as i32,
),
); );
let biome_pos = Vector2::new( let biome_pos = Vector2::new(
@ -209,7 +208,8 @@ impl<'a> ChunkNoiseGenerator<'a> {
let section_x = section_coords::block_to_section(start_block_x); let section_x = section_coords::block_to_section(start_block_x);
let section_z = section_coords::block_to_section(start_block_z); let section_z = section_coords::block_to_section(start_block_z);
AquiferSampler::Aquifer(WorldAquiferSampler::new( AquiferSampler::Aquifer(WorldAquiferSampler::new(
Vector2::new(section_x, section_z), section_x,
section_z,
&random_config.aquifer_random_deriver, &random_config.aquifer_random_deriver,
generation_shape.min_y, generation_shape.min_y,
generation_shape.height, generation_shape.height,
@ -219,23 +219,28 @@ impl<'a> ChunkNoiseGenerator<'a> {
AquiferSampler::SeaLevel(SeaLevelAquiferSampler::new(level_sampler)) AquiferSampler::SeaLevel(SeaLevelAquiferSampler::new(level_sampler))
}; };
let mut samplers = vec![BlockStateSampler::Aquifer(Box::new(aquifer_sampler))]; let state_sampler = if ore_veins {
if ore_veins {
let ore_sampler = OreVeinSampler::new(random_config.ore_random_deriver.clone()); let ore_sampler = OreVeinSampler::new(random_config.ore_random_deriver.clone());
samplers.push(BlockStateSampler::Ore(ore_sampler)); let samplers: Box<[BlockStateSampler]> = Box::new([
}; BlockStateSampler::Aquifer(aquifer_sampler),
BlockStateSampler::Ore(ore_sampler),
]);
let state_sampler = BlockStateSampler::Chained(ChainedBlockStateSampler::new(samplers))
BlockStateSampler::Chained(ChainedBlockStateSampler::new(samplers.into_boxed_slice())); } else {
let samplers: Box<[BlockStateSampler]> =
Box::new([BlockStateSampler::Aquifer(aquifer_sampler)]);
BlockStateSampler::Chained(ChainedBlockStateSampler::new(samplers))
};
let router = ChunkNoiseRouter::generate(noise_router_base, &builder_options); let router = ChunkNoiseRouter::generate(noise_router_base, &builder_options);
Self { Self {
state_sampler, state_sampler,
generation_shape, generation_shape,
start_cell_pos, start_cell_pos_x,
start_cell_pos_z,
vertical_cell_count, vertical_cell_count,
minimum_cell_y, minimum_cell_y,
@ -249,19 +254,19 @@ impl<'a> ChunkNoiseGenerator<'a> {
#[inline] #[inline]
pub fn sample_start_density(&mut self) { pub fn sample_start_density(&mut self) {
self.cache_result_unique_id = 0; self.cache_result_unique_id = 0;
self.sample_density(true, self.start_cell_pos.x); self.sample_density(true, self.start_cell_pos_x);
} }
#[inline] #[inline]
pub fn sample_end_density(&mut self, cell_x: u8) { pub fn sample_end_density(&mut self, cell_x: u8) {
self.sample_density(false, self.start_cell_pos.x + cell_x as i32 + 1); self.sample_density(false, self.start_cell_pos_x + cell_x as i32 + 1);
} }
fn sample_density(&mut self, start: bool, current_x: i32) { fn sample_density(&mut self, start: bool, current_x: i32) {
let x = current_x * self.horizontal_cell_block_count() as i32; let x = current_x * self.horizontal_cell_block_count() as i32;
for cell_z in 0..=(16 / self.horizontal_cell_block_count()) { for cell_z in 0..=(16 / self.horizontal_cell_block_count()) {
let current_cell_z_pos = self.start_cell_pos.y + cell_z as i32; let current_cell_z_pos = self.start_cell_pos_z + cell_z as i32;
let z = current_cell_z_pos * self.horizontal_cell_block_count() as i32; let z = current_cell_z_pos * self.horizontal_cell_block_count() as i32;
self.cache_fill_unique_id += 1; self.cache_fill_unique_id += 1;
@ -331,11 +336,11 @@ impl<'a> ChunkNoiseGenerator<'a> {
self.cache_fill_unique_id += 1; self.cache_fill_unique_id += 1;
let start_x = let start_x =
(self.start_cell_pos.x + cell_x as i32) * self.horizontal_cell_block_count() as i32; (self.start_cell_pos_x + cell_x as i32) * self.horizontal_cell_block_count() as i32;
let start_y = let start_y =
(cell_y as i32 + self.minimum_cell_y) * self.vertical_cell_block_count() as i32; (cell_y as i32 + self.minimum_cell_y) * self.vertical_cell_block_count() as i32;
let start_z = let start_z =
(self.start_cell_pos.y + cell_z as i32) * self.horizontal_cell_block_count() as i32; (self.start_cell_pos_z + cell_z as i32) * self.horizontal_cell_block_count() as i32;
let mapper = ChunkIndexMapper { let mapper = ChunkIndexMapper {
start_x, start_x,
@ -363,25 +368,26 @@ impl<'a> ChunkNoiseGenerator<'a> {
self.cache_fill_unique_id += 1; self.cache_fill_unique_id += 1;
} }
#[expect(clippy::too_many_arguments)]
pub fn sample_block_state( pub fn sample_block_state(
&mut self, &mut self,
start_pos: Vector3<i32>, start_x: i32,
cell_pos: Vector3<i32>, start_y: i32,
start_z: i32,
cell_x: i32,
cell_y: i32,
cell_z: i32,
height_estimator: &mut SurfaceHeightEstimateSampler, height_estimator: &mut SurfaceHeightEstimateSampler,
) -> Option<&'static BlockState> { ) -> Option<&'static BlockState> {
//TODO: Fix this when Blender is added //TODO: Fix this when Blender is added
let pos = UnblendedNoisePos::new( let pos = UnblendedNoisePos::new(start_x + cell_x, start_y + cell_y, start_z + cell_z);
start_pos.x + cell_pos.x,
start_pos.y + cell_pos.y,
start_pos.z + cell_pos.z,
);
let options = ChunkNoiseFunctionSampleOptions::new( let options = ChunkNoiseFunctionSampleOptions::new(
false, false,
SampleAction::CellCaches(WrapperData::new( SampleAction::CellCaches(WrapperData::new(
cell_pos.x as usize, cell_x as usize,
cell_pos.y as usize, cell_y as usize,
cell_pos.z as usize, cell_z as usize,
self.horizontal_cell_block_count() as usize, self.horizontal_cell_block_count() as usize,
self.vertical_cell_block_count() as usize, self.vertical_cell_block_count() as usize,
)), )),

View File

@ -5,7 +5,7 @@ use pumpkin_data::{
tag::Taggable, tag::Taggable,
}; };
use pumpkin_util::{ use pumpkin_util::{
math::{position::BlockPos, vector2::Vector2}, math::position::BlockPos,
random::{RandomGenerator, RandomImpl}, random::{RandomGenerator, RandomImpl},
}; };
use serde::Deserialize; use serde::Deserialize;
@ -38,11 +38,8 @@ impl BambooFeature {
let rnd = random.next_bounded_i32(4) + 1; let rnd = random.next_bounded_i32(4) + 1;
for x in pos.0.x - rnd..pos.0.x + rnd { for x in pos.0.x - rnd..pos.0.x + rnd {
for z in pos.0.z - rnd..pos.0.z + rnd { for z in pos.0.z - rnd..pos.0.z + rnd {
let block_below = BlockPos::new( let block_below =
x, BlockPos::new(x, chunk.top_block_height_exclusive(x, z) - 1, z);
chunk.top_block_height_exclusive(&Vector2::new(x, z)) - 1,
z,
);
let block = GenerationCache::get_block_state(chunk, &block_below.0); let block = GenerationCache::get_block_state(chunk, &block_below.0);
if !block.to_block().has_tag(&tag::Block::MINECRAFT_DIRT) { if !block.to_block().has_tag(&tag::Block::MINECRAFT_DIRT) {
continue; continue;

View File

@ -57,7 +57,7 @@ impl OreFeature {
for _ in n..=(n + q) { for _ in n..=(n + q) {
for _ in p..=(p + q) { for _ in p..=(p + q) {
if o > chunk.ocean_floor_height_exclusive(&pos.0.to_vec2_i32()) { if o > chunk.ocean_floor_height_exclusive(pos.0.x, pos.0.z) {
continue; continue;
} }
return self.generate_vein_part(chunk, random, d, e, h, j, l, m, n, o, p, q, r); return self.generate_vein_part(chunk, random, d, e, h, j, l, m, n, o, p, q, r);

View File

@ -4,7 +4,7 @@ use pumpkin_data::{
block_properties::{BlockProperties, EnumVariants, Integer1To4, SeaPickleLikeProperties}, block_properties::{BlockProperties, EnumVariants, Integer1To4, SeaPickleLikeProperties},
}; };
use pumpkin_util::{ use pumpkin_util::{
math::{int_provider::IntProvider, position::BlockPos, vector2::Vector2}, math::{int_provider::IntProvider, position::BlockPos},
random::{RandomGenerator, RandomImpl}, random::{RandomGenerator, RandomImpl},
}; };
use serde::Deserialize; use serde::Deserialize;
@ -29,7 +29,7 @@ impl SeaPickleFeature {
for _ in 0..count { for _ in 0..count {
let x = random.next_bounded_i32(8) - random.next_bounded_i32(8); let x = random.next_bounded_i32(8) - random.next_bounded_i32(8);
let z = random.next_bounded_i32(8) - random.next_bounded_i32(8); let z = random.next_bounded_i32(8) - random.next_bounded_i32(8);
let y = chunk.ocean_floor_height_exclusive(&Vector2::new(pos.0.x + x, pos.0.z + z)); let y = chunk.ocean_floor_height_exclusive(pos.0.x + x, pos.0.z + z);
if GenerationCache::get_block_state(chunk, &pos.0).to_block() != &Block::WATER { if GenerationCache::get_block_state(chunk, &pos.0).to_block() != &Block::WATER {
continue; continue;
} }

View File

@ -4,7 +4,7 @@ use pumpkin_data::{
block_properties::{BlockProperties, DoubleBlockHalf, TallSeagrassLikeProperties}, block_properties::{BlockProperties, DoubleBlockHalf, TallSeagrassLikeProperties},
}; };
use pumpkin_util::{ use pumpkin_util::{
math::{position::BlockPos, vector2::Vector2}, math::position::BlockPos,
random::{RandomGenerator, RandomImpl}, random::{RandomGenerator, RandomImpl},
}; };
use serde::Deserialize; use serde::Deserialize;
@ -26,7 +26,7 @@ impl SeagrassFeature {
) -> bool { ) -> bool {
let x = random.next_bounded_i32(8) - random.next_bounded_i32(8); let x = random.next_bounded_i32(8) - random.next_bounded_i32(8);
let z = random.next_bounded_i32(8) - random.next_bounded_i32(8); let z = random.next_bounded_i32(8) - random.next_bounded_i32(8);
let y = chunk.ocean_floor_height_exclusive(&Vector2::new(pos.0.x + x, pos.0.z + z)); let y = chunk.ocean_floor_height_exclusive(pos.0.x + x, pos.0.z + z);
let top_pos = BlockPos::new(pos.0.x + x, y, pos.0.z + z); let top_pos = BlockPos::new(pos.0.x + x, y, pos.0.z + z);
if GenerationCache::get_block_state(chunk, &top_pos.0).to_block() == &Block::WATER { if GenerationCache::get_block_state(chunk, &top_pos.0).to_block() == &Block::WATER {
let tall = random.next_f64() < self.probability as f64; let tall = random.next_f64() < self.probability as f64;

View File

@ -9,7 +9,6 @@ use std::sync::LazyLock;
use pumpkin_util::biome::FOLIAGE_NOISE; use pumpkin_util::biome::FOLIAGE_NOISE;
use pumpkin_util::math::int_provider::IntProvider; use pumpkin_util::math::int_provider::IntProvider;
use pumpkin_util::math::position::BlockPos; use pumpkin_util::math::position::BlockPos;
use pumpkin_util::math::vector2::Vector2;
use pumpkin_util::math::vector3::Vector3; use pumpkin_util::math::vector3::Vector3;
use pumpkin_util::random::{RandomGenerator, RandomImpl}; use pumpkin_util::random::{RandomGenerator, RandomImpl};
@ -28,7 +27,7 @@ pub static PLACED_FEATURES: LazyLock<HashMap<String, PlacedFeature>> = LazyLock:
#[derive(Deserialize)] #[derive(Deserialize)]
#[serde(untagged)] #[serde(untagged)]
pub enum PlacedFeatureWrapper { pub enum PlacedFeatureWrapper {
Direct(Box<PlacedFeature>), Direct(PlacedFeature),
Named(String), Named(String),
} }
@ -325,7 +324,7 @@ impl CountOnEveryLayerPlacementModifier {
for _j in 0..self.count.get(random) { for _j in 0..self.count.get(random) {
let x = random.next_bounded_i32(16) + pos.0.x; let x = random.next_bounded_i32(16) + pos.0.x;
let z = random.next_bounded_i32(16) + pos.0.z; let z = random.next_bounded_i32(16) + pos.0.z;
let y = chunk.top_motion_blocking_block_height_exclusive(&Vector2::new(x, z)); let y = chunk.top_motion_blocking_block_height_exclusive(x, z);
let n = Self::find_pos(chunk, x, y, z, i); let n = Self::find_pos(chunk, x, y, z, i);
@ -406,7 +405,7 @@ impl ConditionalPlacementModifier for SurfaceThresholdFilterPlacementModifier {
_random: &mut RandomGenerator, _random: &mut RandomGenerator,
pos: BlockPos, pos: BlockPos,
) -> bool { ) -> bool {
let y = chunk.get_top_y(&self.heightmap, &pos.0.to_vec2_i32()); let y = chunk.get_top_y(&self.heightmap, pos.0.x, pos.0.z);
let min = y.saturating_add(self.min_inclusive.unwrap_or(i32::MIN)); let min = y.saturating_add(self.min_inclusive.unwrap_or(i32::MIN));
let max = y.saturating_add(self.max_inclusive.unwrap_or(i32::MAX)); let max = y.saturating_add(self.max_inclusive.unwrap_or(i32::MAX));
min <= pos.0.y && pos.0.y <= max min <= pos.0.y && pos.0.y <= max
@ -470,8 +469,8 @@ impl ConditionalPlacementModifier for SurfaceWaterDepthFilterPlacementModifier {
_random: &mut RandomGenerator, _random: &mut RandomGenerator,
pos: BlockPos, pos: BlockPos,
) -> bool { ) -> bool {
let world_top = chunk.top_block_height_exclusive(&Vector2::new(pos.0.x, pos.0.z)); let world_top = chunk.top_block_height_exclusive(pos.0.x, pos.0.z);
let ocean = chunk.ocean_floor_height_exclusive(&Vector2::new(pos.0.x, pos.0.z)); let ocean = chunk.ocean_floor_height_exclusive(pos.0.x, pos.0.z);
world_top - ocean <= self.max_water_depth world_top - ocean <= self.max_water_depth
} }
} }
@ -490,7 +489,7 @@ impl ConditionalPlacementModifier for BiomePlacementModifier {
) -> bool { ) -> bool {
// we check if the current feature can be applied to the biome at the pos // we check if the current feature can be applied to the biome at the pos
let name = format!("minecraft:{this_feature}"); let name = format!("minecraft:{this_feature}");
let biome = chunk.get_biome_for_terrain_gen(&pos.0); let biome = chunk.get_biome_for_terrain_gen(pos.0.x, pos.0.y, pos.0.z);
for feature in biome.features { for feature in biome.features {
if feature.contains(&name.deref()) { if feature.contains(&name.deref()) {
@ -536,7 +535,7 @@ impl HeightmapPlacementModifier {
) -> Box<dyn Iterator<Item = BlockPos>> { ) -> Box<dyn Iterator<Item = BlockPos>> {
let x = pos.0.x; let x = pos.0.x;
let z = pos.0.z; let z = pos.0.z;
let top = chunk.get_top_y(&self.heightmap, &Vector2::new(x, z)); let top = chunk.get_top_y(&self.heightmap, x, z);
if top > min_y as i32 { if top > min_y as i32 {
return Box::new(iter::once(BlockPos(Vector3::new(x, top, z)))); return Box::new(iter::once(BlockPos(Vector3::new(x, top, z))));
} }

View File

@ -33,8 +33,8 @@ pub struct VeryBiasedToBottomHeightProvider {
impl VeryBiasedToBottomHeightProvider { impl VeryBiasedToBottomHeightProvider {
pub fn get(&self, random: &mut RandomGenerator, min_y: i8, height: u16) -> i32 { pub fn get(&self, random: &mut RandomGenerator, min_y: i8, height: u16) -> i32 {
let min = self.min_inclusive.get_y(min_y, height) as i32; let min = self.min_inclusive.get_y(min_y as i16, height);
let max = self.max_inclusive.get_y(min_y, height) as i32; let max = self.max_inclusive.get_y(min_y as i16, height);
let inner = self.inner.unwrap_or(1) as i32; let inner = self.inner.unwrap_or(1) as i32;
let min_rnd = random.next_inbetween_i32(min + inner, max); let min_rnd = random.next_inbetween_i32(min + inner, max);
@ -52,8 +52,8 @@ pub struct UniformHeightProvider {
impl UniformHeightProvider { impl UniformHeightProvider {
pub fn get(&self, random: &mut RandomGenerator, min_y: i8, height: u16) -> i32 { pub fn get(&self, random: &mut RandomGenerator, min_y: i8, height: u16) -> i32 {
let min = self.min_inclusive.get_y(min_y, height) as i32; let min = self.min_inclusive.get_y(min_y as i16, height);
let max = self.max_inclusive.get_y(min_y, height) as i32; let max = self.max_inclusive.get_y(min_y as i16, height);
random.next_inbetween_i32(min, max) random.next_inbetween_i32(min, max)
} }
@ -69,21 +69,21 @@ pub struct TrapezoidHeightProvider {
impl TrapezoidHeightProvider { impl TrapezoidHeightProvider {
pub fn get(&self, random: &mut RandomGenerator, min_y: i8, height: u16) -> i32 { pub fn get(&self, random: &mut RandomGenerator, min_y: i8, height: u16) -> i32 {
let plateau = self.plateau.unwrap_or(0); let plateau = self.plateau.unwrap_or(0);
let i = self.min_inclusive.get_y(min_y, height); let i = self.min_inclusive.get_y(min_y as i16, height);
let j = self.max_inclusive.get_y(min_y, height); let j = self.max_inclusive.get_y(min_y as i16, height);
if i > j { if i > j {
log::warn!("Empty height range"); log::warn!("Empty height range");
return i as i32; return i;
} }
let k = j - i; let k = j - i;
if plateau >= k as i32 { if plateau >= k {
return random.next_inbetween_i32(i as i32, j as i32); return random.next_inbetween_i32(i, j);
} }
let l = (k as i32 - plateau) / 2; let l = (k - plateau) / 2;
let m = k as i32 - l; let m = k - l;
i as i32 + random.next_inbetween_i32(0, m) + random.next_inbetween_i32(0, l) i + random.next_inbetween_i32(0, m) + random.next_inbetween_i32(0, l)
} }
} }

View File

@ -6,7 +6,7 @@ use super::{
density_function::{IndexToNoisePos, NoiseFunctionComponentRange, NoisePos}, density_function::{IndexToNoisePos, NoiseFunctionComponentRange, NoisePos},
}; };
use enum_dispatch::enum_dispatch; use enum_dispatch::enum_dispatch;
use pumpkin_util::math::{lerp, lerp3, vector2::Vector2}; use pumpkin_util::math::{lerp, lerp3};
use crate::generation::{biome_coords, positions::chunk_pos}; use crate::generation::{biome_coords, positions::chunk_pos};
@ -486,7 +486,7 @@ impl MutableChunkNoiseFunctionComponentImpl for Cache2D {
pos: &impl NoisePos, pos: &impl NoisePos,
sample_options: &ChunkNoiseFunctionSampleOptions, sample_options: &ChunkNoiseFunctionSampleOptions,
) -> f64 { ) -> f64 {
let packed_column = chunk_pos::packed(&Vector2::new(pos.x(), pos.z())); let packed_column = chunk_pos::packed(pos.x() as u64, pos.z() as u64);
if packed_column == self.last_sample_column { if packed_column == self.last_sample_column {
self.last_sample_result self.last_sample_result
} else { } else {

View File

@ -70,7 +70,7 @@ pub enum ChunkNoiseFunctionComponent<'a> {
Dependent(&'a DependentProtoNoiseFunctionComponent), Dependent(&'a DependentProtoNoiseFunctionComponent),
// NOTE: The box here is intentional: we want to bring down the size to keep the component stack // NOTE: The box here is intentional: we want to bring down the size to keep the component stack
// smaller // smaller
Chunk(Box<ChunkSpecificNoiseFunctionComponent>), Chunk(ChunkSpecificNoiseFunctionComponent),
PassThrough(PassThrough), PassThrough(PassThrough),
//Panic(String), //Panic(String),
} }
@ -360,7 +360,7 @@ impl<'a> ChunkNoiseRouter<'a> {
match wrapper.wrapper_type { match wrapper.wrapper_type {
WrapperType::Interpolated => { WrapperType::Interpolated => {
interpolator_indices.push(component_index); interpolator_indices.push(component_index);
ChunkNoiseFunctionComponent::Chunk(Box::new( ChunkNoiseFunctionComponent::Chunk(
ChunkSpecificNoiseFunctionComponent::DensityInterpolator( ChunkSpecificNoiseFunctionComponent::DensityInterpolator(
DensityInterpolator::new( DensityInterpolator::new(
wrapper.input_index, wrapper.input_index,
@ -369,33 +369,33 @@ impl<'a> ChunkNoiseRouter<'a> {
build_options, build_options,
), ),
), ),
)) )
} }
WrapperType::CellCache => { WrapperType::CellCache => {
cell_cache_indices.push(component_index); cell_cache_indices.push(component_index);
ChunkNoiseFunctionComponent::Chunk(Box::new( ChunkNoiseFunctionComponent::Chunk(
ChunkSpecificNoiseFunctionComponent::CellCache(CellCache::new( ChunkSpecificNoiseFunctionComponent::CellCache(CellCache::new(
wrapper.input_index, wrapper.input_index,
min_value, min_value,
max_value, max_value,
build_options, build_options,
)), )),
)) )
} }
WrapperType::CacheOnce => ChunkNoiseFunctionComponent::Chunk(Box::new( WrapperType::CacheOnce => ChunkNoiseFunctionComponent::Chunk(
ChunkSpecificNoiseFunctionComponent::CacheOnce(CacheOnce::new( ChunkSpecificNoiseFunctionComponent::CacheOnce(CacheOnce::new(
wrapper.input_index, wrapper.input_index,
min_value, min_value,
max_value, max_value,
)), )),
)), ),
WrapperType::Cache2D => ChunkNoiseFunctionComponent::Chunk(Box::new( WrapperType::Cache2D => ChunkNoiseFunctionComponent::Chunk(
ChunkSpecificNoiseFunctionComponent::Cache2D(Cache2D::new( ChunkSpecificNoiseFunctionComponent::Cache2D(Cache2D::new(
wrapper.input_index, wrapper.input_index,
min_value, min_value,
max_value, max_value,
)), )),
)), ),
WrapperType::CacheFlat => { WrapperType::CacheFlat => {
let mut flat_cache = FlatCache::new( let mut flat_cache = FlatCache::new(
wrapper.input_index, wrapper.input_index,
@ -445,9 +445,9 @@ impl<'a> ChunkNoiseRouter<'a> {
} }
} }
ChunkNoiseFunctionComponent::Chunk(Box::new( ChunkNoiseFunctionComponent::Chunk(
ChunkSpecificNoiseFunctionComponent::FlatCache(flat_cache), ChunkSpecificNoiseFunctionComponent::FlatCache(flat_cache),
)) )
} }
} }
} }
@ -485,7 +485,7 @@ impl<'a> ChunkNoiseRouter<'a> {
let ChunkNoiseFunctionComponent::Chunk(chunk) = component.first_mut().unwrap() else { let ChunkNoiseFunctionComponent::Chunk(chunk) = component.first_mut().unwrap() else {
unreachable!(); unreachable!();
}; };
let ChunkSpecificNoiseFunctionComponent::CellCache(cell_cache) = chunk.as_mut() else { let ChunkSpecificNoiseFunctionComponent::CellCache(cell_cache) = chunk else {
unreachable!(); unreachable!();
}; };
@ -514,7 +514,7 @@ impl<'a> ChunkNoiseRouter<'a> {
unreachable!(); unreachable!();
}; };
let ChunkSpecificNoiseFunctionComponent::DensityInterpolator(density_interpolator) = let ChunkSpecificNoiseFunctionComponent::DensityInterpolator(density_interpolator) =
chunk.as_mut() chunk
else { else {
unreachable!(); unreachable!();
}; };
@ -547,7 +547,7 @@ impl<'a> ChunkNoiseRouter<'a> {
}; };
let ChunkSpecificNoiseFunctionComponent::DensityInterpolator(density_interpolator) = let ChunkSpecificNoiseFunctionComponent::DensityInterpolator(density_interpolator) =
chunk.as_mut() chunk
else { else {
unreachable!(); unreachable!();
}; };
@ -566,7 +566,7 @@ impl<'a> ChunkNoiseRouter<'a> {
}; };
let ChunkSpecificNoiseFunctionComponent::DensityInterpolator(density_interpolator) = let ChunkSpecificNoiseFunctionComponent::DensityInterpolator(density_interpolator) =
chunk.as_mut() chunk
else { else {
unreachable!(); unreachable!();
}; };
@ -584,7 +584,7 @@ impl<'a> ChunkNoiseRouter<'a> {
unreachable!(); unreachable!();
}; };
let ChunkSpecificNoiseFunctionComponent::DensityInterpolator(density_interpolator) = let ChunkSpecificNoiseFunctionComponent::DensityInterpolator(density_interpolator) =
chunk.as_mut() chunk
else { else {
unreachable!(); unreachable!();
}; };
@ -602,7 +602,7 @@ impl<'a> ChunkNoiseRouter<'a> {
unreachable!(); unreachable!();
}; };
let ChunkSpecificNoiseFunctionComponent::DensityInterpolator(density_interpolator) = let ChunkSpecificNoiseFunctionComponent::DensityInterpolator(density_interpolator) =
chunk.as_mut() chunk
else { else {
unreachable!(); unreachable!();
}; };
@ -620,7 +620,7 @@ impl<'a> ChunkNoiseRouter<'a> {
unreachable!(); unreachable!();
}; };
let ChunkSpecificNoiseFunctionComponent::DensityInterpolator(density_interpolator) = let ChunkSpecificNoiseFunctionComponent::DensityInterpolator(density_interpolator) =
chunk.as_mut() chunk
else { else {
unreachable!(); unreachable!();
}; };

View File

@ -181,9 +181,9 @@ impl ShiftedNoise {
} }
pub struct InterpolatedNoiseSampler { pub struct InterpolatedNoiseSampler {
lower_noise: Box<OctavePerlinNoiseSampler>, lower_noise: OctavePerlinNoiseSampler,
upper_noise: Box<OctavePerlinNoiseSampler>, upper_noise: OctavePerlinNoiseSampler,
noise: Box<OctavePerlinNoiseSampler>, noise: OctavePerlinNoiseSampler,
data: &'static InterpolatedNoiseSamplerData, data: &'static InterpolatedNoiseSamplerData,
fractions: [f64; 16], fractions: [f64; 16],
max_value: f64, max_value: f64,
@ -197,24 +197,9 @@ impl InterpolatedNoiseSampler {
let little_start = -7; let little_start = -7;
let little_amplitudes = [1.0; 8]; let little_amplitudes = [1.0; 8];
let lower_noise = Box::new(OctavePerlinNoiseSampler::new( let lower_noise = OctavePerlinNoiseSampler::new(random, big_start, &big_amplitudes, true);
random, let upper_noise = OctavePerlinNoiseSampler::new(random, big_start, &big_amplitudes, true);
big_start, let noise = OctavePerlinNoiseSampler::new(random, little_start, &little_amplitudes, true);
&big_amplitudes,
true,
));
let upper_noise = Box::new(OctavePerlinNoiseSampler::new(
random,
big_start,
&big_amplitudes,
true,
));
let noise = Box::new(OctavePerlinNoiseSampler::new(
random,
little_start,
&little_amplitudes,
true,
));
let max_value = lower_noise.get_total_amplitude(data.scaled_y_scale + 2.0); let max_value = lower_noise.get_total_amplitude(data.scaled_y_scale + 2.0);

View File

@ -7,7 +7,6 @@ use pumpkin_data::noise_router::{self, BaseNoiseFunctionComponent};
use serde::Deserialize; use serde::Deserialize;
// I do a lot of leaking here, but its only for testing // I do a lot of leaking here, but its only for testing
pub struct HashableF32(pub f32); pub struct HashableF32(pub f32);
// Normally this is bad, but we just care about checking if components are the same // Normally this is bad, but we just care about checking if components are the same

View File

@ -140,13 +140,13 @@ impl<'a> MultiNoiseSampler<'a> {
let max_value = component_stack[wrapper.input_index].max(); let max_value = component_stack[wrapper.input_index].max();
match wrapper.wrapper_type { match wrapper.wrapper_type {
WrapperType::Cache2D => ChunkNoiseFunctionComponent::Chunk(Box::new( WrapperType::Cache2D => ChunkNoiseFunctionComponent::Chunk(
ChunkSpecificNoiseFunctionComponent::Cache2D(Cache2D::new( ChunkSpecificNoiseFunctionComponent::Cache2D(Cache2D::new(
wrapper.input_index, wrapper.input_index,
min_value, min_value,
max_value, max_value,
)), )),
)), ),
WrapperType::CacheFlat => { WrapperType::CacheFlat => {
let mut flat_cache = FlatCache::new( let mut flat_cache = FlatCache::new(
wrapper.input_index, wrapper.input_index,
@ -196,9 +196,9 @@ impl<'a> MultiNoiseSampler<'a> {
} }
} }
ChunkNoiseFunctionComponent::Chunk(Box::new( ChunkNoiseFunctionComponent::Chunk(
ChunkSpecificNoiseFunctionComponent::FlatCache(flat_cache), ChunkSpecificNoiseFunctionComponent::FlatCache(flat_cache),
)) )
} }
// Java passes thru if the noise pos is not the chunk itself, which it is // Java passes thru if the noise pos is not the chunk itself, which it is
// never for the MultiNoiseSampler // never for the MultiNoiseSampler

View File

@ -68,7 +68,7 @@ impl<'a> DoublePerlinNoiseBuilder<'a> {
} }
} }
pub fn get_noise_sampler_for_id(&mut self, id: &str) -> DoublePerlinNoiseSampler { pub fn get_noise_sampler_for_id(&self, id: &str) -> DoublePerlinNoiseSampler {
let parameters = DoublePerlinNoiseParameters::id_to_parameters(id) let parameters = DoublePerlinNoiseParameters::id_to_parameters(id)
.unwrap_or_else(|| panic!("Unknown noise id: {id}")); .unwrap_or_else(|| panic!("Unknown noise id: {id}"));
@ -140,7 +140,7 @@ impl ProtoNoiseRouters {
base_stack: &[BaseNoiseFunctionComponent], base_stack: &[BaseNoiseFunctionComponent],
random_config: &GlobalRandomConfig, random_config: &GlobalRandomConfig,
) -> Box<[ProtoNoiseFunctionComponent]> { ) -> Box<[ProtoNoiseFunctionComponent]> {
let mut perlin_noise_builder = DoublePerlinNoiseBuilder::new(random_config); let perlin_noise_builder = DoublePerlinNoiseBuilder::new(random_config);
// Contiguous memory for our function components // Contiguous memory for our function components
let mut stack = Vec::<ProtoNoiseFunctionComponent>::with_capacity(base_stack.len()); let mut stack = Vec::<ProtoNoiseFunctionComponent>::with_capacity(base_stack.len());

View File

@ -1,7 +1,6 @@
use std::collections::HashMap; use std::collections::HashMap;
use pumpkin_data::noise_router::WrapperType; use pumpkin_data::noise_router::WrapperType;
use pumpkin_util::math::vector2::Vector2;
use crate::generation::{biome_coords, positions::chunk_pos}; use crate::generation::{biome_coords, positions::chunk_pos};
@ -68,7 +67,7 @@ impl<'a> SurfaceHeightEstimateSampler<'a> {
let biome_aligned_x = biome_coords::to_block(biome_coords::from_block(block_x)); let biome_aligned_x = biome_coords::to_block(biome_coords::from_block(block_x));
let biome_aligned_z = biome_coords::to_block(biome_coords::from_block(block_z)); let biome_aligned_z = biome_coords::to_block(biome_coords::from_block(block_z));
let packed_column = chunk_pos::packed(&Vector2::new(biome_aligned_x, biome_aligned_z)); let packed_column = chunk_pos::packed(biome_aligned_x as u64, biome_aligned_z as u64);
if let Some(estimate) = self.cache.get(&packed_column) { if let Some(estimate) = self.cache.get(&packed_column) {
*estimate *estimate
} else { } else {
@ -125,13 +124,13 @@ impl<'a> SurfaceHeightEstimateSampler<'a> {
let max_value = component_stack[wrapper.input_index].max(); let max_value = component_stack[wrapper.input_index].max();
match wrapper.wrapper_type { match wrapper.wrapper_type {
WrapperType::Cache2D => ChunkNoiseFunctionComponent::Chunk(Box::new( WrapperType::Cache2D => ChunkNoiseFunctionComponent::Chunk(
ChunkSpecificNoiseFunctionComponent::Cache2D(Cache2D::new( ChunkSpecificNoiseFunctionComponent::Cache2D(Cache2D::new(
wrapper.input_index, wrapper.input_index,
min_value, min_value,
max_value, max_value,
)), )),
)), ),
WrapperType::CacheFlat => { WrapperType::CacheFlat => {
let mut flat_cache = FlatCache::new( let mut flat_cache = FlatCache::new(
wrapper.input_index, wrapper.input_index,
@ -181,9 +180,9 @@ impl<'a> SurfaceHeightEstimateSampler<'a> {
} }
} }
ChunkNoiseFunctionComponent::Chunk(Box::new( ChunkNoiseFunctionComponent::Chunk(
ChunkSpecificNoiseFunctionComponent::FlatCache(flat_cache), ChunkSpecificNoiseFunctionComponent::FlatCache(flat_cache),
)) )
} }
// Java passes thru if the noise pos is not the chunk itself, which it is // Java passes thru if the noise pos is not the chunk itself, which it is
// never for the Height estimator // never for the Height estimator

View File

@ -39,10 +39,10 @@ pub mod chunk_pos {
use crate::generation::section_coords::get_offset_pos; use crate::generation::section_coords::get_offset_pos;
// A chunk outside of normal bounds // A chunk outside of normal bounds
pub const MARKER: u64 = packed(&Vector2::new(1875066, 1875066)); pub const MARKER: u64 = packed(1875066, 1875066);
pub const fn packed(vec: &Vector2<i32>) -> u64 { pub const fn packed(x: u64, y: u64) -> u64 {
(vec.x as u64 & 4294967295u64) | ((vec.y as u64 & 4294967295u64) << 32) (x & 4294967295u64) | ((y & 4294967295u64) << 32)
} }
pub const fn unpack_x(packed: u64) -> i32 { pub const fn unpack_x(packed: u64) -> i32 {
@ -69,20 +69,20 @@ pub mod chunk_pos {
get_offset_pos(coord, offset) get_offset_pos(coord, offset)
} }
pub const fn start_block_x(vec: &Vector2<i32>) -> i32 { pub const fn start_block_x(x: i32) -> i32 {
vec.x << 4 x << 4
} }
pub const fn end_block_x(vec: &Vector2<i32>) -> i32 { pub const fn end_block_x(x: i32) -> i32 {
start_block_x(vec) + 15 start_block_x(x) + 15
} }
pub const fn start_block_z(vec: &Vector2<i32>) -> i32 { pub const fn start_block_z(z: i32) -> i32 {
vec.y << 4 z << 4
} }
pub const fn end_block_z(vec: &Vector2<i32>) -> i32 { pub const fn end_block_z(z: i32) -> i32 {
start_block_z(vec) + 15 start_block_z(z) + 15
} }
pub const fn to_chunk_pos(vec: &Vector2<i32>) -> Vector2<i32> { pub const fn to_chunk_pos(vec: &Vector2<i32>) -> Vector2<i32> {
@ -107,17 +107,18 @@ pub const MIN_HEIGHT_CELL: i32 = MIN_HEIGHT << 4;
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use pumpkin_util::math::{vector2::Vector2, vector3::Vector3}; use pumpkin_util::math::vector3::Vector3;
use super::{block_pos, chunk_pos}; use super::{block_pos, chunk_pos};
#[test] #[test]
fn test_chunk_packing() { fn test_chunk_packing() {
let pos = Vector2::new(305135135, -1351513511); let x = 305135135_i32;
let packed = chunk_pos::packed(&pos); let y = -1351513511_i32;
let packed = chunk_pos::packed(x as u64, y as u64);
assert_eq!(packed as i64, -5804706329542001121i64); assert_eq!(packed as i64, -5804706329542001121i64);
assert_eq!(pos.x, chunk_pos::unpack_x(packed)); assert_eq!(x, chunk_pos::unpack_x(packed));
assert_eq!(pos.y, chunk_pos::unpack_z(packed)); assert_eq!(y, chunk_pos::unpack_z(packed));
} }
#[test] #[test]

View File

@ -9,7 +9,7 @@ use pumpkin_data::{
use pumpkin_util::math::block_box::BlockBox; use pumpkin_util::math::block_box::BlockBox;
use pumpkin_util::{ use pumpkin_util::{
HeightMap, HeightMap,
math::{position::BlockPos, vector2::Vector2, vector3::Vector3}, math::{position::BlockPos, vector3::Vector3},
random::{RandomGenerator, get_decorator_seed, xoroshiro128::Xoroshiro}, random::{RandomGenerator, get_decorator_seed, xoroshiro128::Xoroshiro},
}; };
@ -52,13 +52,13 @@ pub trait GenerationCache: HeightLimitView + BlockAccessor {
fn get_block_state(&self, pos: &Vector3<i32>) -> RawBlockState; fn get_block_state(&self, pos: &Vector3<i32>) -> RawBlockState;
fn get_fluid_and_fluid_state(&self, position: &Vector3<i32>) -> (Fluid, FluidState); fn get_fluid_and_fluid_state(&self, position: &Vector3<i32>) -> (Fluid, FluidState);
fn set_block_state(&mut self, pos: &Vector3<i32>, block_state: &BlockState); fn set_block_state(&mut self, pos: &Vector3<i32>, block_state: &BlockState);
fn top_motion_blocking_block_height_exclusive(&self, pos: &Vector2<i32>) -> i32; fn top_motion_blocking_block_height_exclusive(&self, x: i32, z: i32) -> i32;
fn top_motion_blocking_block_no_leaves_height_exclusive(&self, pos: &Vector2<i32>) -> i32; fn top_motion_blocking_block_no_leaves_height_exclusive(&self, x: i32, z: i32) -> i32;
fn get_top_y(&self, heightmap: &HeightMap, pos: &Vector2<i32>) -> i32; fn get_top_y(&self, heightmap: &HeightMap, x: i32, z: i32) -> i32;
fn top_block_height_exclusive(&self, pos: &Vector2<i32>) -> i32; fn top_block_height_exclusive(&self, x: i32, z: i32) -> i32;
fn ocean_floor_height_exclusive(&self, pos: &Vector2<i32>) -> i32; fn ocean_floor_height_exclusive(&self, x: i32, z: i32) -> i32;
fn is_air(&self, local_pos: &Vector3<i32>) -> bool; fn is_air(&self, local_pos: &Vector3<i32>) -> bool;
fn get_biome_for_terrain_gen(&self, global_block_pos: &Vector3<i32>) -> &'static Biome; fn get_biome_for_terrain_gen(&self, x: i32, y: i32, z: i32) -> &'static Biome;
} }
const AIR_BLOCK: Block = Block::AIR; const AIR_BLOCK: Block = Block::AIR;
@ -120,7 +120,8 @@ impl FluidLevelSamplerImpl for StandardChunkFluidLevelSampler {
/// ///
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct ProtoChunk { pub struct ProtoChunk {
pub chunk_pos: Vector2<i32>, pub x: i32,
pub z: i32,
pub default_block: &'static BlockState, pub default_block: &'static BlockState,
biome_mixer_seed: i64, biome_mixer_seed: i64,
// These are local positions // These are local positions
@ -150,8 +151,8 @@ pub struct TerrainCache {
impl TerrainCache { impl TerrainCache {
pub fn from_random(random_config: &GlobalRandomConfig) -> Self { pub fn from_random(random_config: &GlobalRandomConfig) -> Self {
let random = &random_config.base_random_deriver; let random = &random_config.base_random_deriver;
let mut noise_builder = DoublePerlinNoiseBuilder::new(random_config); let noise_builder = DoublePerlinNoiseBuilder::new(random_config);
let terrain_builder = SurfaceTerrainBuilder::new(&mut noise_builder, random); let terrain_builder = SurfaceTerrainBuilder::new(&noise_builder, random);
let surface_noise = noise_builder.get_noise_sampler_for_id("surface"); let surface_noise = noise_builder.get_noise_sampler_for_id("surface");
let secondary_noise = noise_builder.get_noise_sampler_for_id("surface_secondary"); let secondary_noise = noise_builder.get_noise_sampler_for_id("surface_secondary");
Self { Self {
@ -164,7 +165,8 @@ impl TerrainCache {
impl ProtoChunk { impl ProtoChunk {
pub fn new( pub fn new(
chunk_pos: Vector2<i32>, x: i32,
z: i32,
settings: &GenerationSettings, settings: &GenerationSettings,
default_block: &'static BlockState, default_block: &'static BlockState,
biome_mixer_seed: i64, biome_mixer_seed: i64,
@ -174,7 +176,8 @@ impl ProtoChunk {
let default_heightmap = vec![i16::MIN; CHUNK_AREA].into_boxed_slice(); let default_heightmap = vec![i16::MIN; CHUNK_AREA].into_boxed_slice();
Self { Self {
chunk_pos, x,
z,
default_block, default_block,
flat_block_map: vec![0; CHUNK_AREA * height as usize].into_boxed_slice(), flat_block_map: vec![0; CHUNK_AREA * height as usize].into_boxed_slice(),
flat_biome_map: vec![ flat_biome_map: vec![
@ -203,7 +206,8 @@ impl ProtoChunk {
biome_mixer_seed: i64, biome_mixer_seed: i64,
) -> Self { ) -> Self {
let mut proto_chunk = ProtoChunk::new( let mut proto_chunk = ProtoChunk::new(
chunk_data.position, chunk_data.x,
chunk_data.z,
settings, settings,
default_block, default_block,
biome_mixer_seed, biome_mixer_seed,
@ -233,12 +237,11 @@ impl ProtoChunk {
let biome = Biome::from_id(biome_id).unwrap(); let biome = Biome::from_id(biome_id).unwrap();
let relative_y_block = (section_y as i32 * 16) + (y as i32 * 4); let relative_y_block = (section_y as i32 * 16) + (y as i32 * 4);
let local_biome_pos = Vector3::new( let index = proto_chunk.local_biome_pos_to_biome_index(
x as i32, x as i32,
biome_coords::from_block(relative_y_block), biome_coords::from_block(relative_y_block),
z as i32, z as i32,
); );
let index = proto_chunk.local_biome_pos_to_biome_index(&local_biome_pos);
proto_chunk.flat_biome_map[index] = biome; proto_chunk.flat_biome_map[index] = biome;
} }
} }
@ -290,87 +293,84 @@ impl ProtoChunk {
self.bottom_y self.bottom_y
} }
fn maybe_update_surface_height_map(&mut self, pos: &Vector3<i32>) { fn maybe_update_surface_height_map(&mut self, local_x: i32, y: i32, local_z: i32) {
let local_x = pos.x & 15;
let local_z = pos.z & 15;
let index = Self::local_position_to_height_map_index(local_x, local_z); let index = Self::local_position_to_height_map_index(local_x, local_z);
let current_height = self.flat_surface_height_map[index]; let current_height = self.flat_surface_height_map[index];
if pos.y > current_height as i32 { if y > current_height as i32 {
self.flat_surface_height_map[index] = pos.y as _; self.flat_surface_height_map[index] = y as _;
} }
} }
fn maybe_update_ocean_floor_height_map(&mut self, pos: &Vector3<i32>) { fn maybe_update_ocean_floor_height_map(&mut self, local_x: i32, y: i32, local_z: i32) {
let local_x = pos.x & 15;
let local_z = pos.z & 15;
let index = Self::local_position_to_height_map_index(local_x, local_z); let index = Self::local_position_to_height_map_index(local_x, local_z);
let current_height = self.flat_ocean_floor_height_map[index]; let current_height = self.flat_ocean_floor_height_map[index];
if pos.y > current_height as i32 { if y > current_height as i32 {
self.flat_ocean_floor_height_map[index] = pos.y as _; self.flat_ocean_floor_height_map[index] = y as _;
} }
} }
fn maybe_update_motion_blocking_height_map(&mut self, pos: &Vector3<i32>) { fn maybe_update_motion_blocking_height_map(&mut self, local_x: i32, y: i32, local_z: i32) {
let local_x = pos.x & 15;
let local_z = pos.z & 15;
let index = Self::local_position_to_height_map_index(local_x, local_z); let index = Self::local_position_to_height_map_index(local_x, local_z);
let current_height = self.flat_motion_blocking_height_map[index]; let current_height = self.flat_motion_blocking_height_map[index];
if pos.y > current_height as i32 { if y > current_height as i32 {
self.flat_motion_blocking_height_map[index] = pos.y as _; self.flat_motion_blocking_height_map[index] = y as _;
} }
} }
fn maybe_update_motion_blocking_no_leaves_height_map(&mut self, pos: &Vector3<i32>) { fn maybe_update_motion_blocking_no_leaves_height_map(
let local_x = pos.x & 15; &mut self,
let local_z = pos.z & 15; local_x: i32,
y: i32,
local_z: i32,
) {
let index = Self::local_position_to_height_map_index(local_x, local_z); let index = Self::local_position_to_height_map_index(local_x, local_z);
let current_height = self.flat_motion_blocking_no_leaves_height_map[index]; let current_height = self.flat_motion_blocking_no_leaves_height_map[index];
if pos.y > current_height as i32 { if y > current_height as i32 {
self.flat_motion_blocking_no_leaves_height_map[index] = pos.y as _; self.flat_motion_blocking_no_leaves_height_map[index] = y as _;
} }
} }
pub fn get_top_y(&self, heightmap: &HeightMap, pos: &Vector2<i32>) -> i32 { pub fn get_top_y(&self, heightmap: &HeightMap, x: i32, z: i32) -> i32 {
match heightmap { match heightmap {
HeightMap::WorldSurfaceWg => self.top_block_height_exclusive(pos), HeightMap::WorldSurfaceWg => self.top_block_height_exclusive(x, z),
HeightMap::WorldSurface => self.top_block_height_exclusive(pos), HeightMap::WorldSurface => self.top_block_height_exclusive(x, z),
HeightMap::OceanFloorWg => self.ocean_floor_height_exclusive(pos), HeightMap::OceanFloorWg => self.ocean_floor_height_exclusive(x, z),
HeightMap::OceanFloor => self.ocean_floor_height_exclusive(pos), HeightMap::OceanFloor => self.ocean_floor_height_exclusive(x, z),
HeightMap::MotionBlocking => self.top_motion_blocking_block_height_exclusive(pos), HeightMap::MotionBlocking => self.top_motion_blocking_block_height_exclusive(x, z),
HeightMap::MotionBlockingNoLeaves => { HeightMap::MotionBlockingNoLeaves => {
self.top_motion_blocking_block_no_leaves_height_exclusive(pos) self.top_motion_blocking_block_no_leaves_height_exclusive(x, z)
} }
} }
} }
pub fn top_block_height_exclusive(&self, pos: &Vector2<i32>) -> i32 { pub fn top_block_height_exclusive(&self, x: i32, z: i32) -> i32 {
let local_x = pos.x & 15; let local_x = x & 15;
let local_z = pos.y & 15; let local_z = z & 15;
let index = Self::local_position_to_height_map_index(local_x, local_z); let index = Self::local_position_to_height_map_index(local_x, local_z);
self.flat_surface_height_map[index] as i32 + 1 self.flat_surface_height_map[index] as i32 + 1
} }
pub fn ocean_floor_height_exclusive(&self, pos: &Vector2<i32>) -> i32 { pub fn ocean_floor_height_exclusive(&self, x: i32, z: i32) -> i32 {
let local_x = pos.x & 15; let local_x = x & 15;
let local_z = pos.y & 15; let local_z = z & 15;
let index = Self::local_position_to_height_map_index(local_x, local_z); let index = Self::local_position_to_height_map_index(local_x, local_z);
self.flat_ocean_floor_height_map[index] as i32 + 1 self.flat_ocean_floor_height_map[index] as i32 + 1
} }
pub fn top_motion_blocking_block_height_exclusive(&self, pos: &Vector2<i32>) -> i32 { pub fn top_motion_blocking_block_height_exclusive(&self, x: i32, z: i32) -> i32 {
let local_x = pos.x & 15; let local_x = x & 15;
let local_z = pos.y & 15; let local_z = z & 15;
let index = Self::local_position_to_height_map_index(local_x, local_z); let index = Self::local_position_to_height_map_index(local_x, local_z);
self.flat_motion_blocking_height_map[index] as i32 + 1 self.flat_motion_blocking_height_map[index] as i32 + 1
} }
pub fn top_motion_blocking_block_no_leaves_height_exclusive(&self, pos: &Vector2<i32>) -> i32 { pub fn top_motion_blocking_block_no_leaves_height_exclusive(&self, x: i32, z: i32) -> i32 {
let local_x = pos.x & 15; let local_x = x & 15;
let local_z = pos.y & 15; let local_z = z & 15;
let index = Self::local_position_to_height_map_index(local_x, local_z); let index = Self::local_position_to_height_map_index(local_x, local_z);
self.flat_motion_blocking_no_leaves_height_map[index] as i32 + 1 self.flat_motion_blocking_no_leaves_height_map[index] as i32 + 1
} }
@ -381,40 +381,39 @@ impl ProtoChunk {
} }
#[inline] #[inline]
fn local_pos_to_block_index(&self, local_pos: &Vector3<i32>) -> usize { fn local_pos_to_block_index(&self, x: i32, y: i32, z: i32) -> usize {
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
{ {
assert!(local_pos.x >= 0 && local_pos.x <= 15); assert!((0..=15).contains(&x));
assert!(local_pos.y < self.height() as i32); assert!(y < self.height() as i32);
assert!(local_pos.y >= 0); assert!(y >= 0);
assert!(local_pos.z >= 0 && local_pos.z <= 15); assert!((0..=15).contains(&z));
} }
self.height() as usize * CHUNK_DIM as usize * local_pos.x as usize self.height() as usize * CHUNK_DIM as usize * x as usize
+ CHUNK_DIM as usize * local_pos.y as usize + CHUNK_DIM as usize * y as usize
+ local_pos.z as usize + z as usize
} }
#[inline] #[inline]
fn local_biome_pos_to_biome_index(&self, local_biome_pos: &Vector3<i32>) -> usize { fn local_biome_pos_to_biome_index(&self, x: i32, y: i32, z: i32) -> usize {
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
{ {
assert!(local_biome_pos.x >= 0 && local_biome_pos.x <= 3); assert!((0..=3).contains(&x));
assert!( assert!(
local_biome_pos.y < biome_coords::from_chunk(self.height() as i32) y < biome_coords::from_chunk(self.height() as i32) && y >= 0,
&& local_biome_pos.y >= 0,
"{} - {} vs {}", "{} - {} vs {}",
0, 0,
biome_coords::from_chunk(self.height() as i32), biome_coords::from_chunk(self.height() as i32),
local_biome_pos.y y
); );
assert!(local_biome_pos.z >= 0 && local_biome_pos.z <= 3); assert!((0..=3).contains(&z));
} }
biome_coords::from_block(self.height() as usize) biome_coords::from_block(self.height() as usize)
* biome_coords::from_block(CHUNK_DIM as usize) * biome_coords::from_block(CHUNK_DIM as usize)
* local_biome_pos.x as usize * x as usize
+ biome_coords::from_block(CHUNK_DIM as usize) * local_biome_pos.y as usize + biome_coords::from_block(CHUNK_DIM as usize) * y as usize
+ local_biome_pos.z as usize + z as usize
} }
#[inline] #[inline]
@ -424,76 +423,70 @@ impl ProtoChunk {
} }
#[inline] #[inline]
pub fn get_block_state_raw(&self, local_pos: &Vector3<i32>) -> u16 { pub fn get_block_state_raw(&self, x: i32, y: i32, z: i32) -> u16 {
let index = self.local_pos_to_block_index(local_pos); let index = self.local_pos_to_block_index(x, y, z);
self.flat_block_map[index] self.flat_block_map[index]
} }
#[inline] #[inline]
pub fn get_block_state(&self, local_pos: &Vector3<i32>) -> RawBlockState { pub fn get_block_state(&self, local_pos: &Vector3<i32>) -> RawBlockState {
let local_pos = Vector3::new( let local_y = local_pos.y - self.bottom_y() as i32;
local_pos.x & 15, if local_y < 0 || local_y >= self.height() as i32 {
local_pos.y - self.bottom_y() as i32,
local_pos.z & 15,
);
if local_pos.y < 0 || local_pos.y >= self.height() as i32 {
return RawBlockState(Block::VOID_AIR.default_state.id); return RawBlockState(Block::VOID_AIR.default_state.id);
} }
RawBlockState(self.get_block_state_raw(&local_pos)) RawBlockState(self.get_block_state_raw(local_pos.x & 15, local_y, local_pos.z & 15))
} }
pub fn set_block_state(&mut self, pos: &Vector3<i32>, block_state: &BlockState) { pub fn set_block_state(&mut self, pos: &Vector3<i32>, block_state: &BlockState) {
let local_pos = Vector3::new(pos.x & 15, pos.y - self.bottom_y() as i32, pos.z & 15); let local_x = pos.x & 15;
if local_pos.y < 0 || local_pos.y >= self.height() as i32 { let local_y = pos.y - self.bottom_y() as i32;
let local_z = pos.z & 15;
if local_y < 0 || local_y >= self.height() as i32 {
return; return;
} }
if !block_state.is_air() { if !block_state.is_air() {
self.maybe_update_surface_height_map(pos); self.maybe_update_surface_height_map(local_x, pos.y, local_z);
}
if blocks_movement(block_state) {
self.maybe_update_ocean_floor_height_map(pos);
}
if blocks_movement(block_state) || block_state.is_liquid() {
self.maybe_update_motion_blocking_height_map(pos);
let block = Block::from_state_id(block_state.id); let block = Block::from_state_id(block_state.id);
if !block.has_tag(&tag::Block::MINECRAFT_LEAVES) {
{ let blocks_movement = blocks_movement(block_state, block);
self.maybe_update_motion_blocking_no_leaves_height_map(pos); if blocks_movement {
self.maybe_update_ocean_floor_height_map(local_x, pos.y, local_z);
} else if blocks_movement || block_state.is_liquid() {
self.maybe_update_motion_blocking_height_map(local_x, pos.y, local_z);
if !block.has_tag(&tag::Block::MINECRAFT_LEAVES) {
{
self.maybe_update_motion_blocking_no_leaves_height_map(
local_x, pos.y, local_z,
);
}
} }
} }
} }
let index = self.local_pos_to_block_index(&local_pos); let index = self.local_pos_to_block_index(local_x, local_y, local_z);
self.flat_block_map[index] = block_state.id; self.flat_block_map[index] = block_state.id;
} }
#[inline] #[inline]
pub fn get_biome(&self, global_biome_pos: &Vector3<i32>) -> &'static Biome { pub fn get_biome(&self, x: i32, y: i32, z: i32) -> &'static Biome {
let local_pos = Vector3::new( let index = self.local_biome_pos_to_biome_index(
global_biome_pos.x & biome_coords::from_block(15), x & biome_coords::from_block(15),
global_biome_pos.y - biome_coords::from_block(self.bottom_y() as i32), y - biome_coords::from_block(self.bottom_y() as i32),
global_biome_pos.z & biome_coords::from_block(15), z & biome_coords::from_block(15),
); );
let index = self.local_biome_pos_to_biome_index(&local_pos);
self.flat_biome_map[index] self.flat_biome_map[index]
} }
pub fn step_to_biomes(&mut self, dimension: Dimension, noise_router: &ProtoNoiseRouters) { pub fn step_to_biomes(&mut self, dimension: Dimension, noise_router: &ProtoNoiseRouters) {
debug_assert_eq!(self.stage, StagedChunkEnum::Empty); debug_assert_eq!(self.stage, StagedChunkEnum::Empty);
let chunk_pos = self.chunk_pos; let start_x = start_block_x(self.x);
let start_x = start_block_x(&chunk_pos); let start_z = start_block_z(self.z);
let start_z = start_block_z(&chunk_pos);
let biome_pos = Vector2::new(
biome_coords::from_block(start_x),
biome_coords::from_block(start_z),
);
let horizontal_biome_end = biome_coords::from_block(16); let horizontal_biome_end = biome_coords::from_block(16);
let multi_noise_config = let multi_noise_config =
super::noise::router::multi_noise_sampler::MultiNoiseSamplerBuilderOptions::new( super::noise::router::multi_noise_sampler::MultiNoiseSamplerBuilderOptions::new(
biome_pos.x, biome_coords::from_block(start_x),
biome_pos.y, biome_coords::from_block(start_z),
horizontal_biome_end as usize, horizontal_biome_end as usize,
); );
let mut multi_noise_sampler = let mut multi_noise_sampler =
@ -510,16 +503,15 @@ impl ProtoChunk {
) { ) {
debug_assert_eq!(self.stage, StagedChunkEnum::Biomes); debug_assert_eq!(self.stage, StagedChunkEnum::Biomes);
let chunk_pos = self.chunk_pos;
let generation_shape = &settings.shape; let generation_shape = &settings.shape;
let horizontal_cell_count = CHUNK_DIM / generation_shape.horizontal_cell_block_count(); let horizontal_cell_count = CHUNK_DIM / generation_shape.horizontal_cell_block_count();
let start_x = start_block_x(&chunk_pos); let start_x = start_block_x(self.x);
let start_z = start_block_z(&chunk_pos); let start_z = start_block_z(self.z);
let sampler = FluidLevelSampler::Chunk(Box::new(StandardChunkFluidLevelSampler::new( let sampler = FluidLevelSampler::Chunk(StandardChunkFluidLevelSampler::new(
FluidLevel::new(settings.sea_level, settings.default_fluid.name), FluidLevel::new(settings.sea_level, settings.default_fluid.name),
FluidLevel::new(-54, &Block::LAVA), FluidLevel::new(-54, &Block::LAVA),
))); ));
let mut noise_sampler = ChunkNoiseGenerator::new( let mut noise_sampler = ChunkNoiseGenerator::new(
&noise_router.noise, &noise_router.noise,
@ -532,16 +524,13 @@ impl ProtoChunk {
settings.aquifers_enabled, settings.aquifers_enabled,
settings.ore_veins_enabled, settings.ore_veins_enabled,
); );
let biome_pos = Vector2::new(
biome_coords::from_block(start_x),
biome_coords::from_block(start_z),
);
let horizontal_biome_end = biome_coords::from_block( let horizontal_biome_end = biome_coords::from_block(
horizontal_cell_count * generation_shape.horizontal_cell_block_count(), horizontal_cell_count * generation_shape.horizontal_cell_block_count(),
); );
let surface_config = SurfaceHeightSamplerBuilderOptions::new( let surface_config = SurfaceHeightSamplerBuilderOptions::new(
biome_pos.x, biome_coords::from_block(start_x),
biome_pos.y, biome_coords::from_block(start_z),
horizontal_biome_end as usize, horizontal_biome_end as usize,
generation_shape.min_y as i32, generation_shape.min_y as i32,
generation_shape.max_y() as i32, generation_shape.max_y() as i32,
@ -565,22 +554,17 @@ impl ProtoChunk {
) { ) {
debug_assert_eq!(self.stage, StagedChunkEnum::Noise); debug_assert_eq!(self.stage, StagedChunkEnum::Noise);
// Build surface // Build surface
let chunk_pos = self.chunk_pos; let start_x = start_block_x(self.x);
let start_x = start_block_x(&chunk_pos); let start_z = start_block_z(self.z);
let start_z = start_block_z(&chunk_pos);
let generation_shape = &settings.shape; let generation_shape = &settings.shape;
let horizontal_cell_count = CHUNK_DIM / generation_shape.horizontal_cell_block_count(); let horizontal_cell_count = CHUNK_DIM / generation_shape.horizontal_cell_block_count();
let biome_pos = Vector2::new(
biome_coords::from_block(start_x),
biome_coords::from_block(start_z),
);
let horizontal_biome_end = biome_coords::from_block( let horizontal_biome_end = biome_coords::from_block(
horizontal_cell_count * generation_shape.horizontal_cell_block_count(), horizontal_cell_count * generation_shape.horizontal_cell_block_count(),
); );
let surface_config = SurfaceHeightSamplerBuilderOptions::new( let surface_config = SurfaceHeightSamplerBuilderOptions::new(
biome_pos.x, biome_coords::from_block(start_x),
biome_pos.y, biome_coords::from_block(start_z),
horizontal_biome_end as usize, horizontal_biome_end as usize,
generation_shape.min_y as i32, generation_shape.min_y as i32,
generation_shape.max_y() as i32, generation_shape.max_y() as i32,
@ -609,8 +593,8 @@ impl ProtoChunk {
let bottom_section = section_coords::block_to_section(min_y) as i32; let bottom_section = section_coords::block_to_section(min_y) as i32;
let top_section = section_coords::block_to_section(min_y as i32 + self.height() as i32 - 1); let top_section = section_coords::block_to_section(min_y as i32 + self.height() as i32 - 1);
let start_block_x = chunk_pos::start_block_x(&self.chunk_pos); let start_block_x = start_block_x(self.x);
let start_block_z = chunk_pos::start_block_z(&self.chunk_pos); let start_block_z = start_block_z(self.z);
let start_biome_x = biome_coords::from_block(start_block_x); let start_biome_x = biome_coords::from_block(start_block_x);
let start_biome_z = biome_coords::from_block(start_block_z); let start_biome_z = biome_coords::from_block(start_block_z);
@ -623,26 +607,30 @@ impl ProtoChunk {
for x in 0..biomes_per_section { for x in 0..biomes_per_section {
for y in 0..biomes_per_section { for y in 0..biomes_per_section {
for z in 0..biomes_per_section { for z in 0..biomes_per_section {
let biome_pos =
Vector3::new(start_biome_x + x, start_biome_y + y, start_biome_z + z);
let biome = if dimension == Dimension::End { let biome = if dimension == Dimension::End {
TheEndBiomeSupplier::biome(&biome_pos, multi_noise_sampler, dimension) TheEndBiomeSupplier::biome(
start_biome_x + x,
start_biome_y + y,
start_biome_z + z,
multi_noise_sampler,
dimension,
)
} else { } else {
MultiNoiseBiomeSupplier::biome( MultiNoiseBiomeSupplier::biome(
&biome_pos, start_biome_x + x,
start_biome_y + y,
start_biome_z + z,
multi_noise_sampler, multi_noise_sampler,
dimension, dimension,
) )
}; };
//dbg!("Populating biome: {:?} -> {:?}", biome_pos, biome); //dbg!("Populating biome: {:?} -> {:?}", biome_pos, biome);
let local_biome_pos = Vector3 { let index = self.local_biome_pos_to_biome_index(
x, x,
// Make the y start from 0 start_biome_y + y - biome_coords::from_block(min_y as i32),
y: start_biome_y + y - biome_coords::from_block(min_y as i32),
z, z,
}; );
let index = self.local_biome_pos_to_biome_index(&local_biome_pos);
self.flat_biome_map[index] = biome; self.flat_biome_map[index] = biome;
} }
@ -722,12 +710,12 @@ impl ProtoChunk {
let block_state = noise_sampler let block_state = noise_sampler
.sample_block_state( .sample_block_state(
Vector3::new( sample_start_x,
sample_start_x, sample_start_y,
sample_start_y, sample_start_z,
sample_start_z, cell_offset_x,
), cell_offset_y,
Vector3::new(cell_offset_x, cell_offset_y, cell_offset_z), cell_offset_z,
surface_height_estimate_sampler, surface_height_estimate_sampler,
) )
.unwrap_or(self.default_block); .unwrap_or(self.default_block);
@ -744,16 +732,18 @@ impl ProtoChunk {
} }
} }
pub fn get_biome_for_terrain_gen(&self, global_block_pos: &Vector3<i32>) -> &'static Biome { pub fn get_biome_for_terrain_gen(&self, x: i32, y: i32, z: i32) -> &'static Biome {
// TODO: See if we can cache this value // TODO: See if we can cache this value
let seed_biome_pos = biome::get_biome_blend( let seed_biome_pos = biome::get_biome_blend(
self.bottom_y(), self.bottom_y(),
self.height(), self.height(),
self.biome_mixer_seed, self.biome_mixer_seed,
global_block_pos, x,
y,
z,
); );
self.get_biome(&seed_biome_pos) self.get_biome(seed_biome_pos.x, seed_biome_pos.y, seed_biome_pos.z)
} }
/// Constructs the terrain surface, although "surface" is a misnomer as it also places underground blocks like bedrock and deepslate. /// Constructs the terrain surface, although "surface" is a misnomer as it also places underground blocks like bedrock and deepslate.
@ -767,8 +757,8 @@ impl ProtoChunk {
terrain_cache: &TerrainCache, terrain_cache: &TerrainCache,
surface_height_estimate_sampler: &mut SurfaceHeightEstimateSampler, surface_height_estimate_sampler: &mut SurfaceHeightEstimateSampler,
) { ) {
let start_x = chunk_pos::start_block_x(&self.chunk_pos); let start_x = chunk_pos::start_block_x(self.x);
let start_z = chunk_pos::start_block_z(&self.chunk_pos); let start_z = chunk_pos::start_block_z(self.z);
let min_y = self.bottom_y(); let min_y = self.bottom_y();
let random = &random_config.base_random_deriver; let random = &random_config.base_random_deriver;
@ -788,8 +778,7 @@ impl ProtoChunk {
let x = start_x + local_x; let x = start_x + local_x;
let z = start_z + local_z; let z = start_z + local_z;
let mut top_block = let mut top_block = self.top_block_height_exclusive(local_x, local_z);
self.top_block_height_exclusive(&Vector2::new(local_x, local_z));
let biome_y = if settings.legacy_random_source { let biome_y = if settings.legacy_random_source {
0 0
@ -797,14 +786,14 @@ impl ProtoChunk {
top_block top_block
}; };
let this_biome = self.get_biome_for_terrain_gen(&Vector3::new(x, biome_y, z)); let this_biome = self.get_biome_for_terrain_gen(x, biome_y, z);
if this_biome == &Biome::ERODED_BADLANDS { if this_biome == &Biome::ERODED_BADLANDS {
terrain_cache terrain_cache
.terrain_builder .terrain_builder
.place_badlands_pillar(self, x, z, top_block); .place_badlands_pillar(self, x, z, top_block);
// Get the top block again if we placed a pillar! // Get the top block again if we placed a pillar!
top_block = self.top_block_height_exclusive(&Vector2::new(local_x, local_z)); top_block = self.top_block_height_exclusive(local_x, local_z);
} }
context.init_horizontal(x, z); context.init_horizontal(x, z);
@ -858,7 +847,11 @@ impl ProtoChunk {
// panic!("Blending with biome {:?} at: {:?}", biome, biome_pos); // panic!("Blending with biome {:?} at: {:?}", biome, biome_pos);
if state.id == self.default_block.id { if state.id == self.default_block.id {
context.biome = self.get_biome_for_terrain_gen(&context.block_pos); context.biome = self.get_biome_for_terrain_gen(
context.block_pos_x,
context.block_pos_y,
context.block_pos_z,
);
let new_state = settings.surface_rule.try_apply( let new_state = settings.surface_rule.try_apply(
self, self,
&mut context, &mut context,
@ -905,15 +898,14 @@ impl ProtoChunk {
) { ) {
let chunk = cache.get_center_chunk_mut(); let chunk = cache.get_center_chunk_mut();
debug_assert_eq!(chunk.stage, StagedChunkEnum::Surface); debug_assert_eq!(chunk.stage, StagedChunkEnum::Surface);
let chunk_pos = chunk.chunk_pos;
let min_y = chunk.bottom_y(); let min_y = chunk.bottom_y();
let height = chunk.height(); let height = chunk.height();
let bottom_section = section_coords::block_to_section(min_y) as i32; let bottom_section = section_coords::block_to_section(min_y) as i32;
let block_pos = BlockPos(Vector3::new( let block_pos = BlockPos(Vector3::new(
section_coords::section_to_block(chunk_pos.x), section_coords::section_to_block(chunk.x),
bottom_section, bottom_section,
section_coords::section_to_block(chunk_pos.y), section_coords::section_to_block(chunk.z),
)); ));
let population_seed = let population_seed =
@ -953,7 +945,7 @@ impl ProtoChunk {
// for structure in &set.structures { // for structure in &set.structures {
// let start = self.structure_starts.get(STRUCTURES.get(name).unwrap()); // let start = self.structure_starts.get(STRUCTURES.get(name).unwrap());
// } // }
if !set.placement.should_generate(calculator, self.chunk_pos) { if !set.placement.should_generate(calculator, self.x, self.z) {
continue; // ?? continue; // ??
} }
@ -976,9 +968,8 @@ impl ProtoChunk {
} }
fn get_block_box_for_chunk(&self) -> BlockBox { fn get_block_box_for_chunk(&self) -> BlockBox {
let pos = self.chunk_pos; let x = start_block_x(self.x);
let x = start_block_x(&pos); let z = start_block_z(self.z);
let z = start_block_z(&pos);
let bottom = self.bottom_y() as i32 + 1; let bottom = self.bottom_y() as i32 + 1;
let top = self.top_y() as i32; let top = self.top_y() as i32;
BlockBox::new(x, bottom, z, x + 15, top, z + 15) BlockBox::new(x, bottom, z, x + 15, top, z + 15)
@ -993,11 +984,11 @@ impl ProtoChunk {
} }
fn start_block_x(&self) -> i32 { fn start_block_x(&self) -> i32 {
start_block_x(&self.chunk_pos) start_block_x(self.x)
} }
fn start_block_z(&self) -> i32 { fn start_block_z(&self) -> i32 {
start_block_z(&self.chunk_pos) start_block_z(self.z)
} }
} }

View File

@ -48,7 +48,11 @@ impl StructureType {
StructureType::NetherFortress(generator) => generator.get_structure_position(chunk), StructureType::NetherFortress(generator) => generator.get_structure_position(chunk),
}; };
if let Some(structure) = STRUCTURES.get(name) { if let Some(structure) = STRUCTURES.get(name) {
let current_biome = chunk.get_biome(&position.position.0); let current_biome = chunk.get_biome(
position.position.0.x,
position.position.0.y,
position.position.0.z,
);
if Biome::get_tag_values(&structure.biomes) if Biome::get_tag_values(&structure.biomes)
.unwrap() .unwrap()
.contains(&current_biome.registry_id) .contains(&current_biome.registry_id)

View File

@ -1,5 +1,5 @@
use pumpkin_util::{ use pumpkin_util::{
math::{floor_div, vector2::Vector2}, math::floor_div,
random::{ random::{
RandomGenerator, RandomImpl, get_carver_seed, get_region_seed, xoroshiro128::Xoroshiro, RandomGenerator, RandomImpl, get_carver_seed, get_region_seed, xoroshiro128::Xoroshiro,
}, },
@ -19,22 +19,23 @@ impl StructurePlacement {
pub fn should_generate( pub fn should_generate(
&self, &self,
calculator: StructurePlacementCalculator, calculator: StructurePlacementCalculator,
chunk_pos: Vector2<i32>, chunk_x: i32,
chunk_z: i32,
) -> bool { ) -> bool {
self.r#type self.r#type
.is_start_chunk(&calculator, chunk_pos, self.salt) .is_start_chunk(&calculator, chunk_x, chunk_z, self.salt)
&& self.apply_frequency_reduction(calculator.seed, chunk_pos) && self.apply_frequency_reduction(calculator.seed, chunk_x, chunk_z)
// TODO: add exclusion_zone, only used for pillager_outposts // TODO: add exclusion_zone, only used for pillager_outposts
} }
fn apply_frequency_reduction(&self, seed: i64, chunk_pos: Vector2<i32>) -> bool { fn apply_frequency_reduction(&self, seed: i64, chunk_x: i32, chunk_z: i32) -> bool {
let frequency = self.frequency.unwrap_or(1.0); let frequency = self.frequency.unwrap_or(1.0);
frequency >= 1.0 frequency >= 1.0
|| self || self
.frequency_reduction_method .frequency_reduction_method
.as_ref() .as_ref()
.unwrap_or(&FrequencyReductionMethod::Default) .unwrap_or(&FrequencyReductionMethod::Default)
.should_generate(seed, chunk_pos, self.salt, frequency) .should_generate(seed, chunk_x, chunk_z, self.salt, frequency)
} }
} }
@ -51,19 +52,20 @@ impl FrequencyReductionMethod {
pub fn should_generate( pub fn should_generate(
&self, &self,
seed: i64, seed: i64,
chunk_pos: Vector2<i32>, chunk_x: i32,
chunk_z: i32,
salt: i32, salt: i32,
frequency: f32, frequency: f32,
) -> bool { ) -> bool {
match self { match self {
FrequencyReductionMethod::Default => { FrequencyReductionMethod::Default => {
let region_seed = get_region_seed(seed as u64, chunk_pos.x, chunk_pos.y, salt); let region_seed = get_region_seed(seed as u64, chunk_x, chunk_z, salt);
let mut random = RandomGenerator::Xoroshiro(Xoroshiro::from_seed(region_seed)); let mut random = RandomGenerator::Xoroshiro(Xoroshiro::from_seed(region_seed));
random.next_f32() < frequency random.next_f32() < frequency
} }
FrequencyReductionMethod::LegacyType1 => { FrequencyReductionMethod::LegacyType1 => {
let x = chunk_pos.x >> 4; let x = chunk_x >> 4;
let z = chunk_pos.y >> 4; let z = chunk_z >> 4;
let mut random = RandomGenerator::Xoroshiro(Xoroshiro::from_seed( let mut random = RandomGenerator::Xoroshiro(Xoroshiro::from_seed(
(x ^ z << 4) as u64 ^ seed as u64, (x ^ z << 4) as u64 ^ seed as u64,
)); ));
@ -71,15 +73,14 @@ impl FrequencyReductionMethod {
random.next_bounded_i32((1.0 / frequency) as i32) == 0 random.next_bounded_i32((1.0 / frequency) as i32) == 0
} }
FrequencyReductionMethod::LegacyType2 => { FrequencyReductionMethod::LegacyType2 => {
let region_seed = get_region_seed(seed as u64, chunk_pos.x, chunk_pos.y, 10387320); let region_seed = get_region_seed(seed as u64, chunk_x, chunk_z, 10387320);
let mut random = RandomGenerator::Xoroshiro(Xoroshiro::from_seed(region_seed)); let mut random = RandomGenerator::Xoroshiro(Xoroshiro::from_seed(region_seed));
random.next_f32() < frequency random.next_f32() < frequency
} }
FrequencyReductionMethod::LegacyType3 => { FrequencyReductionMethod::LegacyType3 => {
let mut random: RandomGenerator = let mut random: RandomGenerator =
RandomGenerator::Xoroshiro(Xoroshiro::from_seed(seed as u64)); RandomGenerator::Xoroshiro(Xoroshiro::from_seed(seed as u64));
let carver_seed = let carver_seed = get_carver_seed(&mut random, seed as u64, chunk_x, chunk_z);
get_carver_seed(&mut random, seed as u64, chunk_pos.x, chunk_pos.y);
let mut random: RandomGenerator = let mut random: RandomGenerator =
RandomGenerator::Xoroshiro(Xoroshiro::from_seed(carver_seed)); RandomGenerator::Xoroshiro(Xoroshiro::from_seed(carver_seed));
@ -102,12 +103,13 @@ impl StructurePlacementType {
pub fn is_start_chunk( pub fn is_start_chunk(
&self, &self,
calculator: &StructurePlacementCalculator, calculator: &StructurePlacementCalculator,
chunk_pos: Vector2<i32>, chunk_x: i32,
chunk_z: i32,
salt: i32, salt: i32,
) -> bool { ) -> bool {
match self { match self {
StructurePlacementType::RandomSpread(placement) => { StructurePlacementType::RandomSpread(placement) => {
placement.is_start_chunk(calculator, chunk_pos, salt) placement.is_start_chunk(calculator, chunk_x, chunk_z, salt)
} }
StructurePlacementType::ConcentricRings => false, // TODO, This is needed for Stronghold, since it is placed in rings StructurePlacementType::ConcentricRings => false, // TODO, This is needed for Stronghold, since it is placed in rings
} }
@ -140,25 +142,26 @@ impl SpreadType {
} }
impl RandomSpreadStructurePlacement { impl RandomSpreadStructurePlacement {
fn get_start_chunk(&self, seed: i64, chunk_pos: Vector2<i32>, salt: i32) -> Vector2<i32> { fn get_start_chunk(&self, seed: i64, chunk_x: i32, chunk_z: i32, salt: i32) -> (i32, i32) {
let x = floor_div(chunk_pos.x, self.spacing); let x = floor_div(chunk_x, self.spacing);
let z = floor_div(chunk_pos.y, self.spacing); let z = floor_div(chunk_z, self.spacing);
let region_seed = get_region_seed(seed as u64, x, z, salt); let region_seed = get_region_seed(seed as u64, x, z, salt);
let mut random = RandomGenerator::Xoroshiro(Xoroshiro::from_seed(region_seed)); let mut random = RandomGenerator::Xoroshiro(Xoroshiro::from_seed(region_seed));
let bound = self.spacing - self.separation; let bound = self.spacing - self.separation;
let rand_x = self.spread_type.get(&mut random, bound); let rand_x = self.spread_type.get(&mut random, bound);
let rand_z = self.spread_type.get(&mut random, bound); let rand_z = self.spread_type.get(&mut random, bound);
Vector2::new(x * self.spacing + rand_x, z * self.spacing + rand_z) (x * self.spacing + rand_x, z * self.spacing + rand_z)
} }
pub fn is_start_chunk( pub fn is_start_chunk(
&self, &self,
calculator: &StructurePlacementCalculator, calculator: &StructurePlacementCalculator,
chunk_pos: Vector2<i32>, chunk_x: i32,
chunk_z: i32,
salt: i32, salt: i32,
) -> bool { ) -> bool {
let pos = self.get_start_chunk(calculator.seed, chunk_pos, salt); let pos = self.get_start_chunk(calculator.seed, chunk_x, chunk_z, salt);
pos == chunk_pos (chunk_x == pos.0) && (chunk_z == pos.1)
} }
} }

View File

@ -1,7 +1,7 @@
use pumpkin_data::{Block, BlockDirection}; use pumpkin_data::{Block, BlockDirection};
use pumpkin_util::{ use pumpkin_util::{
HeightMap, HeightMap,
math::{block_box::BlockBox, position::BlockPos, vector2::Vector2, vector3::Vector3}, math::{block_box::BlockBox, position::BlockPos, vector3::Vector3},
}; };
use serde::Deserialize; use serde::Deserialize;
@ -18,14 +18,14 @@ pub struct BuriedTreasureGenerator;
impl StructureGenerator for BuriedTreasureGenerator { impl StructureGenerator for BuriedTreasureGenerator {
fn get_structure_position(&self, chunk: &ProtoChunk) -> super::StructurePosition { fn get_structure_position(&self, chunk: &ProtoChunk) -> super::StructurePosition {
let x = get_center_x(chunk.chunk_pos.x); let x = get_center_x(chunk.x);
let z = get_center_z(chunk.chunk_pos.y); let z = get_center_z(chunk.z);
let y = chunk.get_top_y(&HeightMap::OceanFloorWg, &Vector2::new(x, z)) - 1; let y = chunk.get_top_y(&HeightMap::OceanFloorWg, x, z) - 1;
let generator = StructurePiecesCollector { let generator = StructurePiecesCollector {
pieces_positions: vec![BlockBox::from_pos(BlockPos::new( pieces_positions: vec![BlockBox::from_pos(BlockPos::new(
get_offset_x(chunk.chunk_pos.x, 9), get_offset_x(chunk.x, 9),
90, 90,
get_offset_z(chunk.chunk_pos.y, 9), get_offset_z(chunk.z, 9),
))], ))],
}; };
StructurePosition { StructurePosition {
@ -37,7 +37,8 @@ impl StructureGenerator for BuriedTreasureGenerator {
fn generate(&self, bounding_box: BlockBox, chunk: &mut crate::ProtoChunk) { fn generate(&self, bounding_box: BlockBox, chunk: &mut crate::ProtoChunk) {
let y = chunk.get_top_y( let y = chunk.get_top_y(
&HeightMap::OceanFloorWg, &HeightMap::OceanFloorWg,
&Vector2::new(bounding_box.min.x, bounding_box.min.z), bounding_box.min.x,
bounding_box.min.z,
); );
let mut pos = BlockPos::new(bounding_box.min.x, y, bounding_box.min.z); let mut pos = BlockPos::new(bounding_box.min.x, y, bounding_box.min.z);
for _ in y..chunk.bottom_y() as i32 { for _ in y..chunk.bottom_y() as i32 {

View File

@ -17,9 +17,8 @@ pub struct NetherFortressGenerator;
impl StructureGenerator for NetherFortressGenerator { impl StructureGenerator for NetherFortressGenerator {
fn get_structure_position(&self, chunk: &ProtoChunk) -> StructurePosition { fn get_structure_position(&self, chunk: &ProtoChunk) -> StructurePosition {
let chunk_pos = chunk.chunk_pos; let start_x = chunk_pos::start_block_x(chunk.x);
let start_x = chunk_pos::start_block_x(&chunk_pos); let start_z = chunk_pos::start_block_z(chunk.z);
let start_z = chunk_pos::start_block_z(&chunk_pos);
let generator = StructurePiecesCollector { let generator = StructurePiecesCollector {
pieces_positions: vec![], // TODO pieces_positions: vec![], // TODO
}; };

View File

@ -3,7 +3,7 @@ use std::{cell::RefCell, num::NonZeroUsize};
use lru::LruCache; use lru::LruCache;
use pumpkin_data::chunk::Biome; use pumpkin_data::chunk::Biome;
use pumpkin_util::{ use pumpkin_util::{
math::{lerp2, vector2::Vector2, vector3::Vector3, vertical_surface_type::VerticalSurfaceType}, math::{lerp2, vertical_surface_type::VerticalSurfaceType},
random::{RandomDeriver, RandomDeriverImpl, RandomImpl}, random::{RandomDeriver, RandomDeriverImpl, RandomImpl},
}; };
use serde::Deserialize; use serde::Deserialize;
@ -33,7 +33,9 @@ pub struct MaterialRuleContext<'a> {
pub height: u16, pub height: u16,
pub random_deriver: &'a RandomDeriver, pub random_deriver: &'a RandomDeriver,
fluid_height: i32, fluid_height: i32,
pub block_pos: Vector3<i32>, pub block_pos_x: i32,
pub block_pos_y: i32,
pub block_pos_z: i32,
pub biome: &'a Biome, pub biome: &'a Biome,
pub run_depth: i32, pub run_depth: i32,
pub secondary_depth: f64, pub secondary_depth: f64,
@ -77,7 +79,9 @@ impl<'a> MaterialRuleContext<'a> {
random_deriver, random_deriver,
terrain_builder, terrain_builder,
fluid_height: 0, fluid_height: 0,
block_pos: Vector3::new(0, 0, 0), block_pos_x: 0,
block_pos_y: 0,
block_pos_z: 0,
biome: &Biome::PLAINS, biome: &Biome::PLAINS,
run_depth: 0, run_depth: 0,
secondary_depth: 0.0, secondary_depth: 0.0,
@ -93,20 +97,20 @@ impl<'a> MaterialRuleContext<'a> {
fn sample_run_depth(&self) -> i32 { fn sample_run_depth(&self) -> i32 {
let noise = let noise =
self.surface_noise self.surface_noise
.sample(self.block_pos.x as f64, 0.0, self.block_pos.z as f64); .sample(self.block_pos_x as f64, 0.0, self.block_pos_z as f64);
(noise * 2.75 (noise * 2.75
+ 3.0 + 3.0
+ self + self
.random_deriver .random_deriver
.split_pos(self.block_pos.x, 0, self.block_pos.z) .split_pos(self.block_pos_x, 0, self.block_pos_z)
.next_f64() .next_f64()
* 0.25) as i32 * 0.25) as i32
} }
pub fn init_horizontal(&mut self, x: i32, z: i32) { pub fn init_horizontal(&mut self, x: i32, z: i32) {
self.unique_horizontal_pos_value += 1; self.unique_horizontal_pos_value += 1;
self.block_pos.x = x; self.block_pos_x = x;
self.block_pos.z = z; self.block_pos_z = z;
self.run_depth = self.sample_run_depth(); self.run_depth = self.sample_run_depth();
} }
@ -117,7 +121,7 @@ impl<'a> MaterialRuleContext<'a> {
y: i32, y: i32,
fluid_height: i32, fluid_height: i32,
) { ) {
self.block_pos.y = y; self.block_pos_y = y;
self.fluid_height = fluid_height; self.fluid_height = fluid_height;
self.stone_depth_below = stone_depth_below; self.stone_depth_below = stone_depth_below;
self.stone_depth_above = stone_depth_above; self.stone_depth_above = stone_depth_above;
@ -128,7 +132,7 @@ impl<'a> MaterialRuleContext<'a> {
self.last_unique_horizontal_pos_value = self.unique_horizontal_pos_value; self.last_unique_horizontal_pos_value = self.unique_horizontal_pos_value;
self.secondary_depth = self.secondary_depth =
self.secondary_noise self.secondary_noise
.sample(self.block_pos.x as f64, 0.0, self.block_pos.z as f64) .sample(self.block_pos_x as f64, 0.0, self.block_pos_z as f64)
} }
self.secondary_depth self.secondary_depth
} }
@ -178,23 +182,23 @@ impl MaterialCondition {
MaterialCondition::YAbove(above_y) => above_y.test(context), MaterialCondition::YAbove(above_y) => above_y.test(context),
MaterialCondition::Water(water) => water.test(context), MaterialCondition::Water(water) => water.test(context),
MaterialCondition::Temperature => { MaterialCondition::Temperature => {
let temperature = context let temperature = context.biome.weather.compute_temperature(
.biome context.block_pos_x as f64,
.weather context.block_pos_y,
.compute_temperature(&context.block_pos, context.sea_level); context.block_pos_z as f64,
context.sea_level,
);
temperature < 0.15f32 temperature < 0.15f32
} }
MaterialCondition::Steep => { MaterialCondition::Steep => {
let local_x = context.block_pos.x & 15; let local_x = context.block_pos_x & 15;
let local_z = context.block_pos.z & 15; let local_z = context.block_pos_z & 15;
let local_z_sub = 0.max(local_z - 1); let local_z_sub = 0.max(local_z - 1);
let local_z_add = 15.min(local_z + 1); let local_z_add = 15.min(local_z + 1);
let sub_height = let sub_height = chunk.top_block_height_exclusive(local_x, local_z_sub);
chunk.top_block_height_exclusive(&Vector2::new(local_x, local_z_sub)); let add_height = chunk.top_block_height_exclusive(local_x, local_z_add);
let add_height =
chunk.top_block_height_exclusive(&Vector2::new(local_x, local_z_add));
if add_height >= sub_height + 4 { if add_height >= sub_height + 4 {
true true
@ -202,10 +206,8 @@ impl MaterialCondition {
let local_x_sub = 0.max(local_x - 1); let local_x_sub = 0.max(local_x - 1);
let local_x_add = 15.min(local_x + 1); let local_x_add = 15.min(local_x + 1);
let sub_height = let sub_height = chunk.top_block_height_exclusive(local_x_sub, local_z);
chunk.top_block_height_exclusive(&Vector2::new(local_x_sub, local_z)); let add_height = chunk.top_block_height_exclusive(local_x_add, local_z);
let add_height =
chunk.top_block_height_exclusive(&Vector2::new(local_x_add, local_z));
sub_height >= add_height + 4 sub_height >= add_height + 4
} }
@ -240,13 +242,13 @@ pub struct AboveYMaterialCondition {
impl AboveYMaterialCondition { impl AboveYMaterialCondition {
pub fn test(&self, context: &MaterialRuleContext) -> bool { pub fn test(&self, context: &MaterialRuleContext) -> bool {
context.block_pos.y context.block_pos_y
+ if self.add_stone_depth { + if self.add_stone_depth {
context.stone_depth_above context.stone_depth_above
} else { } else {
0 0
} }
>= self.anchor.get_y(context.min_y, context.height) as i32 >= self.anchor.get_y(context.min_y as i16, context.height)
+ context.run_depth * self.surface_depth_multiplier + context.run_depth * self.surface_depth_multiplier
} }
} }
@ -279,7 +281,7 @@ impl SurfaceMaterialCondition {
surface_height_estimate_sampler: &mut SurfaceHeightEstimateSampler, surface_height_estimate_sampler: &mut SurfaceHeightEstimateSampler,
) -> bool { ) -> bool {
// TODO // TODO
context.block_pos.y >= estimate_surface_height(context, surface_height_estimate_sampler) context.block_pos_y >= estimate_surface_height(context, surface_height_estimate_sampler)
} }
} }
@ -289,9 +291,9 @@ pub fn estimate_surface_height(
) -> i32 { ) -> i32 {
if context.last_est_heiht_unique_horizontal_pos_value != context.unique_horizontal_pos_value { if context.last_est_heiht_unique_horizontal_pos_value != context.unique_horizontal_pos_value {
context.last_est_heiht_unique_horizontal_pos_value = context.unique_horizontal_pos_value; context.last_est_heiht_unique_horizontal_pos_value = context.unique_horizontal_pos_value;
let x = section_coords::block_to_section(context.block_pos.x); let x = section_coords::block_to_section(context.block_pos_x);
let z = section_coords::block_to_section(context.block_pos.z); let z = section_coords::block_to_section(context.block_pos_z);
let packed = chunk_pos::packed(&Vector2::new(x, z)) as i64; let packed = chunk_pos::packed(x as u64, z as u64) as i64;
if context.packed_chunk_pos != packed { if context.packed_chunk_pos != packed {
context.packed_chunk_pos = packed; context.packed_chunk_pos = packed;
context.estimated_surface_heights[0] = surface_height_estimate_sampler.estimate_height( context.estimated_surface_heights[0] = surface_height_estimate_sampler.estimate_height(
@ -312,8 +314,8 @@ pub fn estimate_surface_height(
); );
} }
let surface = lerp2( let surface = lerp2(
((context.block_pos.x & 15) as f32 / 16.0) as f64, ((context.block_pos_x & 15) as f32 / 16.0) as f64,
((context.block_pos.z & 15) as f32 / 16.0) as f64, ((context.block_pos_z & 15) as f32 / 16.0) as f64,
context.estimated_surface_heights[0] as f64, context.estimated_surface_heights[0] as f64,
context.estimated_surface_heights[1] as f64, context.estimated_surface_heights[1] as f64,
context.estimated_surface_heights[2] as f64, context.estimated_surface_heights[2] as f64,
@ -349,7 +351,7 @@ impl NoiseThresholdMaterialCondition {
let sampler = context let sampler = context
.noise_builder .noise_builder
.get_noise_sampler_for_id(self.noise.strip_prefix("minecraft:").unwrap()); .get_noise_sampler_for_id(self.noise.strip_prefix("minecraft:").unwrap());
let value = sampler.sample(context.block_pos.x as f64, 0.0, context.block_pos.z as f64); let value = sampler.sample(context.block_pos_x as f64, 0.0, context.block_pos_z as f64);
value >= self.min_threshold && value <= self.max_threshold value >= self.min_threshold && value <= self.max_threshold
} }
} }
@ -398,7 +400,7 @@ pub struct WaterMaterialCondition {
impl WaterMaterialCondition { impl WaterMaterialCondition {
pub fn test(&self, context: &MaterialRuleContext) -> bool { pub fn test(&self, context: &MaterialRuleContext) -> bool {
context.fluid_height == i32::MIN context.fluid_height == i32::MIN
|| context.block_pos.y || context.block_pos_y
+ (if self.add_stone_depth { + (if self.add_stone_depth {
context.stone_depth_above context.stone_depth_above
} else { } else {
@ -421,8 +423,12 @@ pub struct VerticalGradientMaterialCondition {
impl VerticalGradientMaterialCondition { impl VerticalGradientMaterialCondition {
pub fn test(&self, context: &MaterialRuleContext) -> bool { pub fn test(&self, context: &MaterialRuleContext) -> bool {
let true_at = self.true_at_and_below.get_y(context.min_y, context.height); let true_at = self
let false_at = self.false_at_and_above.get_y(context.min_y, context.height); .true_at_and_below
.get_y(context.min_y as i16, context.height);
let false_at = self
.false_at_and_above
.get_y(context.min_y as i16, context.height);
let context_pointer: *const RandomDeriver = context.random_deriver; let context_pointer: *const RandomDeriver = context.random_deriver;
let key = context_pointer.addr(); let key = context_pointer.addr();
@ -443,16 +449,16 @@ impl VerticalGradientMaterialCondition {
.next_splitter() .next_splitter()
}); });
let block_y = context.block_pos.y; let block_y = context.block_pos_y;
if block_y <= true_at as i32 { if block_y <= true_at {
return true; return true;
} }
if block_y >= false_at as i32 { if block_y >= false_at {
return false; return false;
} }
let mapped = let mapped =
pumpkin_util::math::map(block_y as f32, true_at as f32, false_at as f32, 1.0, 0.0); pumpkin_util::math::map(block_y as f32, true_at as f32, false_at as f32, 1.0, 0.0);
let mut random = splitter.split_pos(context.block_pos.x, block_y, context.block_pos.z); let mut random = splitter.split_pos(context.block_pos_x, block_y, context.block_pos_z);
random.next_f32() < mapped random.next_f32() < mapped
} }
} }

View File

@ -17,7 +17,7 @@ pub enum MaterialRule {
#[serde(rename = "minecraft:sequence")] #[serde(rename = "minecraft:sequence")]
Sequence(SequenceMaterialRule), Sequence(SequenceMaterialRule),
#[serde(rename = "minecraft:condition")] #[serde(rename = "minecraft:condition")]
Condition(Box<ConditionMaterialRule>), Condition(ConditionMaterialRule),
} }
impl MaterialRule { impl MaterialRule {
@ -45,11 +45,11 @@ pub struct BadLandsMaterialRule;
impl BadLandsMaterialRule { impl BadLandsMaterialRule {
pub fn try_apply(&self, context: &mut MaterialRuleContext) -> Option<&'static BlockState> { pub fn try_apply(&self, context: &mut MaterialRuleContext) -> Option<&'static BlockState> {
Some( Some(context.terrain_builder.get_terracotta_block(
context context.block_pos_x,
.terrain_builder context.block_pos_y,
.get_terracotta_block(&context.block_pos), context.block_pos_z,
) ))
} }
} }

View File

@ -27,10 +27,7 @@ pub struct SurfaceTerrainBuilder {
} }
impl SurfaceTerrainBuilder { impl SurfaceTerrainBuilder {
pub fn new( pub fn new(noise_builder: &DoublePerlinNoiseBuilder, random_deriver: &RandomDeriver) -> Self {
noise_builder: &mut DoublePerlinNoiseBuilder,
random_deriver: &RandomDeriver,
) -> Self {
Self { Self {
terracotta_bands: Self::create_terracotta_bands( terracotta_bands: Self::create_terracotta_bands(
random_deriver.split_string("minecraft:clay_bands"), random_deriver.split_string("minecraft:clay_bands"),
@ -217,8 +214,9 @@ impl SurfaceTerrainBuilder {
let mut block_threshold = scaled_threshold.min(scaled_roof_noise); let mut block_threshold = scaled_threshold.min(scaled_roof_noise);
// TODO: Cache this // TODO: Cache this
let pos = Vector3::new(x, sea_level, z); let temperature = biome
let temperature = biome.weather.compute_temperature(&pos, sea_level); .weather
.compute_temperature(x as f64, sea_level, z as f64, sea_level);
if temperature > 0.1f32 { if temperature > 0.1f32 {
block_threshold -= 2.0; block_threshold -= 2.0;
} }
@ -258,13 +256,13 @@ impl SurfaceTerrainBuilder {
} }
} }
pub fn get_terracotta_block(&self, pos: &Vector3<i32>) -> &'static BlockState { pub fn get_terracotta_block(&self, x: i32, y: i32, z: i32) -> &'static BlockState {
let offset = (self let offset = (self
.terracotta_bands_offset_noise .terracotta_bands_offset_noise
.sample(pos.x as f64, 0.0, pos.z as f64) .sample(x as f64, 0.0, z as f64)
* 4.0) * 4.0)
.round() as i32; .round() as i32;
let offset = pos.y + offset; let offset = y + offset;
self.terracotta_bands[((offset as u64 + self.terracotta_bands.len() as u64) self.terracotta_bands[((offset as u64 + self.terracotta_bands.len() as u64)
% self.terracotta_bands.len() as u64) as usize] % self.terracotta_bands.len() as u64) as usize]
.to_state() .to_state()

View File

@ -9,13 +9,13 @@ pub enum YOffset {
} }
impl YOffset { impl YOffset {
pub fn get_y(&self, min_y: i8, height: u16) -> i16 { pub fn get_y(&self, min_y: i16, height: u16) -> i32 {
match self { match self {
YOffset::AboveBottom(above_bottom) => min_y as i16 + above_bottom.above_bottom as i16, YOffset::AboveBottom(above_bottom) => min_y as i32 + above_bottom.above_bottom as i32,
YOffset::BelowTop(below_top) => { YOffset::BelowTop(below_top) => {
height as i16 - 1 + min_y as i16 - below_top.below_top as i16 height as i32 - 1 + min_y as i32 - below_top.below_top as i32
} }
YOffset::Absolute(absolute) => absolute.absolute, YOffset::Absolute(absolute) => absolute.absolute as i32,
} }
} }
} }

View File

@ -237,7 +237,8 @@ impl Level {
// ); // );
let chunk = ChunkEntityData { let chunk = ChunkEntityData {
chunk_position: pos, x: pos.x,
z: pos.y,
data: HashMap::new(), data: HashMap::new(),
dirty: true, dirty: true,
}; };
@ -508,8 +509,8 @@ impl Level {
let chunk = chunk.downgrade(); let chunk = chunk.downgrade();
let chunk_x_base = chunk.position.x * 16; let chunk_x_base = chunk.x * 16;
let chunk_z_base = chunk.position.y * 16; let chunk_z_base = chunk.z * 16;
let mut section_blocks = Vec::new(); let mut section_blocks = Vec::new();
for i in 0..chunk.section.sections.len() { for i in 0..chunk.section.sections.len() {
@ -669,7 +670,9 @@ impl Level {
while let Some(data) = rx.recv().await { while let Some(data) = rx.recv().await {
match data { match data {
LoadedData::Loaded(chunk) => { LoadedData::Loaded(chunk) => {
let pos = chunk.read().await.chunk_position; let tmp_chunk = chunk.read().await;
let pos = Vector2::new(tmp_chunk.x, tmp_chunk.z);
drop(tmp_chunk);
level.loaded_entity_chunks.insert(pos, chunk.clone()); level.loaded_entity_chunks.insert(pos, chunk.clone());
let _ = sender.send((chunk, false)); let _ = sender.send((chunk, false));
} }

View File

@ -67,23 +67,18 @@ pub fn bench_create_and_populate_noise(
}; };
let biome_mixer_seed = hash_seed(random_config.seed); let biome_mixer_seed = hash_seed(random_config.seed);
let mut chunk = ProtoChunk::new( let mut chunk = ProtoChunk::new(0, 0, settings, default_block, biome_mixer_seed);
Vector2::new(0, 0),
settings,
default_block,
biome_mixer_seed,
);
// Create noise sampler and other required components // Create noise sampler and other required components
let generation_shape = &settings.shape; let generation_shape = &settings.shape;
let horizontal_cell_count = CHUNK_DIM / generation_shape.horizontal_cell_block_count(); let horizontal_cell_count = CHUNK_DIM / generation_shape.horizontal_cell_block_count();
let sampler = FluidLevelSampler::Chunk(Box::new(StandardChunkFluidLevelSampler::new( let sampler = FluidLevelSampler::Chunk(StandardChunkFluidLevelSampler::new(
FluidLevel::new(settings.sea_level, settings.default_fluid.name), FluidLevel::new(settings.sea_level, settings.default_fluid.name),
FluidLevel::new(-54, &pumpkin_data::Block::LAVA), FluidLevel::new(-54, &pumpkin_data::Block::LAVA),
))); ));
let start_x = chunk_pos::start_block_x(&Vector2::new(0, 0)); let start_x = chunk_pos::start_block_x(0);
let start_z = chunk_pos::start_block_z(&Vector2::new(0, 0)); let start_z = chunk_pos::start_block_z(0);
let mut noise_sampler = ChunkNoiseGenerator::new( let mut noise_sampler = ChunkNoiseGenerator::new(
&base_router.noise, &base_router.noise,
@ -133,18 +128,13 @@ pub fn bench_create_and_populate_biome(
use crate::generation::{biome_coords, positions::chunk_pos}; use crate::generation::{biome_coords, positions::chunk_pos};
let biome_mixer_seed = hash_seed(random_config.seed); let biome_mixer_seed = hash_seed(random_config.seed);
let mut chunk = ProtoChunk::new( let mut chunk = ProtoChunk::new(0, 0, settings, default_block, biome_mixer_seed);
Vector2::new(0, 0),
settings,
default_block,
biome_mixer_seed,
);
// Create multi-noise sampler // Create multi-noise sampler
let generation_shape = &settings.shape; let generation_shape = &settings.shape;
let horizontal_cell_count = CHUNK_DIM / generation_shape.horizontal_cell_block_count(); let horizontal_cell_count = CHUNK_DIM / generation_shape.horizontal_cell_block_count();
let start_x = chunk_pos::start_block_x(&Vector2::new(0, 0)); let start_x = chunk_pos::start_block_x(0);
let start_z = chunk_pos::start_block_z(&Vector2::new(0, 0)); let start_z = chunk_pos::start_block_z(0);
let biome_pos = Vector2::new( let biome_pos = Vector2::new(
biome_coords::from_block(start_x), biome_coords::from_block(start_x),
biome_coords::from_block(start_z), biome_coords::from_block(start_z),
@ -186,18 +176,13 @@ pub fn bench_create_and_populate_noise_with_surface(
}; };
let biome_mixer_seed = hash_seed(random_config.seed); let biome_mixer_seed = hash_seed(random_config.seed);
let mut chunk = ProtoChunk::new( let mut chunk = ProtoChunk::new(0, 0, settings, default_block, biome_mixer_seed);
Vector2::new(0, 0),
settings,
default_block,
biome_mixer_seed,
);
// Create all required components // Create all required components
let generation_shape = &settings.shape; let generation_shape = &settings.shape;
let horizontal_cell_count = CHUNK_DIM / generation_shape.horizontal_cell_block_count(); let horizontal_cell_count = CHUNK_DIM / generation_shape.horizontal_cell_block_count();
let start_x = chunk_pos::start_block_x(&Vector2::new(0, 0)); let start_x = chunk_pos::start_block_x(0);
let start_z = chunk_pos::start_block_z(&Vector2::new(0, 0)); let start_z = chunk_pos::start_block_z(0);
// Multi-noise sampler for biomes // Multi-noise sampler for biomes
let biome_pos = Vector2::new( let biome_pos = Vector2::new(
@ -216,10 +201,10 @@ pub fn bench_create_and_populate_noise_with_surface(
MultiNoiseSampler::generate(&base_router.multi_noise, &multi_noise_config); MultiNoiseSampler::generate(&base_router.multi_noise, &multi_noise_config);
// Noise sampler // Noise sampler
let sampler = FluidLevelSampler::Chunk(Box::new(StandardChunkFluidLevelSampler::new( let sampler = FluidLevelSampler::Chunk(StandardChunkFluidLevelSampler::new(
FluidLevel::new(settings.sea_level, settings.default_fluid.name), FluidLevel::new(settings.sea_level, settings.default_fluid.name),
FluidLevel::new(-54, &pumpkin_data::Block::LAVA), FluidLevel::new(-54, &pumpkin_data::Block::LAVA),
))); ));
let mut noise_sampler = ChunkNoiseGenerator::new( let mut noise_sampler = ChunkNoiseGenerator::new(
&base_router.noise, &base_router.noise,

View File

@ -376,12 +376,12 @@ pub async fn calc_block_breaking(
return 0.0; return 0.0;
} }
let i = if player.can_harvest(state, block).await { let i = if player.can_harvest(state, block).await {
30 30.0
} else { } else {
100 100.0
}; };
player.get_mining_speed(block).await / hardness / i as f32 player.get_mining_speed(block).await / hardness / i
} }
#[derive(PartialEq)] #[derive(PartialEq)]

View File

@ -55,18 +55,14 @@ impl<'a> FindArg<'a> for BlockArgumentConsumer {
Some(Arg::Block(name)) => Block::from_name(name).map_or_else( Some(Arg::Block(name)) => Block::from_name(name).map_or_else(
|| { || {
if name.starts_with("minecraft:") { if name.starts_with("minecraft:") {
Err(CommandError::CommandFailed(Box::new( Err(CommandError::CommandFailed(TextComponent::translate(
TextComponent::translate( "argument.block.id.invalid",
"argument.block.id.invalid", [TextComponent::text((*name).to_string())],
[TextComponent::text((*name).to_string())],
),
))) )))
} else { } else {
Err(CommandError::CommandFailed(Box::new( Err(CommandError::CommandFailed(TextComponent::translate(
TextComponent::translate( "argument.block.id.invalid",
"argument.block.id.invalid", [TextComponent::text("minecraft:".to_string() + *name)],
[TextComponent::text("minecraft:".to_string() + *name)],
),
))) )))
} }
}, },
@ -125,18 +121,14 @@ impl<'a> FindArg<'a> for BlockPredicateArgumentConsumer {
Block::from_name(name).map_or_else( Block::from_name(name).map_or_else(
|| { || {
if name.starts_with("minecraft:") { if name.starts_with("minecraft:") {
Err(CommandError::CommandFailed(Box::new( Err(CommandError::CommandFailed(TextComponent::translate(
TextComponent::translate( "argument.block.id.invalid",
"argument.block.id.invalid", [TextComponent::text((*name).to_string())],
[TextComponent::text((*name).to_string())],
),
))) )))
} else { } else {
Err(CommandError::CommandFailed(Box::new( Err(CommandError::CommandFailed(TextComponent::translate(
TextComponent::translate( "argument.block.id.invalid",
"argument.block.id.invalid", [TextComponent::text("minecraft:".to_string() + *name)],
[TextComponent::text("minecraft:".to_string() + *name)],
),
))) )))
} }
}, },
@ -146,11 +138,9 @@ impl<'a> FindArg<'a> for BlockPredicateArgumentConsumer {
|tag| { |tag| {
get_tag_ids(RegistryKey::Block, tag).map_or_else( get_tag_ids(RegistryKey::Block, tag).map_or_else(
|| { || {
Err(CommandError::CommandFailed(Box::new( Err(CommandError::CommandFailed(TextComponent::translate(
TextComponent::translate( "arguments.block.tag.unknown",
"arguments.block.tag.unknown", [TextComponent::text((*tag).to_string())],
[TextComponent::text((*tag).to_string())],
),
))) )))
}, },
|blocks| Ok(Some(BlockPredicate::Tag(blocks.to_vec()))), |blocks| Ok(Some(BlockPredicate::Tag(blocks.to_vec()))),

View File

@ -90,22 +90,18 @@ pub enum NotInBounds {
impl From<NotInBounds> for CommandError { impl From<NotInBounds> for CommandError {
fn from(value: NotInBounds) -> Self { fn from(value: NotInBounds) -> Self {
match value { match value {
NotInBounds::LowerBound(val, min) => { NotInBounds::LowerBound(val, min) => Self::CommandFailed(TextComponent::text(format!(
Self::CommandFailed(Box::new(TextComponent::text(format!( "{} must not be less than {}, found {}",
"{} must not be less than {}, found {}", val.qualifier(),
val.qualifier(), min,
min, val
val ))),
)))) NotInBounds::UpperBound(val, max) => Self::CommandFailed(TextComponent::text(format!(
} "{} must not be more than {}, found {}",
NotInBounds::UpperBound(val, max) => { val.qualifier(),
Self::CommandFailed(Box::new(TextComponent::text(format!( max,
"{} must not be more than {}, found {}", val
val.qualifier(), ))),
max,
val
))))
}
} }
} }
} }

View File

@ -56,18 +56,14 @@ impl<'a> FindArg<'a> for ItemArgumentConsumer {
.map_or_else( .map_or_else(
|| { || {
if name.starts_with("minecraft:") { if name.starts_with("minecraft:") {
Err(CommandError::CommandFailed(Box::new( Err(CommandError::CommandFailed(TextComponent::translate(
TextComponent::translate( "argument.item.id.invalid",
"argument.item.id.invalid", [TextComponent::text((*name).to_string())],
[TextComponent::text((*name).to_string())],
),
))) )))
} else { } else {
Err(CommandError::CommandFailed(Box::new( Err(CommandError::CommandFailed(TextComponent::translate(
TextComponent::translate( "argument.item.id.invalid",
"argument.item.id.invalid", [TextComponent::text("minecraft:".to_string() + *name)],
[TextComponent::text("minecraft:".to_string() + *name)],
),
))) )))
} }
}, },

View File

@ -54,8 +54,8 @@ impl<'a> FindArg<'a> for SoundArgumentConsumer {
Some(Arg::Block(name)) => { Some(Arg::Block(name)) => {
Sound::from_name(name.strip_prefix("minecraft:").unwrap_or(name)).map_or_else( Sound::from_name(name.strip_prefix("minecraft:").unwrap_or(name)).map_or_else(
|| { || {
Err(CommandError::CommandFailed(Box::new(TextComponent::text( Err(CommandError::CommandFailed(TextComponent::text(format!(
format!("Sound {name} does not exist."), "Sound {name} does not exist."
)))) ))))
}, },
Result::Ok, Result::Ok,

View File

@ -54,9 +54,9 @@ impl<'a> FindArg<'a> for SummonableEntitiesArgumentConsumer {
Some(Arg::Block(name)) => { Some(Arg::Block(name)) => {
EntityType::from_name(name.strip_prefix("minecraft:").unwrap_or(name)).map_or_else( EntityType::from_name(name.strip_prefix("minecraft:").unwrap_or(name)).map_or_else(
|| { || {
Err(CommandError::CommandFailed(Box::new(TextComponent::text( Err(CommandError::CommandFailed(TextComponent::text(
"Can't find Entity", "Can't find Entity",
)))) )))
}, },
Result::Ok, Result::Ok,
) )

View File

@ -62,9 +62,9 @@ impl CommandExecutor for ListExecutor {
handle_banlist(entries, sender).await; handle_banlist(entries, sender).await;
} }
_ => { _ => {
return Err(CommandError::CommandFailed(Box::new(TextComponent::text( return Err(CommandError::CommandFailed(TextComponent::text(
"Incorrect argument for command".to_string(), "Incorrect argument for command",
)))); )));
} }
} }

View File

@ -225,7 +225,7 @@ async fn display_data(
let mut nbt = NbtCompound::new(); let mut nbt = NbtCompound::new();
storage.write_nbt(&mut nbt).await; storage.write_nbt(&mut nbt).await;
let display = snbt_colorful_display(&NbtTag::Compound(nbt), 0) let display = snbt_colorful_display(&NbtTag::Compound(nbt), 0)
.map_err(|string| CommandError::CommandFailed(Box::new(TextComponent::text(string))))?; .map_err(|string| CommandError::CommandFailed(TextComponent::text(string)))?;
Ok(TextComponent::translate( Ok(TextComponent::translate(
"commands.data.entity.query", "commands.data.entity.query",
[target_name, display], [target_name, display],

View File

@ -46,7 +46,7 @@ impl CommandExecutor for Executor {
), ),
}; };
return Err(CommandError::CommandFailed(Box::new(err_msg))); return Err(CommandError::CommandFailed(err_msg));
} }
}; };
@ -58,7 +58,7 @@ impl CommandExecutor for Executor {
TextComponent::text(enchantment.max_level.to_string()), TextComponent::text(enchantment.max_level.to_string()),
], ],
); );
return Err(CommandError::CommandFailed(Box::new(msg))); return Err(CommandError::CommandFailed(msg));
} }
let only_one = targets.len() == 1; let only_one = targets.len() == 1;
@ -88,7 +88,7 @@ impl CommandExecutor for Executor {
"commands.enchant.failed.itemless", "commands.enchant.failed.itemless",
[targets[0].get_display_name().await], [targets[0].get_display_name().await],
); );
return Err(CommandError::CommandFailed(Box::new(msg))); return Err(CommandError::CommandFailed(msg));
} }
continue; continue;
} }
@ -98,7 +98,7 @@ impl CommandExecutor for Executor {
"commands.enchant.failed.incompatible", "commands.enchant.failed.incompatible",
[item.item.translated_name()], [item.item.translated_name()],
); );
return Err(CommandError::CommandFailed(Box::new(msg))); return Err(CommandError::CommandFailed(msg));
} }
continue; continue;
} }
@ -111,7 +111,7 @@ impl CommandExecutor for Executor {
"commands.enchant.failed.incompatible", "commands.enchant.failed.incompatible",
[item.item.translated_name()], [item.item.translated_name()],
); );
return Err(CommandError::CommandFailed(Box::new(msg))); return Err(CommandError::CommandFailed(msg));
} }
} else { } else {
item.enchant(enchantment, level); item.enchant(enchantment, level);
@ -120,7 +120,7 @@ impl CommandExecutor for Executor {
} }
if success == 0 { if success == 0 {
let msg = TextComponent::translate("commands.enchant.failed", []); let msg = TextComponent::translate("commands.enchant.failed", []);
return Err(CommandError::CommandFailed(Box::new(msg))); return Err(CommandError::CommandFailed(msg));
} }
if only_one { if only_one {
let msg = TextComponent::translate( let msg = TextComponent::translate(

View File

@ -27,9 +27,9 @@ impl CommandExecutor for Executor {
_ => match server.worlds.read().await.first() { _ => match server.worlds.read().await.first() {
Some(world) => world.level.seed.0, Some(world) => world.level.seed.0,
None => { None => {
return Err(CommandError::CommandFailed(Box::new(TextComponent::text( return Err(CommandError::CommandFailed(TextComponent::text(
"Unable to get Seed", "Unable to get Seed",
)))); )));
} }
}, },
}; };

View File

@ -102,9 +102,9 @@ async fn setworldspawn(
yaw: f32, yaw: f32,
) -> Result<(), CommandError> { ) -> Result<(), CommandError> {
let Some(world) = sender.world() else { let Some(world) = sender.world() else {
return Err(CommandError::CommandFailed(Box::new(TextComponent::text( return Err(CommandError::CommandFailed(TextComponent::text(
"Failed to get world.", "Failed to get world.",
)))); )));
}; };
match world.dimension_type { match world.dimension_type {

View File

@ -66,8 +66,9 @@ impl CommandExecutor for EntitiesToEntityExecutor {
let destination = EntityArgumentConsumer::find_arg(args, ARG_DESTINATION)?; let destination = EntityArgumentConsumer::find_arg(args, ARG_DESTINATION)?;
let pos = destination.get_entity().pos.load(); let pos = destination.get_entity().pos.load();
if !World::is_valid(pos) { if !World::is_valid(pos) {
return Err(CommandError::CommandFailed(Box::new( return Err(CommandError::CommandFailed(TextComponent::translate(
TextComponent::translate("argument.pos.outofbounds", []), "argument.pos.outofbounds",
[],
))); )));
} }
for target in targets { for target in targets {
@ -100,8 +101,9 @@ impl CommandExecutor for EntitiesToPosFacingPosExecutor {
let pos = Position3DArgumentConsumer::find_arg(args, ARG_LOCATION)?; let pos = Position3DArgumentConsumer::find_arg(args, ARG_LOCATION)?;
if !World::is_valid(pos) { if !World::is_valid(pos) {
return Err(CommandError::CommandFailed(Box::new( return Err(CommandError::CommandFailed(TextComponent::translate(
TextComponent::translate("argument.pos.outofbounds", []), "argument.pos.outofbounds",
[],
))); )));
} }
let facing_pos = Position3DArgumentConsumer::find_arg(args, ARG_FACING_LOCATION)?; let facing_pos = Position3DArgumentConsumer::find_arg(args, ARG_FACING_LOCATION)?;
@ -140,8 +142,9 @@ impl CommandExecutor for EntitiesToPosFacingEntityExecutor {
let pos = Position3DArgumentConsumer::find_arg(args, ARG_LOCATION)?; let pos = Position3DArgumentConsumer::find_arg(args, ARG_LOCATION)?;
if !World::is_valid(pos) { if !World::is_valid(pos) {
return Err(CommandError::CommandFailed(Box::new( return Err(CommandError::CommandFailed(TextComponent::translate(
TextComponent::translate("argument.pos.outofbounds", []), "argument.pos.outofbounds",
[],
))); )));
} }
let facing_entity = EntityArgumentConsumer::find_arg(args, ARG_FACING_ENTITY)?; let facing_entity = EntityArgumentConsumer::find_arg(args, ARG_FACING_ENTITY)?;
@ -179,8 +182,9 @@ impl CommandExecutor for EntitiesToPosWithRotationExecutor {
let pos = Position3DArgumentConsumer::find_arg(args, ARG_LOCATION)?; let pos = Position3DArgumentConsumer::find_arg(args, ARG_LOCATION)?;
if !World::is_valid(pos) { if !World::is_valid(pos) {
return Err(CommandError::CommandFailed(Box::new( return Err(CommandError::CommandFailed(TextComponent::translate(
TextComponent::translate("argument.pos.outofbounds", []), "argument.pos.outofbounds",
[],
))); )));
} }
let (yaw, pitch) = RotationArgumentConsumer::find_arg(args, ARG_ROTATION)?; let (yaw, pitch) = RotationArgumentConsumer::find_arg(args, ARG_ROTATION)?;
@ -213,8 +217,9 @@ impl CommandExecutor for EntitiesToPosExecutor {
let pos = Position3DArgumentConsumer::find_arg(args, ARG_LOCATION)?; let pos = Position3DArgumentConsumer::find_arg(args, ARG_LOCATION)?;
if !World::is_valid(pos) { if !World::is_valid(pos) {
return Err(CommandError::CommandFailed(Box::new( return Err(CommandError::CommandFailed(TextComponent::translate(
TextComponent::translate("argument.pos.outofbounds", []), "argument.pos.outofbounds",
[],
))); )));
} }
// todo command context // todo command context
@ -257,8 +262,9 @@ impl CommandExecutor for SelfToEntityExecutor {
let yaw = player.living_entity.entity.yaw.load(); let yaw = player.living_entity.entity.yaw.load();
let pitch = player.living_entity.entity.pitch.load(); let pitch = player.living_entity.entity.pitch.load();
if !World::is_valid(pos) { if !World::is_valid(pos) {
return Err(CommandError::CommandFailed(Box::new( return Err(CommandError::CommandFailed(TextComponent::translate(
TextComponent::translate("argument.pos.outofbounds", []), "argument.pos.outofbounds",
[],
))); )));
} }
player player
@ -293,8 +299,9 @@ impl CommandExecutor for SelfToPosExecutor {
let yaw = player.living_entity.entity.yaw.load(); let yaw = player.living_entity.entity.yaw.load();
let pitch = player.living_entity.entity.pitch.load(); let pitch = player.living_entity.entity.pitch.load();
if !World::is_valid(pos) { if !World::is_valid(pos) {
return Err(CommandError::CommandFailed(Box::new( return Err(CommandError::CommandFailed(TextComponent::translate(
TextComponent::translate("argument.pos.outofbounds", []), "argument.pos.outofbounds",
[],
))); )));
} }
player player

View File

@ -24,7 +24,7 @@ pub enum CommandError {
PermissionDenied, PermissionDenied,
/// A general error occurred during command execution that doesn't fit into /// A general error occurred during command execution that doesn't fit into
/// more specific `CommandError` variants. /// more specific `CommandError` variants.
CommandFailed(Box<TextComponent>), CommandFailed(TextComponent),
} }
impl CommandError { impl CommandError {
@ -49,7 +49,7 @@ impl CommandError {
"I'm sorry, but you do not have permission to perform this command. Please contact the server administrator if you believe this is an error.", "I'm sorry, but you do not have permission to perform this command. Please contact the server administrator if you believe this is an error.",
) )
} }
CommandFailed(s) => *s, CommandFailed(s) => s,
} }
} }
} }
@ -138,9 +138,7 @@ impl CommandDispatcher {
pub(crate) fn split_parts(cmd: &str) -> Result<(&str, Vec<&str>), CommandError> { pub(crate) fn split_parts(cmd: &str) -> Result<(&str, Vec<&str>), CommandError> {
if cmd.is_empty() { if cmd.is_empty() {
return Err(CommandFailed(Box::new(TextComponent::text( return Err(CommandFailed(TextComponent::text("Empty Command")));
"Empty Command",
))));
} }
let mut args = Vec::new(); let mut args = Vec::new();
let mut current_arg_start = 0usize; let mut current_arg_start = 0usize;
@ -167,9 +165,7 @@ impl CommandDispatcher {
'}' => { '}' => {
if !in_single_quotes && !in_double_quotes { if !in_single_quotes && !in_double_quotes {
if in_braces == 0 { if in_braces == 0 {
return Err(CommandFailed(Box::new(TextComponent::text( return Err(CommandFailed(TextComponent::text("Unmatched braces")));
"Unmatched braces",
))));
} }
in_braces -= 1; in_braces -= 1;
} }
@ -182,9 +178,7 @@ impl CommandDispatcher {
']' => { ']' => {
if !in_single_quotes && !in_double_quotes { if !in_single_quotes && !in_double_quotes {
if in_brackets == 0 { if in_brackets == 0 {
return Err(CommandFailed(Box::new(TextComponent::text( return Err(CommandFailed(TextComponent::text("Unmatched brackets")));
"Unmatched brackets",
))));
} }
in_brackets -= 1; in_brackets -= 1;
} }
@ -216,24 +210,22 @@ impl CommandDispatcher {
args.push(&cmd[current_arg_start..]); args.push(&cmd[current_arg_start..]);
} }
if in_single_quotes || in_double_quotes { if in_single_quotes || in_double_quotes {
return Err(CommandFailed(Box::new(TextComponent::text( return Err(CommandFailed(TextComponent::text(
"Unmatched quotes at the end", "Unmatched quotes at the end",
)))); )));
} }
if in_braces != 0 { if in_braces != 0 {
return Err(CommandFailed(Box::new(TextComponent::text( return Err(CommandFailed(TextComponent::text(
"Unmatched braces at the end", "Unmatched braces at the end",
)))); )));
} }
if in_brackets != 0 { if in_brackets != 0 {
return Err(CommandFailed(Box::new(TextComponent::text( return Err(CommandFailed(TextComponent::text(
"Unmatched brackets at the end", "Unmatched brackets at the end",
)))); )));
} }
if args.is_empty() { if args.is_empty() {
return Err(CommandFailed(Box::new(TextComponent::text( return Err(CommandFailed(TextComponent::text("Empty Command")));
"Empty Command",
))));
} }
let key = args.remove(0); let key = args.remove(0);
Ok((key, args.into_iter().rev().collect())) Ok((key, args.into_iter().rev().collect()))
@ -249,15 +241,15 @@ impl CommandDispatcher {
let (key, raw_args) = Self::split_parts(cmd)?; let (key, raw_args) = Self::split_parts(cmd)?;
if !self.commands.contains_key(key) { if !self.commands.contains_key(key) {
return Err(CommandFailed(Box::new(TextComponent::text(format!( return Err(CommandFailed(TextComponent::text(format!(
"Command {key} does not exist" "Command {key} does not exist"
))))); ))));
} }
let Some(permission) = self.permissions.get(key) else { let Some(permission) = self.permissions.get(key) else {
return Err(CommandFailed(Box::new(TextComponent::text( return Err(CommandFailed(TextComponent::text(
"Permission for Command not found".to_string(), "Permission for Command not found".to_string(),
)))); )));
}; };
if !src.has_permission(permission.as_str()).await { if !src.has_permission(permission.as_str()).await {
@ -272,18 +264,16 @@ impl CommandDispatcher {
return Ok(()); return Ok(());
} }
} }
Err(CommandFailed(Box::new(TextComponent::text(format!( Err(CommandFailed(TextComponent::text(format!(
"Invalid Syntax. Usage: {tree}" "Invalid Syntax. Usage: {tree}"
))))) ))))
} }
pub fn get_tree<'a>(&'a self, key: &str) -> Result<&'a CommandTree, CommandError> { pub fn get_tree<'a>(&'a self, key: &str) -> Result<&'a CommandTree, CommandError> {
let command = let command = self
self.commands .commands
.get(key) .get(key)
.ok_or(CommandFailed(Box::new(TextComponent::text( .ok_or(CommandFailed(TextComponent::text("Command not found")))?;
"Command not found",
))))?;
match command { match command {
Command::Tree(tree) => Ok(tree), Command::Tree(tree) => Ok(tree),
@ -292,9 +282,9 @@ impl CommandDispatcher {
log::error!( log::error!(
"Error while parsing command alias \"{key}\": pointing to \"{target}\" which is not a valid tree" "Error while parsing command alias \"{key}\": pointing to \"{target}\" which is not a valid tree"
); );
return Err(CommandFailed(Box::new(TextComponent::text( return Err(CommandFailed(TextComponent::text(
"Internal Error (See logs for details)", "Internal Error (See logs for details)",
)))); )));
}; };
Ok(tree) Ok(tree)
} }

View File

@ -1935,7 +1935,9 @@ impl World {
let Some((chunk, _first_load)) = recv_result else { let Some((chunk, _first_load)) = recv_result else {
break; break;
}; };
let position = chunk.read().await.chunk_position; let tmp_chunk = chunk.read().await;
let position = Vector2::new(tmp_chunk.x, tmp_chunk.z);
drop(tmp_chunk);
let chunk = if level.is_chunk_watched(&position) { let chunk = if level.is_chunk_watched(&position) {
chunk chunk

View File

@ -373,10 +373,6 @@ pub async fn spawn_category_for_position(
new_pos = BlockPos::new(new_x, new_pos.0.y, new_z); new_pos = BlockPos::new(new_x, new_pos.0.y, new_z);
let new_pos_center = new_pos.to_centered_f64(); let new_pos_center = new_pos.to_centered_f64();
let player_distance = get_nearest_player(&new_pos_center, world).await; let player_distance = get_nearest_player(&new_pos_center, world).await;
if player_distance == f64::MAX {
// debug!("player_distance infinity");
return;
}
if !is_right_distance_to_player_and_spawn_point( if !is_right_distance_to_player_and_spawn_point(
&new_pos, &new_pos,
player_distance, player_distance,