mirror of
https://github.com/Pumpkin-MC/Pumpkin.git
synced 2026-08-30 20:14:23 +00:00
ci: add Windows Arm and macOS Intel
This commit is contained in:
4
.github/workflows/rust.yml
vendored
4
.github/workflows/rust.yml
vendored
@@ -41,7 +41,7 @@ jobs:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
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:
|
||||
- stable
|
||||
steps:
|
||||
@@ -55,7 +55,7 @@ jobs:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
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:
|
||||
- stable
|
||||
steps:
|
||||
|
||||
@@ -886,9 +886,8 @@ pub(crate) fn build() -> TokenStream {
|
||||
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() {
|
||||
let block = Block::from_state_id(block_state.id);
|
||||
return block != &Block::COBWEB && block != &Block::BAMBOO_SAPLING;
|
||||
}
|
||||
false
|
||||
|
||||
@@ -22,8 +22,8 @@ pub struct CLevelChunk<'a> {
|
||||
|
||||
impl<'a> PacketWrite for CLevelChunk<'a> {
|
||||
fn write<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
|
||||
VarInt(self.chunk.position.x).write(writer)?;
|
||||
VarInt(self.chunk.position.y).write(writer)?;
|
||||
VarInt(self.chunk.x).write(writer)?;
|
||||
VarInt(self.chunk.z).write(writer)?;
|
||||
|
||||
VarInt(self.dimension).write(writer)?;
|
||||
let sub_chunk_count = self.chunk.section.sections.len() as u32;
|
||||
|
||||
@@ -134,7 +134,7 @@ impl UDPNetworkDecoder {
|
||||
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)?;
|
||||
|
||||
@@ -157,7 +157,7 @@ impl UDPNetworkDecoder {
|
||||
let gamepacket_id = (header & 0x3FF) as u16; // 0x3FF is 10 bits set to 1
|
||||
|
||||
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()))?;
|
||||
|
||||
Ok(RawPacket {
|
||||
|
||||
@@ -17,9 +17,9 @@ impl ClientPacket for CChunkData<'_> {
|
||||
let mut write = write;
|
||||
|
||||
// Chunk X
|
||||
write.write_i32_be(self.0.position.x)?;
|
||||
write.write_i32_be(self.0.x)?;
|
||||
// Chunk Z
|
||||
write.write_i32_be(self.0.position.y)?;
|
||||
write.write_i32_be(self.0.z)?;
|
||||
|
||||
let heightmaps = &self.0.heightmap;
|
||||
write.write_var_int(&VarInt(3))?; // Map size
|
||||
|
||||
@@ -43,7 +43,7 @@ impl Serialize for CMultiBlockUpdate {
|
||||
))?;
|
||||
|
||||
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);
|
||||
tuple.serialize_element(&var_long)?;
|
||||
}
|
||||
|
||||
@@ -2,10 +2,7 @@ use std::sync::LazyLock;
|
||||
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::{
|
||||
math::vector3::Vector3, noise::simplex::OctaveSimplexNoiseSampler,
|
||||
random::legacy_rand::LegacyRand,
|
||||
};
|
||||
use crate::{noise::simplex::OctaveSimplexNoiseSampler, random::legacy_rand::LegacyRand};
|
||||
|
||||
pub static TEMPERATURE_NOISE: LazyLock<OctaveSimplexNoiseSampler> = LazyLock::new(|| {
|
||||
let mut rand = LegacyRand::from_seed(1234);
|
||||
@@ -30,20 +27,17 @@ pub enum 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 {
|
||||
TemperatureModifier::None => temperature,
|
||||
TemperatureModifier::Frozen => {
|
||||
let frozen_ocean_sample =
|
||||
FROZEN_OCEAN_NOISE.sample(pos.x as f64 * 0.05, pos.z as f64 * 0.05, false)
|
||||
* 7.0;
|
||||
let foliage_sample =
|
||||
FOLIAGE_NOISE.sample(pos.x as f64 * 0.2, pos.z as f64 * 0.2, false);
|
||||
FROZEN_OCEAN_NOISE.sample(x * 0.05, z * 0.05, false) * 7.0;
|
||||
let foliage_sample = FOLIAGE_NOISE.sample(x * 0.2, z * 0.2, false);
|
||||
|
||||
let threshold = frozen_ocean_sample + foliage_sample;
|
||||
if threshold < 0.3 {
|
||||
let foliage_sample =
|
||||
FOLIAGE_NOISE.sample(pos.x as f64 * 0.09, pos.z as f64 * 0.09, false);
|
||||
let foliage_sample = FOLIAGE_NOISE.sample(x * 0.09, z * 0.09, false);
|
||||
if foliage_sample < 0.8 {
|
||||
return 0.2f32;
|
||||
}
|
||||
@@ -81,19 +75,18 @@ impl Weather {
|
||||
}
|
||||
|
||||
/// This is an expensive function and should be cached
|
||||
pub fn compute_temperature(&self, pos: &Vector3<i32>, sea_level: i32) -> f32 {
|
||||
let modified_temperature = self
|
||||
.temperature_modifier
|
||||
.convert_temperature(pos, self.temperature);
|
||||
pub fn compute_temperature(&self, x: f64, y: i32, z: f64, sea_level: i32) -> f32 {
|
||||
let modified_temperature =
|
||||
self.temperature_modifier
|
||||
.convert_temperature(x, z, self.temperature);
|
||||
let offset_sea_level = sea_level + 17;
|
||||
|
||||
if pos.y > offset_sea_level {
|
||||
if y > offset_sea_level {
|
||||
let temperature_noise =
|
||||
(TEMPERATURE_NOISE.sample(pos.x as f64 / 8.0, pos.z as f64 / 8.0, false) * 8.0)
|
||||
as f32;
|
||||
(TEMPERATURE_NOISE.sample(x / 8.0, z / 8.0, false) * 8.0) as f32;
|
||||
|
||||
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 {
|
||||
modified_temperature
|
||||
}
|
||||
|
||||
@@ -71,13 +71,7 @@ pub const fn floor_log2(value: u32) -> u8 {
|
||||
}
|
||||
|
||||
pub const fn smallest_encompassing_power_of_two(value: u32) -> u32 {
|
||||
let mut i = value - 1;
|
||||
i |= i >> 1;
|
||||
i |= i >> 2;
|
||||
i |= i >> 4;
|
||||
i |= i >> 8;
|
||||
i |= i >> 16;
|
||||
i + 1
|
||||
value.next_power_of_two()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
||||
@@ -82,7 +82,7 @@ pub struct TextComponentBase {
|
||||
/// Style of the text. Bold, Italic, underline, Color...
|
||||
/// Also has `ClickEvent
|
||||
#[serde(flatten)]
|
||||
pub style: Style,
|
||||
pub style: Box<Style>,
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
/// Extra text components
|
||||
pub extra: Vec<TextComponentBase>,
|
||||
@@ -144,7 +144,7 @@ impl TextComponentBase {
|
||||
// Divide the translation into slices and inserts the substitutions
|
||||
let component = match self.content {
|
||||
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_slices = vec![];
|
||||
|
||||
@@ -171,7 +171,7 @@ impl TextComponentBase {
|
||||
)
|
||||
},
|
||||
},
|
||||
style: Style::default(),
|
||||
style: Box::new(Style::default()),
|
||||
extra: vec![],
|
||||
});
|
||||
}
|
||||
@@ -242,7 +242,7 @@ impl TextComponent {
|
||||
pub fn text<P: Into<Cow<'static, str>>>(plain: P) -> Self {
|
||||
Self(TextComponentBase {
|
||||
content: TextContent::Text { text: plain.into() },
|
||||
style: Style::default(),
|
||||
style: Box::new(Style::default()),
|
||||
extra: vec![],
|
||||
})
|
||||
}
|
||||
@@ -256,7 +256,7 @@ impl TextComponent {
|
||||
translate: key.into(),
|
||||
with: with.into().into_iter().map(|x| x.0).collect(),
|
||||
},
|
||||
style: Style::default(),
|
||||
style: Box::new(Style::default()),
|
||||
extra: vec![],
|
||||
})
|
||||
}
|
||||
@@ -275,7 +275,7 @@ impl TextComponent {
|
||||
locale,
|
||||
with: with.into().into_iter().map(|x| x.0).collect(),
|
||||
},
|
||||
style: Style::default(),
|
||||
style: Box::new(Style::default()),
|
||||
extra: vec![],
|
||||
})
|
||||
}
|
||||
@@ -288,7 +288,7 @@ impl TextComponent {
|
||||
pub fn from_content(content: TextContent) -> Self {
|
||||
Self(TextComponentBase {
|
||||
content,
|
||||
style: Style::default(),
|
||||
style: Box::new(Style::default()),
|
||||
extra: vec![],
|
||||
})
|
||||
}
|
||||
@@ -296,7 +296,7 @@ impl TextComponent {
|
||||
pub fn add_text<P: Into<Cow<'static, str>>>(mut self, text: P) -> Self {
|
||||
self.0.extra.push(TextComponentBase {
|
||||
content: TextContent::Text { text: text.into() },
|
||||
style: Style::default(),
|
||||
style: Box::new(Style::default()),
|
||||
extra: vec![],
|
||||
});
|
||||
self
|
||||
@@ -317,7 +317,7 @@ impl TextComponent {
|
||||
content: TextContent::Text {
|
||||
text: Cow::Owned(with_resolved_fields),
|
||||
},
|
||||
style: Style::default(),
|
||||
style: Box::new(Style::default()),
|
||||
extra: vec![],
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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 key = key.into().to_lowercase();
|
||||
let key = key.to_lowercase();
|
||||
match translations[locale as usize].get(&key) {
|
||||
Some(translation) => translation.clone(),
|
||||
None => match translations[Locale::EnUs as usize].get(&key) {
|
||||
@@ -96,7 +96,7 @@ pub fn reorder_substitutions(
|
||||
.iter()
|
||||
.map(|_| TextComponentBase {
|
||||
content: TextContent::Text { text: "".into() },
|
||||
style: Style::default(),
|
||||
style: Box::new(Style::default()),
|
||||
extra: vec![],
|
||||
})
|
||||
.collect();
|
||||
@@ -138,7 +138,7 @@ pub fn translation_to_pretty<P: Into<Cow<'static, str>>>(
|
||||
locale: Locale,
|
||||
with: Vec<TextComponentBase>,
|
||||
) -> 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('%') {
|
||||
return translation;
|
||||
}
|
||||
@@ -162,7 +162,7 @@ pub fn get_translation_text<P: Into<Cow<'static, str>>>(
|
||||
locale: Locale,
|
||||
with: Vec<TextComponentBase>,
|
||||
) -> 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('%') {
|
||||
return translation;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
use pumpkin_data::chunk::Biome;
|
||||
use pumpkin_util::math::vector3::Vector3;
|
||||
|
||||
use crate::{
|
||||
biome::BiomeSupplier,
|
||||
@@ -21,13 +20,15 @@ impl TheEndBiomeSupplier {
|
||||
|
||||
impl BiomeSupplier for TheEndBiomeSupplier {
|
||||
fn biome(
|
||||
global_biome_pos: &Vector3<i32>,
|
||||
x: i32,
|
||||
y: i32,
|
||||
z: i32,
|
||||
noise: &mut MultiNoiseSampler<'_>,
|
||||
_dimension: Dimension,
|
||||
) -> &'static Biome {
|
||||
let x = biome_coords::to_block(global_biome_pos.x);
|
||||
let y = biome_coords::to_block(global_biome_pos.y);
|
||||
let z = biome_coords::to_block(global_biome_pos.z);
|
||||
let x = biome_coords::to_block(x);
|
||||
let y = biome_coords::to_block(y);
|
||||
let z = biome_coords::to_block(z);
|
||||
let section_x = section_coords::block_to_section(x);
|
||||
let section_z = section_coords::block_to_section(z);
|
||||
if section_x * section_x + section_z * section_z <= 4096 {
|
||||
|
||||
@@ -3,7 +3,6 @@ use std::cell::RefCell;
|
||||
|
||||
use enum_dispatch::enum_dispatch;
|
||||
use pumpkin_data::chunk::{Biome, BiomeTree, NETHER_BIOME_SOURCE, OVERWORLD_BIOME_SOURCE};
|
||||
use pumpkin_util::math::vector3::Vector3;
|
||||
|
||||
use crate::{
|
||||
dimension::Dimension, generation::noise::router::multi_noise_sampler::MultiNoiseSampler,
|
||||
@@ -19,7 +18,9 @@ thread_local! {
|
||||
#[enum_dispatch]
|
||||
pub trait BiomeSupplier {
|
||||
fn biome(
|
||||
at: &Vector3<i32>,
|
||||
x: i32,
|
||||
y: i32,
|
||||
z: i32,
|
||||
noise: &mut MultiNoiseSampler<'_>,
|
||||
dimension: Dimension,
|
||||
) -> &'static Biome;
|
||||
@@ -29,7 +30,9 @@ pub struct MultiNoiseBiomeSupplier;
|
||||
|
||||
impl BiomeSupplier for MultiNoiseBiomeSupplier {
|
||||
fn biome(
|
||||
global_biome_pos: &Vector3<i32>,
|
||||
x: i32,
|
||||
y: i32,
|
||||
z: i32,
|
||||
noise: &mut MultiNoiseSampler<'_>,
|
||||
dimension: Dimension,
|
||||
) -> &'static Biome {
|
||||
@@ -38,7 +41,7 @@ impl BiomeSupplier for MultiNoiseBiomeSupplier {
|
||||
Dimension::Nether => &NETHER_BIOME_SOURCE,
|
||||
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();
|
||||
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)]
|
||||
mod test {
|
||||
use pumpkin_data::{chunk::Biome, noise_router::OVERWORLD_BASE_NOISE_ROUTER};
|
||||
use pumpkin_util::{
|
||||
math::{vector2::Vector2, vector3::Vector3},
|
||||
read_data_from_file,
|
||||
};
|
||||
use pumpkin_util::read_data_from_file;
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::{
|
||||
@@ -84,11 +84,7 @@ mod test {
|
||||
let multi_noise_config = MultiNoiseSamplerBuilderOptions::new(1, 1, 1);
|
||||
let mut sampler =
|
||||
MultiNoiseSampler::generate(&noise_router.multi_noise, &multi_noise_config);
|
||||
let biome = MultiNoiseBiomeSupplier::biome(
|
||||
&pumpkin_util::math::vector3::Vector3 { x: -24, y: 1, z: 8 },
|
||||
&mut sampler,
|
||||
Dimension::Overworld,
|
||||
);
|
||||
let biome = MultiNoiseBiomeSupplier::biome(-24, 1, 8, &mut sampler, Dimension::Overworld);
|
||||
assert_eq!(biome, &Biome::DESERT)
|
||||
}
|
||||
|
||||
@@ -115,14 +111,20 @@ mod test {
|
||||
let default_block = surface_settings.default_block.get_state();
|
||||
|
||||
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
|
||||
use crate::biome::hash_seed;
|
||||
let biome_mixer_seed = hash_seed(random_config.seed);
|
||||
|
||||
let mut chunk =
|
||||
ProtoChunk::new(chunk_pos, surface_settings, default_block, biome_mixer_seed);
|
||||
let mut chunk = ProtoChunk::new(
|
||||
chunk_x,
|
||||
chunk_z,
|
||||
surface_settings,
|
||||
default_block,
|
||||
biome_mixer_seed,
|
||||
);
|
||||
|
||||
// Create MultiNoiseSampler for populate_biomes
|
||||
use crate::generation::noise::router::multi_noise_sampler::{
|
||||
@@ -130,16 +132,13 @@ mod test {
|
||||
};
|
||||
use crate::generation::{biome_coords, positions::chunk_pos};
|
||||
|
||||
let start_x = chunk_pos::start_block_x(&chunk_pos);
|
||||
let start_z = chunk_pos::start_block_z(&chunk_pos);
|
||||
let biome_pos = Vector2::new(
|
||||
biome_coords::from_block(start_x),
|
||||
biome_coords::from_block(start_z),
|
||||
);
|
||||
let start_x = chunk_pos::start_block_x(chunk_x);
|
||||
let start_z = chunk_pos::start_block_z(chunk_z);
|
||||
|
||||
let horizontal_biome_end = biome_coords::from_block(16);
|
||||
let multi_noise_config = MultiNoiseSamplerBuilderOptions::new(
|
||||
biome_pos.x,
|
||||
biome_pos.y,
|
||||
biome_coords::from_block(start_x),
|
||||
biome_coords::from_block(start_z),
|
||||
horizontal_biome_end as usize,
|
||||
);
|
||||
let mut multi_noise_sampler =
|
||||
@@ -148,8 +147,7 @@ mod test {
|
||||
chunk.populate_biomes(Dimension::Overworld, &mut multi_noise_sampler);
|
||||
|
||||
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(&global_biome_pos);
|
||||
let calculated_biome = chunk.get_biome(biome_x, biome_y, biome_z);
|
||||
|
||||
assert_eq!(
|
||||
biome_id,
|
||||
|
||||
@@ -31,10 +31,7 @@ impl NoiseValuePoint {
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use pumpkin_data::{chunk::Biome, noise_router::OVERWORLD_BASE_NOISE_ROUTER};
|
||||
use pumpkin_util::{
|
||||
math::{vector2::Vector2, vector3::Vector3},
|
||||
read_data_from_file,
|
||||
};
|
||||
use pumpkin_util::read_data_from_file;
|
||||
|
||||
use crate::{
|
||||
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");
|
||||
|
||||
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 noise_router =
|
||||
ProtoNoiseRouters::generate(&OVERWORLD_BASE_NOISE_ROUTER, &random_config);
|
||||
@@ -70,7 +69,8 @@ mod test {
|
||||
let biome_mixer_seed = hash_seed(random_config.seed);
|
||||
|
||||
let _chunk = ProtoChunk::new(
|
||||
chunk_pos,
|
||||
chunk_x,
|
||||
chunk_z,
|
||||
surface_config,
|
||||
surface_config.default_block.get_state(),
|
||||
biome_mixer_seed,
|
||||
@@ -82,16 +82,12 @@ mod test {
|
||||
};
|
||||
use crate::generation::{biome_coords, positions::chunk_pos};
|
||||
|
||||
let start_x = chunk_pos::start_block_x(&chunk_pos);
|
||||
let start_z = chunk_pos::start_block_z(&chunk_pos);
|
||||
let biome_pos = Vector2::new(
|
||||
biome_coords::from_block(start_x),
|
||||
biome_coords::from_block(start_z),
|
||||
);
|
||||
let start_x = chunk_pos::start_block_x(chunk_x);
|
||||
let start_z = chunk_pos::start_block_z(chunk_z);
|
||||
let horizontal_biome_end = biome_coords::from_block(16);
|
||||
let multi_noise_config = MultiNoiseSamplerBuilderOptions::new(
|
||||
biome_pos.x,
|
||||
biome_pos.y,
|
||||
biome_coords::from_block(start_x),
|
||||
biome_coords::from_block(start_z),
|
||||
horizontal_biome_end as usize,
|
||||
);
|
||||
let mut multi_noise_sampler =
|
||||
@@ -124,12 +120,8 @@ mod test {
|
||||
);
|
||||
|
||||
for (x, y, z, biome_id) in expected_data {
|
||||
let global_biome_pos = Vector3::new(x, y, z);
|
||||
let calculated_biome = MultiNoiseBiomeSupplier::biome(
|
||||
&global_biome_pos,
|
||||
&mut sampler,
|
||||
Dimension::Overworld,
|
||||
);
|
||||
let calculated_biome =
|
||||
MultiNoiseBiomeSupplier::biome(x, y, z, &mut sampler, Dimension::Overworld);
|
||||
|
||||
assert_eq!(
|
||||
biome_id,
|
||||
|
||||
@@ -342,9 +342,9 @@ impl<S: SingleChunkDataSerializer> AnvilChunkFile<S> {
|
||||
(at.x >> SUBREGION_BITS, at.y >> SUBREGION_BITS)
|
||||
}
|
||||
|
||||
pub const fn get_chunk_index(pos: &Vector2<i32>) -> usize {
|
||||
let local_x = pos.x & SUBREGION_AND;
|
||||
let local_z = pos.y & SUBREGION_AND;
|
||||
pub const fn get_chunk_index(x: i32, z: i32) -> usize {
|
||||
let local_x = x & SUBREGION_AND;
|
||||
let local_z = z & SUBREGION_AND;
|
||||
let index = (local_z << SUBREGION_BITS) + local_x;
|
||||
index as usize
|
||||
}
|
||||
@@ -518,7 +518,7 @@ pub trait SingleChunkDataSerializer: Send + Sync + Sized + Dirtiable {
|
||||
&self,
|
||||
) -> Pin<Box<dyn Future<Output = Result<Bytes, ChunkSerializingError>> + Send + '_>>;
|
||||
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> {
|
||||
@@ -629,7 +629,7 @@ impl<S: SingleChunkDataSerializer> ChunkSerializer for AnvilChunkFile<S> {
|
||||
.unwrap()
|
||||
.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
|
||||
let compression_type = self.chunks_data[index]
|
||||
.as_ref()
|
||||
@@ -797,13 +797,13 @@ impl<S: SingleChunkDataSerializer> ChunkSerializer for AnvilChunkFile<S> {
|
||||
|
||||
async fn get_chunks(
|
||||
&self,
|
||||
chunks: &[Vector2<i32>],
|
||||
chunks: Vec<Vector2<i32>>,
|
||||
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
|
||||
// runtime
|
||||
for chunk in chunks.iter().cloned() {
|
||||
let index = AnvilChunkFile::<S>::get_chunk_index(&chunk);
|
||||
for chunk in chunks.into_iter() {
|
||||
let index = AnvilChunkFile::<S>::get_chunk_index(chunk.x, chunk.y);
|
||||
let is_ok = match &self.chunks_data[index] {
|
||||
None => stream.send(LoadedData::Missing(chunk)).await.is_ok(),
|
||||
Some(chunk_metadata) => {
|
||||
|
||||
@@ -139,8 +139,8 @@ impl LinearFileHeader {
|
||||
}
|
||||
|
||||
impl<S: SingleChunkDataSerializer> LinearFile<S> {
|
||||
const fn get_chunk_index(at: &Vector2<i32>) -> usize {
|
||||
AnvilChunkFile::<S>::get_chunk_index(at)
|
||||
const fn get_chunk_index(x: i32, z: i32) -> usize {
|
||||
AnvilChunkFile::<S>::get_chunk_index(x, z)
|
||||
}
|
||||
|
||||
fn check_signature(bytes: &[u8]) -> Result<(), ChunkReadingError> {
|
||||
@@ -327,7 +327,7 @@ impl<S: SingleChunkDataSerializer> ChunkSerializer for LinearFile<S> {
|
||||
chunk: &Self::Data,
|
||||
_chunk_config: &Self::ChunkConfig,
|
||||
) -> 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
|
||||
.to_bytes()
|
||||
.await
|
||||
@@ -348,13 +348,13 @@ impl<S: SingleChunkDataSerializer> ChunkSerializer for LinearFile<S> {
|
||||
|
||||
async fn get_chunks(
|
||||
&self,
|
||||
chunks: &[Vector2<i32>],
|
||||
chunks: Vec<Vector2<i32>>,
|
||||
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
|
||||
// runtime
|
||||
for chunk in chunks.iter().cloned() {
|
||||
let index = LinearFile::<S>::get_chunk_index(&chunk);
|
||||
for chunk in chunks.into_iter() {
|
||||
let index = LinearFile::<S>::get_chunk_index(chunk.x, chunk.y);
|
||||
let linear_chunk_data = &self.chunks_data[index];
|
||||
|
||||
let result = if let Some(data) = linear_chunk_data {
|
||||
|
||||
@@ -43,8 +43,8 @@ impl SingleChunkDataSerializer for ChunkData {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn position(&self) -> &Vector2<i32> {
|
||||
&self.position
|
||||
fn position(&self) -> (i32, i32) {
|
||||
(self.x, self.z)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -163,7 +163,8 @@ impl ChunkData {
|
||||
Ok(ChunkData {
|
||||
section,
|
||||
heightmap: chunk_data.heightmaps,
|
||||
position,
|
||||
x: position.x,
|
||||
z: position.y,
|
||||
// This chunk is read from disk, so it has not been modified
|
||||
dirty: false,
|
||||
block_ticks: ChunkTickScheduler::from_vec(&chunk_data.block_ticks),
|
||||
@@ -206,8 +207,8 @@ impl ChunkData {
|
||||
|
||||
let nbt = ChunkNbt {
|
||||
data_version: WORLD_DATA_VERSION,
|
||||
x_pos: self.position.x,
|
||||
z_pos: self.position.y,
|
||||
x_pos: self.x,
|
||||
z_pos: self.z,
|
||||
min_y_section: section_coords::block_to_section(self.section.min_y),
|
||||
status: self.status,
|
||||
heightmaps: self.heightmap.clone(),
|
||||
@@ -264,8 +265,8 @@ impl SingleChunkDataSerializer for ChunkEntityData {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn position(&self) -> &Vector2<i32> {
|
||||
&self.chunk_position
|
||||
fn position(&self) -> (i32, i32) {
|
||||
(self.x, self.z)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -310,7 +311,8 @@ impl ChunkEntityData {
|
||||
}
|
||||
|
||||
Ok(ChunkEntityData {
|
||||
chunk_position: position,
|
||||
x: position.x,
|
||||
z: position.y,
|
||||
data: map,
|
||||
dirty: false,
|
||||
})
|
||||
@@ -319,7 +321,7 @@ impl ChunkEntityData {
|
||||
fn internal_to_bytes(&self) -> Result<Bytes, ChunkSerializingError> {
|
||||
let nbt = EntityNbt {
|
||||
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(),
|
||||
};
|
||||
|
||||
|
||||
@@ -273,7 +273,7 @@ where
|
||||
// This minimizes the time we block other operations
|
||||
let reader = async move {
|
||||
let serializer = chunk_serializer.read().await;
|
||||
serializer.get_chunks(&chunks, send).await;
|
||||
serializer.get_chunks(chunks, send).await;
|
||||
};
|
||||
|
||||
join!(intermediary, reader);
|
||||
|
||||
@@ -125,7 +125,7 @@ pub trait ChunkSerializer: Send + Sync + Default {
|
||||
/// Get the chunks data from the serializer
|
||||
fn get_chunks(
|
||||
&self,
|
||||
chunks: &[Vector2<i32>],
|
||||
chunks: Vec<Vector2<i32>>,
|
||||
stream: tokio::sync::mpsc::Sender<LoadedData<Self::Data, ChunkReadingError>>,
|
||||
) -> impl Future<Output = ()> + Send;
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ use pumpkin_data::tag::Taggable;
|
||||
use pumpkin_data::{Block, BlockState};
|
||||
use pumpkin_nbt::compound::NbtCompound;
|
||||
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 std::ops::{BitAnd, BitOr};
|
||||
use std::{collections::HashMap, sync::Arc};
|
||||
@@ -72,7 +72,8 @@ pub struct ChunkData {
|
||||
pub section: ChunkSections,
|
||||
/// See `https://minecraft.wiki/w/Heightmap` for more info
|
||||
pub heightmap: ChunkHeightmaps,
|
||||
pub position: Vector2<i32>,
|
||||
pub x: i32,
|
||||
pub z: i32,
|
||||
pub block_ticks: ChunkTickScheduler<&'static Block>,
|
||||
pub fluid_ticks: ChunkTickScheduler<&'static Fluid>,
|
||||
pub block_entities: HashMap<BlockPos, Arc<dyn BlockEntity>>,
|
||||
@@ -83,7 +84,10 @@ pub struct ChunkData {
|
||||
|
||||
#[derive(Clone)]
|
||||
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 dirty: bool,
|
||||
@@ -528,7 +532,7 @@ impl ChunkData {
|
||||
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())
|
||||
.is_some_and(|fluid| !fluid.states.is_empty());
|
||||
|
||||
|
||||
@@ -779,8 +779,7 @@ impl Chunk {
|
||||
let absolute_y =
|
||||
biome_coords::from_block(generation_settings.shape.min_y as i32)
|
||||
+ y as i32;
|
||||
let biome =
|
||||
proto_chunk.get_biome(&Vector3::new(x as i32, absolute_y, z as i32));
|
||||
let biome = proto_chunk.get_biome(x as i32, absolute_y, z as i32);
|
||||
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) {
|
||||
for z in 0..BlockPalette::SIZE {
|
||||
for x in 0..BlockPalette::SIZE {
|
||||
let block = proto_chunk
|
||||
.get_block_state_raw(&Vector3::new(x as i32, y as i32, z as i32));
|
||||
let block = proto_chunk.get_block_state_raw(x as i32, y as i32, z as i32);
|
||||
section.block_states.set(x, relative_y, z, block);
|
||||
}
|
||||
}
|
||||
@@ -811,7 +809,8 @@ impl Chunk {
|
||||
},
|
||||
section: sections,
|
||||
heightmap: Default::default(),
|
||||
position: proto_chunk.chunk_pos,
|
||||
x: proto_chunk.x,
|
||||
z: proto_chunk.z,
|
||||
dirty: true,
|
||||
block_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 {
|
||||
HeightMap::WorldSurfaceWg => self.top_block_height_exclusive(pos),
|
||||
HeightMap::WorldSurface => self.top_block_height_exclusive(pos),
|
||||
HeightMap::OceanFloorWg => self.ocean_floor_height_exclusive(pos),
|
||||
HeightMap::OceanFloor => self.ocean_floor_height_exclusive(pos),
|
||||
HeightMap::MotionBlocking => self.top_motion_blocking_block_height_exclusive(pos),
|
||||
HeightMap::WorldSurfaceWg => self.top_block_height_exclusive(x, z),
|
||||
HeightMap::WorldSurface => self.top_block_height_exclusive(x, z),
|
||||
HeightMap::OceanFloorWg => self.ocean_floor_height_exclusive(x, z),
|
||||
HeightMap::OceanFloor => self.ocean_floor_height_exclusive(x, z),
|
||||
HeightMap::MotionBlocking => self.top_motion_blocking_block_height_exclusive(x, z),
|
||||
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 {
|
||||
let dx = (pos.x >> 4) - self.x;
|
||||
let dy = (pos.y >> 4) - self.y;
|
||||
fn top_motion_blocking_block_height_exclusive(&self, x: i32, z: i32) -> i32 {
|
||||
let dx = (x >> 4) - self.x;
|
||||
let dy = (z >> 4) - self.y;
|
||||
debug_assert!(dx < self.size && dy < self.size);
|
||||
debug_assert!(dx >= 0 && dy >= 0);
|
||||
match &self.chunks[(dx * self.size + dy) as usize] {
|
||||
@@ -994,18 +993,18 @@ impl GenerationCache for Cache {
|
||||
let chunk = data.blocking_read();
|
||||
chunk.heightmap.get_height(
|
||||
ChunkHeightmapType::MotionBlocking,
|
||||
pos.x,
|
||||
pos.y,
|
||||
x,
|
||||
z,
|
||||
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 {
|
||||
let dx = (pos.x >> 4) - self.x;
|
||||
let dy = (pos.y >> 4) - self.y;
|
||||
fn top_motion_blocking_block_no_leaves_height_exclusive(&self, x: i32, z: i32) -> i32 {
|
||||
let dx = (x >> 4) - self.x;
|
||||
let dy = (z >> 4) - self.y;
|
||||
debug_assert!(dx < self.size && dy < self.size);
|
||||
debug_assert!(dx >= 0 && dy >= 0);
|
||||
match &self.chunks[(dx * self.size + dy) as usize] {
|
||||
@@ -1013,18 +1012,18 @@ impl GenerationCache for Cache {
|
||||
let chunk = data.blocking_read();
|
||||
chunk.heightmap.get_height(
|
||||
ChunkHeightmapType::MotionBlockingNoLeaves,
|
||||
pos.x,
|
||||
pos.y,
|
||||
x,
|
||||
z,
|
||||
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 {
|
||||
let dx = (pos.x >> 4) - self.x;
|
||||
let dy = (pos.y >> 4) - self.y;
|
||||
fn top_block_height_exclusive(&self, x: i32, z: i32) -> i32 {
|
||||
let dx = (x >> 4) - self.x;
|
||||
let dy = (z >> 4) - self.y;
|
||||
debug_assert!(dx < self.size && dy < self.size);
|
||||
debug_assert!(dx >= 0 && dy >= 0);
|
||||
match &self.chunks[(dx * self.size + dy) as usize] {
|
||||
@@ -1032,31 +1031,31 @@ impl GenerationCache for Cache {
|
||||
let chunk = data.blocking_read();
|
||||
chunk.heightmap.get_height(
|
||||
ChunkHeightmapType::WorldSurface,
|
||||
pos.x,
|
||||
pos.y,
|
||||
x,
|
||||
z,
|
||||
chunk.section.min_y,
|
||||
) // 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 {
|
||||
let dx = (pos.x >> 4) - self.x;
|
||||
let dy = (pos.y >> 4) - self.y;
|
||||
fn ocean_floor_height_exclusive(&self, x: i32, z: i32) -> i32 {
|
||||
let dx = (x >> 4) - self.x;
|
||||
let dy = (z >> 4) - self.y;
|
||||
debug_assert!(dx < self.size && dy < self.size);
|
||||
debug_assert!(dx >= 0 && dy >= 0);
|
||||
match &self.chunks[(dx * self.size + dy) as usize] {
|
||||
Chunk::Level(_data) => {
|
||||
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 {
|
||||
let dx = (global_block_pos.x >> 4) - self.x;
|
||||
let dy = (global_block_pos.z >> 4) - self.y;
|
||||
fn get_biome_for_terrain_gen(&self, x: i32, y: i32, z: i32) -> &'static Biome {
|
||||
let dx = (x >> 4) - self.x;
|
||||
let dy = (z >> 4) - self.y;
|
||||
debug_assert!(dx < self.size && dy < self.size);
|
||||
debug_assert!(dx >= 0 && dy >= 0);
|
||||
match &self.chunks[(dx * self.size + dy) as usize] {
|
||||
@@ -1065,16 +1064,12 @@ impl GenerationCache for Cache {
|
||||
Biome::from_id(
|
||||
data.blocking_read()
|
||||
.section
|
||||
.get_rough_biome_absolute_y(
|
||||
(global_block_pos.x & 15) as usize,
|
||||
global_block_pos.y,
|
||||
(global_block_pos.z & 15) as usize,
|
||||
)
|
||||
.get_rough_biome_absolute_y((x & 15) as usize, y, (z & 15) as usize)
|
||||
.unwrap_or(0),
|
||||
)
|
||||
.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((
|
||||
pos,
|
||||
RecvChunk::IO(Proto(Box::new(ProtoChunk::new(
|
||||
pos,
|
||||
pos.x,
|
||||
pos.y,
|
||||
generation_setting,
|
||||
level.world_gen.default_block,
|
||||
biome_mixer_seed,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use enum_dispatch::enum_dispatch;
|
||||
use pumpkin_data::{Block, BlockState};
|
||||
use pumpkin_util::{
|
||||
math::{clamped_map, floor_div, vector2::Vector2, vector3::Vector3},
|
||||
math::{clamped_map, floor_div, vector3::Vector3},
|
||||
random::{RandomDeriver, RandomDeriverImpl, RandomImpl},
|
||||
};
|
||||
|
||||
@@ -45,7 +45,7 @@ impl FluidLevel {
|
||||
#[enum_dispatch(FluidLevelSamplerImpl)]
|
||||
pub enum FluidLevelSampler {
|
||||
Static(StaticFluidLevelSampler),
|
||||
Chunk(Box<StandardChunkFluidLevelSampler>),
|
||||
Chunk(StandardChunkFluidLevelSampler),
|
||||
}
|
||||
|
||||
impl FluidLevelSamplerImpl for FluidLevelSampler {
|
||||
@@ -106,7 +106,7 @@ macro_rules! local_y {
|
||||
pub struct WorldAquiferSampler {
|
||||
fluid_level_sampler: FluidLevelSampler,
|
||||
start_x: i32,
|
||||
start_y: i8,
|
||||
start_y: i32,
|
||||
start_z: i32,
|
||||
size_y: usize,
|
||||
size_z: usize,
|
||||
@@ -115,40 +115,40 @@ pub struct WorldAquiferSampler {
|
||||
}
|
||||
|
||||
impl WorldAquiferSampler {
|
||||
const CHUNK_POS_OFFSETS: [Vector2<i8>; 13] = [
|
||||
Vector2::new(0, 0),
|
||||
Vector2::new(-2, -1),
|
||||
Vector2::new(-1, -1),
|
||||
Vector2::new(0, -1),
|
||||
Vector2::new(1, -1),
|
||||
Vector2::new(-3, 0),
|
||||
Vector2::new(-2, 0),
|
||||
Vector2::new(-1, 0),
|
||||
Vector2::new(1, 0),
|
||||
Vector2::new(-2, 1),
|
||||
Vector2::new(-1, 1),
|
||||
Vector2::new(0, 1),
|
||||
Vector2::new(1, 1),
|
||||
const CHUNK_POS_OFFSETS: [(i8, i8); 13] = [
|
||||
(0, 0),
|
||||
(-2, -1),
|
||||
(-1, -1),
|
||||
(0, -1),
|
||||
(1, -1),
|
||||
(-3, 0),
|
||||
(-2, 0),
|
||||
(-1, 0),
|
||||
(1, 0),
|
||||
(-2, 1),
|
||||
(-1, 1),
|
||||
(0, 1),
|
||||
(1, 1),
|
||||
];
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn new(
|
||||
chunk_pos: Vector2<i32>,
|
||||
chunk_x: i32,
|
||||
chunk_z: i32,
|
||||
random_deriver: &RandomDeriver,
|
||||
minimum_y: i8,
|
||||
height: u16,
|
||||
fluid_level: FluidLevelSampler,
|
||||
) -> Self {
|
||||
let start_x = local_xz!(chunk_pos::start_block_x(&chunk_pos)) - 1;
|
||||
let end_x = local_xz!(chunk_pos::end_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_x)) + 1;
|
||||
let size_x = (end_x - start_x) as usize + 1;
|
||||
|
||||
let start_y = local_y!(minimum_y) - 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 start_z = local_xz!(chunk_pos::start_block_z(&chunk_pos)) - 1;
|
||||
let end_z = local_xz!(chunk_pos::end_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_z)) + 1;
|
||||
let size_z = (end_z - start_z) as usize + 1;
|
||||
|
||||
let cache_size = size_x * size_y * size_z;
|
||||
@@ -178,7 +178,7 @@ impl WorldAquiferSampler {
|
||||
Self {
|
||||
fluid_level_sampler: fluid_level,
|
||||
start_x,
|
||||
start_y,
|
||||
start_y: start_y as i32,
|
||||
start_z,
|
||||
size_y,
|
||||
size_z,
|
||||
@@ -189,7 +189,7 @@ impl WorldAquiferSampler {
|
||||
|
||||
fn packed_position_index(&self, x: i32, y: i32, z: i32) -> 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;
|
||||
|
||||
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 index = self.packed_position_index(local_x, local_y, local_z);
|
||||
let entry = self
|
||||
.levels
|
||||
.get_mut(index)
|
||||
.expect("Index calculated by packed_position_index is out of bounds for self.levels");
|
||||
let entry = &mut self.levels[index];
|
||||
|
||||
let fluid_level = &self.fluid_level_sampler;
|
||||
entry.get_or_insert_with(|| {
|
||||
Self::get_fluid_level(
|
||||
@@ -321,13 +319,13 @@ impl WorldAquiferSampler {
|
||||
let mut bl = false;
|
||||
let mut min_surface_estimate = i32::MAX;
|
||||
|
||||
for offset in Self::CHUNK_POS_OFFSETS {
|
||||
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);
|
||||
for (offset_x, offset_z) in Self::CHUNK_POS_OFFSETS {
|
||||
let x = block_x + section_coords::section_to_block(offset_x as i32);
|
||||
let z = block_z + section_coords::section_to_block(offset_z as i32);
|
||||
|
||||
let n = height_estimator.estimate_height(x, z);
|
||||
let o = n + 8;
|
||||
let bl2 = offset.x == 0 && offset.y == 0;
|
||||
let bl2 = offset_x == 0 && offset_z == 0;
|
||||
|
||||
if bl2 && k > o {
|
||||
return fluid_level.clone();
|
||||
@@ -691,7 +689,6 @@ mod random_positions_and_hypot {
|
||||
use std::{mem, sync::LazyLock};
|
||||
|
||||
use pumpkin_data::noise_router::OVERWORLD_BASE_NOISE_ROUTER;
|
||||
use pumpkin_util::math::vector2::Vector2;
|
||||
|
||||
use crate::{
|
||||
block::RawBlockState,
|
||||
@@ -738,18 +735,20 @@ mod random_positions_and_hypot {
|
||||
.get(&GeneratorSetting::Overworld)
|
||||
.unwrap();
|
||||
let shape = &surface_config.shape;
|
||||
let chunk_pos = Vector2::new(7, 4);
|
||||
let sampler = FluidLevelSampler::Chunk(Box::new(StandardChunkFluidLevelSampler::new(
|
||||
let chunk_x = 7;
|
||||
let chunk_z = 4;
|
||||
|
||||
let sampler = FluidLevelSampler::Chunk(StandardChunkFluidLevelSampler::new(
|
||||
FluidLevel::new(63, &WATER_BLOCK),
|
||||
FluidLevel::new(-54, &LAVA_BLOCK),
|
||||
)));
|
||||
));
|
||||
const CHUNK_WIDTH: usize = 16;
|
||||
let noise = ChunkNoiseGenerator::new(
|
||||
&base_router.noise,
|
||||
&RANDOM_CONFIG,
|
||||
CHUNK_WIDTH / shape.horizontal_cell_block_count() as usize,
|
||||
chunk_pos::start_block_x(&chunk_pos),
|
||||
chunk_pos::start_block_z(&chunk_pos),
|
||||
chunk_pos::start_block_x(chunk_x),
|
||||
chunk_pos::start_block_z(chunk_z),
|
||||
shape,
|
||||
sampler,
|
||||
true,
|
||||
@@ -771,7 +770,7 @@ mod random_positions_and_hypot {
|
||||
BlockStateSampler::Aquifer(aquifer) => aquifer,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let aquifer = match *sampler {
|
||||
let aquifer = match sampler {
|
||||
AquiferSampler::Aquifer(aquifer) => aquifer,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
@@ -783,8 +782,8 @@ mod random_positions_and_hypot {
|
||||
);
|
||||
|
||||
let surface_height_estimator_options = SurfaceHeightSamplerBuilderOptions::new(
|
||||
chunk_pos.x,
|
||||
chunk_pos.y,
|
||||
chunk_x,
|
||||
chunk_z,
|
||||
horizontal_biome_end,
|
||||
shape.min_y as i32,
|
||||
shape.max_y() as i32,
|
||||
|
||||
@@ -7,12 +7,14 @@ pub fn get_biome_blend(
|
||||
bottom_y: i8,
|
||||
height: u16,
|
||||
seed: i64,
|
||||
global_block_pos: &Vector3<i32>,
|
||||
x: i32,
|
||||
y: i32,
|
||||
z: i32,
|
||||
) -> Vector3<i32> {
|
||||
// This is the "left" side of the biome boundary
|
||||
let offset_x = global_block_pos.x - 2;
|
||||
let offset_y = global_block_pos.y - 2;
|
||||
let offset_z = global_block_pos.z - 2;
|
||||
let offset_x = x - 2;
|
||||
let offset_y = y - 2;
|
||||
let offset_z = z - 2;
|
||||
let biome_x = biome_coords::from_block(offset_x);
|
||||
let biome_y = biome_coords::from_block(offset_y);
|
||||
let biome_z = biome_coords::from_block(offset_z);
|
||||
@@ -174,7 +176,7 @@ mod test {
|
||||
|
||||
#[test]
|
||||
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));
|
||||
}
|
||||
|
||||
@@ -191,7 +193,7 @@ mod test {
|
||||
|
||||
let seed = hash_seed((-777i64) as u64);
|
||||
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);
|
||||
assert_eq!(
|
||||
result, expected,
|
||||
|
||||
@@ -6,7 +6,6 @@ use pumpkin_util::{
|
||||
int_provider::IntProvider,
|
||||
pool::{Pool, Weighted},
|
||||
position::BlockPos,
|
||||
vector3::Vector3,
|
||||
},
|
||||
random::{RandomGenerator, RandomImpl, legacy_rand::LegacyRand},
|
||||
};
|
||||
@@ -81,7 +80,7 @@ pub struct DualNoiseBlockStateProvider {
|
||||
base: NoiseBlockStateProvider,
|
||||
variety: [u32; 2],
|
||||
slow_noise: DoublePerlinNoiseParametersCodec,
|
||||
slow_scale: f32,
|
||||
slow_scale: f64,
|
||||
}
|
||||
|
||||
impl DualNoiseBlockStateProvider {
|
||||
@@ -92,7 +91,8 @@ impl DualNoiseBlockStateProvider {
|
||||
&noise,
|
||||
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(
|
||||
slow_noise,
|
||||
-1.0,
|
||||
@@ -102,10 +102,7 @@ impl DualNoiseBlockStateProvider {
|
||||
) as i32;
|
||||
let mut list = Vec::with_capacity(mapped as usize);
|
||||
for i in 0..mapped {
|
||||
let value = self.get_slow_noise(
|
||||
&BlockPos(pos.0.add(&Vector3::new(i * 54545, 0, i * 34234))),
|
||||
&sampler,
|
||||
);
|
||||
let value = self.get_slow_noise(i as f64 * 54545.0, 0.0, i as f64 * 34234.0, &sampler);
|
||||
list.push(
|
||||
self.base
|
||||
.get_state_by_value(&self.base.states, value)
|
||||
@@ -116,11 +113,11 @@ impl DualNoiseBlockStateProvider {
|
||||
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(
|
||||
pos.0.x as f64 * self.slow_scale as f64,
|
||||
pos.0.y as f64 * self.slow_scale as f64,
|
||||
pos.0.z as f64 * self.slow_scale as f64,
|
||||
x * self.slow_scale,
|
||||
y * self.slow_scale,
|
||||
z * self.slow_scale,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
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;
|
||||
|
||||
@@ -30,7 +30,7 @@ pub const WATER_BLOCK: Block = Block::WATER;
|
||||
pub const CHUNK_DIM: u8 = 16;
|
||||
|
||||
pub enum BlockStateSampler {
|
||||
Aquifer(Box<AquiferSampler>),
|
||||
Aquifer(AquiferSampler),
|
||||
Ore(OreVeinSampler),
|
||||
Chained(ChainedBlockStateSampler),
|
||||
}
|
||||
@@ -142,7 +142,8 @@ impl IndexToNoisePos for ChunkIndexMapper {
|
||||
pub struct ChunkNoiseGenerator<'a> {
|
||||
pub state_sampler: BlockStateSampler,
|
||||
generation_shape: &'a GenerationShapeConfig,
|
||||
start_cell_pos: Vector2<i32>,
|
||||
start_cell_pos_x: i32,
|
||||
start_cell_pos_z: i32,
|
||||
|
||||
vertical_cell_count: usize,
|
||||
minimum_cell_y: i32,
|
||||
@@ -166,15 +167,13 @@ impl<'a> ChunkNoiseGenerator<'a> {
|
||||
aquifers: bool,
|
||||
ore_veins: bool,
|
||||
) -> Self {
|
||||
let start_cell_pos = Vector2::new(
|
||||
floor_div(
|
||||
start_block_x,
|
||||
generation_shape.horizontal_cell_block_count() as i32,
|
||||
),
|
||||
floor_div(
|
||||
start_block_z,
|
||||
generation_shape.horizontal_cell_block_count() as i32,
|
||||
),
|
||||
let start_cell_pos_x = floor_div(
|
||||
start_block_x,
|
||||
generation_shape.horizontal_cell_block_count() as i32,
|
||||
);
|
||||
let start_cell_pos_z = floor_div(
|
||||
start_block_z,
|
||||
generation_shape.horizontal_cell_block_count() as i32,
|
||||
);
|
||||
|
||||
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_z = section_coords::block_to_section(start_block_z);
|
||||
AquiferSampler::Aquifer(WorldAquiferSampler::new(
|
||||
Vector2::new(section_x, section_z),
|
||||
section_x,
|
||||
section_z,
|
||||
&random_config.aquifer_random_deriver,
|
||||
generation_shape.min_y,
|
||||
generation_shape.height,
|
||||
@@ -219,23 +219,28 @@ impl<'a> ChunkNoiseGenerator<'a> {
|
||||
AquiferSampler::SeaLevel(SeaLevelAquiferSampler::new(level_sampler))
|
||||
};
|
||||
|
||||
let mut samplers = vec![BlockStateSampler::Aquifer(Box::new(aquifer_sampler))];
|
||||
|
||||
if ore_veins {
|
||||
let state_sampler = if ore_veins {
|
||||
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.into_boxed_slice()));
|
||||
BlockStateSampler::Chained(ChainedBlockStateSampler::new(samplers))
|
||||
} 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);
|
||||
|
||||
Self {
|
||||
state_sampler,
|
||||
generation_shape,
|
||||
start_cell_pos,
|
||||
|
||||
start_cell_pos_x,
|
||||
start_cell_pos_z,
|
||||
vertical_cell_count,
|
||||
minimum_cell_y,
|
||||
|
||||
@@ -249,19 +254,19 @@ impl<'a> ChunkNoiseGenerator<'a> {
|
||||
#[inline]
|
||||
pub fn sample_start_density(&mut self) {
|
||||
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]
|
||||
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) {
|
||||
let x = current_x * self.horizontal_cell_block_count() as i32;
|
||||
|
||||
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;
|
||||
self.cache_fill_unique_id += 1;
|
||||
|
||||
@@ -331,11 +336,11 @@ impl<'a> ChunkNoiseGenerator<'a> {
|
||||
self.cache_fill_unique_id += 1;
|
||||
|
||||
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 =
|
||||
(cell_y as i32 + self.minimum_cell_y) * self.vertical_cell_block_count() as i32;
|
||||
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 {
|
||||
start_x,
|
||||
@@ -363,25 +368,26 @@ impl<'a> ChunkNoiseGenerator<'a> {
|
||||
self.cache_fill_unique_id += 1;
|
||||
}
|
||||
|
||||
#[expect(clippy::too_many_arguments)]
|
||||
pub fn sample_block_state(
|
||||
&mut self,
|
||||
start_pos: Vector3<i32>,
|
||||
cell_pos: Vector3<i32>,
|
||||
start_x: i32,
|
||||
start_y: i32,
|
||||
start_z: i32,
|
||||
cell_x: i32,
|
||||
cell_y: i32,
|
||||
cell_z: i32,
|
||||
height_estimator: &mut SurfaceHeightEstimateSampler,
|
||||
) -> Option<&'static BlockState> {
|
||||
//TODO: Fix this when Blender is added
|
||||
let pos = UnblendedNoisePos::new(
|
||||
start_pos.x + cell_pos.x,
|
||||
start_pos.y + cell_pos.y,
|
||||
start_pos.z + cell_pos.z,
|
||||
);
|
||||
let pos = UnblendedNoisePos::new(start_x + cell_x, start_y + cell_y, start_z + cell_z);
|
||||
|
||||
let options = ChunkNoiseFunctionSampleOptions::new(
|
||||
false,
|
||||
SampleAction::CellCaches(WrapperData::new(
|
||||
cell_pos.x as usize,
|
||||
cell_pos.y as usize,
|
||||
cell_pos.z as usize,
|
||||
cell_x as usize,
|
||||
cell_y as usize,
|
||||
cell_z as usize,
|
||||
self.horizontal_cell_block_count() as usize,
|
||||
self.vertical_cell_block_count() as usize,
|
||||
)),
|
||||
|
||||
@@ -5,7 +5,7 @@ use pumpkin_data::{
|
||||
tag::Taggable,
|
||||
};
|
||||
use pumpkin_util::{
|
||||
math::{position::BlockPos, vector2::Vector2},
|
||||
math::position::BlockPos,
|
||||
random::{RandomGenerator, RandomImpl},
|
||||
};
|
||||
use serde::Deserialize;
|
||||
@@ -38,11 +38,8 @@ impl BambooFeature {
|
||||
let rnd = random.next_bounded_i32(4) + 1;
|
||||
for x in pos.0.x - rnd..pos.0.x + rnd {
|
||||
for z in pos.0.z - rnd..pos.0.z + rnd {
|
||||
let block_below = BlockPos::new(
|
||||
x,
|
||||
chunk.top_block_height_exclusive(&Vector2::new(x, z)) - 1,
|
||||
z,
|
||||
);
|
||||
let block_below =
|
||||
BlockPos::new(x, chunk.top_block_height_exclusive(x, z) - 1, z);
|
||||
let block = GenerationCache::get_block_state(chunk, &block_below.0);
|
||||
if !block.to_block().has_tag(&tag::Block::MINECRAFT_DIRT) {
|
||||
continue;
|
||||
|
||||
@@ -57,7 +57,7 @@ impl OreFeature {
|
||||
|
||||
for _ in n..=(n + 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;
|
||||
}
|
||||
return self.generate_vein_part(chunk, random, d, e, h, j, l, m, n, o, p, q, r);
|
||||
|
||||
@@ -4,7 +4,7 @@ use pumpkin_data::{
|
||||
block_properties::{BlockProperties, EnumVariants, Integer1To4, SeaPickleLikeProperties},
|
||||
};
|
||||
use pumpkin_util::{
|
||||
math::{int_provider::IntProvider, position::BlockPos, vector2::Vector2},
|
||||
math::{int_provider::IntProvider, position::BlockPos},
|
||||
random::{RandomGenerator, RandomImpl},
|
||||
};
|
||||
use serde::Deserialize;
|
||||
@@ -29,7 +29,7 @@ impl SeaPickleFeature {
|
||||
for _ in 0..count {
|
||||
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 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 {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ use pumpkin_data::{
|
||||
block_properties::{BlockProperties, DoubleBlockHalf, TallSeagrassLikeProperties},
|
||||
};
|
||||
use pumpkin_util::{
|
||||
math::{position::BlockPos, vector2::Vector2},
|
||||
math::position::BlockPos,
|
||||
random::{RandomGenerator, RandomImpl},
|
||||
};
|
||||
use serde::Deserialize;
|
||||
@@ -26,7 +26,7 @@ impl SeagrassFeature {
|
||||
) -> bool {
|
||||
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 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);
|
||||
if GenerationCache::get_block_state(chunk, &top_pos.0).to_block() == &Block::WATER {
|
||||
let tall = random.next_f64() < self.probability as f64;
|
||||
|
||||
@@ -9,7 +9,6 @@ use std::sync::LazyLock;
|
||||
use pumpkin_util::biome::FOLIAGE_NOISE;
|
||||
use pumpkin_util::math::int_provider::IntProvider;
|
||||
use pumpkin_util::math::position::BlockPos;
|
||||
use pumpkin_util::math::vector2::Vector2;
|
||||
use pumpkin_util::math::vector3::Vector3;
|
||||
use pumpkin_util::random::{RandomGenerator, RandomImpl};
|
||||
|
||||
@@ -28,7 +27,7 @@ pub static PLACED_FEATURES: LazyLock<HashMap<String, PlacedFeature>> = LazyLock:
|
||||
#[derive(Deserialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum PlacedFeatureWrapper {
|
||||
Direct(Box<PlacedFeature>),
|
||||
Direct(PlacedFeature),
|
||||
Named(String),
|
||||
}
|
||||
|
||||
@@ -325,7 +324,7 @@ impl CountOnEveryLayerPlacementModifier {
|
||||
for _j in 0..self.count.get(random) {
|
||||
let x = random.next_bounded_i32(16) + pos.0.x;
|
||||
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);
|
||||
|
||||
@@ -406,7 +405,7 @@ impl ConditionalPlacementModifier for SurfaceThresholdFilterPlacementModifier {
|
||||
_random: &mut RandomGenerator,
|
||||
pos: BlockPos,
|
||||
) -> 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 max = y.saturating_add(self.max_inclusive.unwrap_or(i32::MAX));
|
||||
min <= pos.0.y && pos.0.y <= max
|
||||
@@ -470,8 +469,8 @@ impl ConditionalPlacementModifier for SurfaceWaterDepthFilterPlacementModifier {
|
||||
_random: &mut RandomGenerator,
|
||||
pos: BlockPos,
|
||||
) -> bool {
|
||||
let world_top = chunk.top_block_height_exclusive(&Vector2::new(pos.0.x, pos.0.z));
|
||||
let ocean = chunk.ocean_floor_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(pos.0.x, pos.0.z);
|
||||
world_top - ocean <= self.max_water_depth
|
||||
}
|
||||
}
|
||||
@@ -490,7 +489,7 @@ impl ConditionalPlacementModifier for BiomePlacementModifier {
|
||||
) -> bool {
|
||||
// we check if the current feature can be applied to the biome at the pos
|
||||
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 {
|
||||
if feature.contains(&name.deref()) {
|
||||
@@ -536,7 +535,7 @@ impl HeightmapPlacementModifier {
|
||||
) -> Box<dyn Iterator<Item = BlockPos>> {
|
||||
let x = pos.0.x;
|
||||
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 {
|
||||
return Box::new(iter::once(BlockPos(Vector3::new(x, top, z))));
|
||||
}
|
||||
|
||||
@@ -33,8 +33,8 @@ pub struct VeryBiasedToBottomHeightProvider {
|
||||
|
||||
impl VeryBiasedToBottomHeightProvider {
|
||||
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 max = self.max_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 as i16, height);
|
||||
let inner = self.inner.unwrap_or(1) as i32;
|
||||
|
||||
let min_rnd = random.next_inbetween_i32(min + inner, max);
|
||||
@@ -52,8 +52,8 @@ pub struct UniformHeightProvider {
|
||||
|
||||
impl UniformHeightProvider {
|
||||
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 max = self.max_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 as i16, height);
|
||||
|
||||
random.next_inbetween_i32(min, max)
|
||||
}
|
||||
@@ -69,21 +69,21 @@ pub struct TrapezoidHeightProvider {
|
||||
impl TrapezoidHeightProvider {
|
||||
pub fn get(&self, random: &mut RandomGenerator, min_y: i8, height: u16) -> i32 {
|
||||
let plateau = self.plateau.unwrap_or(0);
|
||||
let i = self.min_inclusive.get_y(min_y, height);
|
||||
let j = self.max_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 as i16, height);
|
||||
|
||||
if i > j {
|
||||
log::warn!("Empty height range");
|
||||
return i as i32;
|
||||
return i;
|
||||
}
|
||||
|
||||
let k = j - i;
|
||||
if plateau >= k as i32 {
|
||||
return random.next_inbetween_i32(i as i32, j as i32);
|
||||
if plateau >= k {
|
||||
return random.next_inbetween_i32(i, j);
|
||||
}
|
||||
|
||||
let l = (k as i32 - plateau) / 2;
|
||||
let m = k as i32 - l;
|
||||
i as i32 + random.next_inbetween_i32(0, m) + random.next_inbetween_i32(0, l)
|
||||
let l = (k - plateau) / 2;
|
||||
let m = k - l;
|
||||
i + random.next_inbetween_i32(0, m) + random.next_inbetween_i32(0, l)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ use super::{
|
||||
density_function::{IndexToNoisePos, NoiseFunctionComponentRange, NoisePos},
|
||||
};
|
||||
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};
|
||||
|
||||
@@ -486,7 +486,7 @@ impl MutableChunkNoiseFunctionComponentImpl for Cache2D {
|
||||
pos: &impl NoisePos,
|
||||
sample_options: &ChunkNoiseFunctionSampleOptions,
|
||||
) -> 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 {
|
||||
self.last_sample_result
|
||||
} else {
|
||||
|
||||
@@ -70,7 +70,7 @@ pub enum ChunkNoiseFunctionComponent<'a> {
|
||||
Dependent(&'a DependentProtoNoiseFunctionComponent),
|
||||
// NOTE: The box here is intentional: we want to bring down the size to keep the component stack
|
||||
// smaller
|
||||
Chunk(Box<ChunkSpecificNoiseFunctionComponent>),
|
||||
Chunk(ChunkSpecificNoiseFunctionComponent),
|
||||
PassThrough(PassThrough),
|
||||
//Panic(String),
|
||||
}
|
||||
@@ -360,7 +360,7 @@ impl<'a> ChunkNoiseRouter<'a> {
|
||||
match wrapper.wrapper_type {
|
||||
WrapperType::Interpolated => {
|
||||
interpolator_indices.push(component_index);
|
||||
ChunkNoiseFunctionComponent::Chunk(Box::new(
|
||||
ChunkNoiseFunctionComponent::Chunk(
|
||||
ChunkSpecificNoiseFunctionComponent::DensityInterpolator(
|
||||
DensityInterpolator::new(
|
||||
wrapper.input_index,
|
||||
@@ -369,33 +369,33 @@ impl<'a> ChunkNoiseRouter<'a> {
|
||||
build_options,
|
||||
),
|
||||
),
|
||||
))
|
||||
)
|
||||
}
|
||||
WrapperType::CellCache => {
|
||||
cell_cache_indices.push(component_index);
|
||||
ChunkNoiseFunctionComponent::Chunk(Box::new(
|
||||
ChunkNoiseFunctionComponent::Chunk(
|
||||
ChunkSpecificNoiseFunctionComponent::CellCache(CellCache::new(
|
||||
wrapper.input_index,
|
||||
min_value,
|
||||
max_value,
|
||||
build_options,
|
||||
)),
|
||||
))
|
||||
)
|
||||
}
|
||||
WrapperType::CacheOnce => ChunkNoiseFunctionComponent::Chunk(Box::new(
|
||||
WrapperType::CacheOnce => ChunkNoiseFunctionComponent::Chunk(
|
||||
ChunkSpecificNoiseFunctionComponent::CacheOnce(CacheOnce::new(
|
||||
wrapper.input_index,
|
||||
min_value,
|
||||
max_value,
|
||||
)),
|
||||
)),
|
||||
WrapperType::Cache2D => ChunkNoiseFunctionComponent::Chunk(Box::new(
|
||||
),
|
||||
WrapperType::Cache2D => ChunkNoiseFunctionComponent::Chunk(
|
||||
ChunkSpecificNoiseFunctionComponent::Cache2D(Cache2D::new(
|
||||
wrapper.input_index,
|
||||
min_value,
|
||||
max_value,
|
||||
)),
|
||||
)),
|
||||
),
|
||||
WrapperType::CacheFlat => {
|
||||
let mut flat_cache = FlatCache::new(
|
||||
wrapper.input_index,
|
||||
@@ -445,9 +445,9 @@ impl<'a> ChunkNoiseRouter<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
ChunkNoiseFunctionComponent::Chunk(Box::new(
|
||||
ChunkNoiseFunctionComponent::Chunk(
|
||||
ChunkSpecificNoiseFunctionComponent::FlatCache(flat_cache),
|
||||
))
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -485,7 +485,7 @@ impl<'a> ChunkNoiseRouter<'a> {
|
||||
let ChunkNoiseFunctionComponent::Chunk(chunk) = component.first_mut().unwrap() else {
|
||||
unreachable!();
|
||||
};
|
||||
let ChunkSpecificNoiseFunctionComponent::CellCache(cell_cache) = chunk.as_mut() else {
|
||||
let ChunkSpecificNoiseFunctionComponent::CellCache(cell_cache) = chunk else {
|
||||
unreachable!();
|
||||
};
|
||||
|
||||
@@ -514,7 +514,7 @@ impl<'a> ChunkNoiseRouter<'a> {
|
||||
unreachable!();
|
||||
};
|
||||
let ChunkSpecificNoiseFunctionComponent::DensityInterpolator(density_interpolator) =
|
||||
chunk.as_mut()
|
||||
chunk
|
||||
else {
|
||||
unreachable!();
|
||||
};
|
||||
@@ -547,7 +547,7 @@ impl<'a> ChunkNoiseRouter<'a> {
|
||||
};
|
||||
|
||||
let ChunkSpecificNoiseFunctionComponent::DensityInterpolator(density_interpolator) =
|
||||
chunk.as_mut()
|
||||
chunk
|
||||
else {
|
||||
unreachable!();
|
||||
};
|
||||
@@ -566,7 +566,7 @@ impl<'a> ChunkNoiseRouter<'a> {
|
||||
};
|
||||
|
||||
let ChunkSpecificNoiseFunctionComponent::DensityInterpolator(density_interpolator) =
|
||||
chunk.as_mut()
|
||||
chunk
|
||||
else {
|
||||
unreachable!();
|
||||
};
|
||||
@@ -584,7 +584,7 @@ impl<'a> ChunkNoiseRouter<'a> {
|
||||
unreachable!();
|
||||
};
|
||||
let ChunkSpecificNoiseFunctionComponent::DensityInterpolator(density_interpolator) =
|
||||
chunk.as_mut()
|
||||
chunk
|
||||
else {
|
||||
unreachable!();
|
||||
};
|
||||
@@ -602,7 +602,7 @@ impl<'a> ChunkNoiseRouter<'a> {
|
||||
unreachable!();
|
||||
};
|
||||
let ChunkSpecificNoiseFunctionComponent::DensityInterpolator(density_interpolator) =
|
||||
chunk.as_mut()
|
||||
chunk
|
||||
else {
|
||||
unreachable!();
|
||||
};
|
||||
@@ -620,7 +620,7 @@ impl<'a> ChunkNoiseRouter<'a> {
|
||||
unreachable!();
|
||||
};
|
||||
let ChunkSpecificNoiseFunctionComponent::DensityInterpolator(density_interpolator) =
|
||||
chunk.as_mut()
|
||||
chunk
|
||||
else {
|
||||
unreachable!();
|
||||
};
|
||||
|
||||
@@ -181,9 +181,9 @@ impl ShiftedNoise {
|
||||
}
|
||||
|
||||
pub struct InterpolatedNoiseSampler {
|
||||
lower_noise: Box<OctavePerlinNoiseSampler>,
|
||||
upper_noise: Box<OctavePerlinNoiseSampler>,
|
||||
noise: Box<OctavePerlinNoiseSampler>,
|
||||
lower_noise: OctavePerlinNoiseSampler,
|
||||
upper_noise: OctavePerlinNoiseSampler,
|
||||
noise: OctavePerlinNoiseSampler,
|
||||
data: &'static InterpolatedNoiseSamplerData,
|
||||
fractions: [f64; 16],
|
||||
max_value: f64,
|
||||
@@ -197,24 +197,9 @@ impl InterpolatedNoiseSampler {
|
||||
let little_start = -7;
|
||||
let little_amplitudes = [1.0; 8];
|
||||
|
||||
let lower_noise = Box::new(OctavePerlinNoiseSampler::new(
|
||||
random,
|
||||
big_start,
|
||||
&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 lower_noise = OctavePerlinNoiseSampler::new(random, big_start, &big_amplitudes, true);
|
||||
let upper_noise = OctavePerlinNoiseSampler::new(random, big_start, &big_amplitudes, true);
|
||||
let noise = OctavePerlinNoiseSampler::new(random, little_start, &little_amplitudes, true);
|
||||
|
||||
let max_value = lower_noise.get_total_amplitude(data.scaled_y_scale + 2.0);
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ use pumpkin_data::noise_router::{self, BaseNoiseFunctionComponent};
|
||||
use serde::Deserialize;
|
||||
|
||||
// I do a lot of leaking here, but its only for testing
|
||||
|
||||
pub struct HashableF32(pub f32);
|
||||
|
||||
// Normally this is bad, but we just care about checking if components are the same
|
||||
|
||||
@@ -140,13 +140,13 @@ impl<'a> MultiNoiseSampler<'a> {
|
||||
let max_value = component_stack[wrapper.input_index].max();
|
||||
|
||||
match wrapper.wrapper_type {
|
||||
WrapperType::Cache2D => ChunkNoiseFunctionComponent::Chunk(Box::new(
|
||||
WrapperType::Cache2D => ChunkNoiseFunctionComponent::Chunk(
|
||||
ChunkSpecificNoiseFunctionComponent::Cache2D(Cache2D::new(
|
||||
wrapper.input_index,
|
||||
min_value,
|
||||
max_value,
|
||||
)),
|
||||
)),
|
||||
),
|
||||
WrapperType::CacheFlat => {
|
||||
let mut flat_cache = FlatCache::new(
|
||||
wrapper.input_index,
|
||||
@@ -196,9 +196,9 @@ impl<'a> MultiNoiseSampler<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
ChunkNoiseFunctionComponent::Chunk(Box::new(
|
||||
ChunkNoiseFunctionComponent::Chunk(
|
||||
ChunkSpecificNoiseFunctionComponent::FlatCache(flat_cache),
|
||||
))
|
||||
)
|
||||
}
|
||||
// Java passes thru if the noise pos is not the chunk itself, which it is
|
||||
// never for the MultiNoiseSampler
|
||||
|
||||
@@ -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)
|
||||
.unwrap_or_else(|| panic!("Unknown noise id: {id}"));
|
||||
|
||||
@@ -140,7 +140,7 @@ impl ProtoNoiseRouters {
|
||||
base_stack: &[BaseNoiseFunctionComponent],
|
||||
random_config: &GlobalRandomConfig,
|
||||
) -> 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
|
||||
let mut stack = Vec::<ProtoNoiseFunctionComponent>::with_capacity(base_stack.len());
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use pumpkin_data::noise_router::WrapperType;
|
||||
use pumpkin_util::math::vector2::Vector2;
|
||||
|
||||
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_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) {
|
||||
*estimate
|
||||
} else {
|
||||
@@ -125,13 +124,13 @@ impl<'a> SurfaceHeightEstimateSampler<'a> {
|
||||
let max_value = component_stack[wrapper.input_index].max();
|
||||
|
||||
match wrapper.wrapper_type {
|
||||
WrapperType::Cache2D => ChunkNoiseFunctionComponent::Chunk(Box::new(
|
||||
WrapperType::Cache2D => ChunkNoiseFunctionComponent::Chunk(
|
||||
ChunkSpecificNoiseFunctionComponent::Cache2D(Cache2D::new(
|
||||
wrapper.input_index,
|
||||
min_value,
|
||||
max_value,
|
||||
)),
|
||||
)),
|
||||
),
|
||||
WrapperType::CacheFlat => {
|
||||
let mut flat_cache = FlatCache::new(
|
||||
wrapper.input_index,
|
||||
@@ -181,9 +180,9 @@ impl<'a> SurfaceHeightEstimateSampler<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
ChunkNoiseFunctionComponent::Chunk(Box::new(
|
||||
ChunkNoiseFunctionComponent::Chunk(
|
||||
ChunkSpecificNoiseFunctionComponent::FlatCache(flat_cache),
|
||||
))
|
||||
)
|
||||
}
|
||||
// Java passes thru if the noise pos is not the chunk itself, which it is
|
||||
// never for the Height estimator
|
||||
|
||||
@@ -39,10 +39,10 @@ pub mod chunk_pos {
|
||||
use crate::generation::section_coords::get_offset_pos;
|
||||
|
||||
// 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 {
|
||||
(vec.x as u64 & 4294967295u64) | ((vec.y as u64 & 4294967295u64) << 32)
|
||||
pub const fn packed(x: u64, y: u64) -> u64 {
|
||||
(x & 4294967295u64) | ((y & 4294967295u64) << 32)
|
||||
}
|
||||
|
||||
pub const fn unpack_x(packed: u64) -> i32 {
|
||||
@@ -69,20 +69,20 @@ pub mod chunk_pos {
|
||||
get_offset_pos(coord, offset)
|
||||
}
|
||||
|
||||
pub const fn start_block_x(vec: &Vector2<i32>) -> i32 {
|
||||
vec.x << 4
|
||||
pub const fn start_block_x(x: i32) -> i32 {
|
||||
x << 4
|
||||
}
|
||||
|
||||
pub const fn end_block_x(vec: &Vector2<i32>) -> i32 {
|
||||
start_block_x(vec) + 15
|
||||
pub const fn end_block_x(x: i32) -> i32 {
|
||||
start_block_x(x) + 15
|
||||
}
|
||||
|
||||
pub const fn start_block_z(vec: &Vector2<i32>) -> i32 {
|
||||
vec.y << 4
|
||||
pub const fn start_block_z(z: i32) -> i32 {
|
||||
z << 4
|
||||
}
|
||||
|
||||
pub const fn end_block_z(vec: &Vector2<i32>) -> i32 {
|
||||
start_block_z(vec) + 15
|
||||
pub const fn end_block_z(z: i32) -> i32 {
|
||||
start_block_z(z) + 15
|
||||
}
|
||||
|
||||
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)]
|
||||
mod test {
|
||||
use pumpkin_util::math::{vector2::Vector2, vector3::Vector3};
|
||||
use pumpkin_util::math::vector3::Vector3;
|
||||
|
||||
use super::{block_pos, chunk_pos};
|
||||
|
||||
#[test]
|
||||
fn test_chunk_packing() {
|
||||
let pos = Vector2::new(305135135, -1351513511);
|
||||
let packed = chunk_pos::packed(&pos);
|
||||
let x = 305135135_i32;
|
||||
let y = -1351513511_i32;
|
||||
let packed = chunk_pos::packed(x as u64, y as u64);
|
||||
assert_eq!(packed as i64, -5804706329542001121i64);
|
||||
assert_eq!(pos.x, chunk_pos::unpack_x(packed));
|
||||
assert_eq!(pos.y, chunk_pos::unpack_z(packed));
|
||||
assert_eq!(x, chunk_pos::unpack_x(packed));
|
||||
assert_eq!(y, chunk_pos::unpack_z(packed));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -9,7 +9,7 @@ use pumpkin_data::{
|
||||
use pumpkin_util::math::block_box::BlockBox;
|
||||
use pumpkin_util::{
|
||||
HeightMap,
|
||||
math::{position::BlockPos, vector2::Vector2, vector3::Vector3},
|
||||
math::{position::BlockPos, vector3::Vector3},
|
||||
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_fluid_and_fluid_state(&self, position: &Vector3<i32>) -> (Fluid, FluidState);
|
||||
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_no_leaves_height_exclusive(&self, pos: &Vector2<i32>) -> i32;
|
||||
fn get_top_y(&self, heightmap: &HeightMap, pos: &Vector2<i32>) -> i32;
|
||||
fn top_block_height_exclusive(&self, pos: &Vector2<i32>) -> i32;
|
||||
fn ocean_floor_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, x: i32, z: i32) -> i32;
|
||||
fn get_top_y(&self, heightmap: &HeightMap, x: i32, z: i32) -> i32;
|
||||
fn top_block_height_exclusive(&self, x: i32, z: i32) -> i32;
|
||||
fn ocean_floor_height_exclusive(&self, x: i32, z: i32) -> i32;
|
||||
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;
|
||||
@@ -120,7 +120,8 @@ impl FluidLevelSamplerImpl for StandardChunkFluidLevelSampler {
|
||||
///
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ProtoChunk {
|
||||
pub chunk_pos: Vector2<i32>,
|
||||
pub x: i32,
|
||||
pub z: i32,
|
||||
pub default_block: &'static BlockState,
|
||||
biome_mixer_seed: i64,
|
||||
// These are local positions
|
||||
@@ -150,8 +151,8 @@ pub struct TerrainCache {
|
||||
impl TerrainCache {
|
||||
pub fn from_random(random_config: &GlobalRandomConfig) -> Self {
|
||||
let random = &random_config.base_random_deriver;
|
||||
let mut noise_builder = DoublePerlinNoiseBuilder::new(random_config);
|
||||
let terrain_builder = SurfaceTerrainBuilder::new(&mut noise_builder, random);
|
||||
let noise_builder = DoublePerlinNoiseBuilder::new(random_config);
|
||||
let terrain_builder = SurfaceTerrainBuilder::new(&noise_builder, random);
|
||||
let surface_noise = noise_builder.get_noise_sampler_for_id("surface");
|
||||
let secondary_noise = noise_builder.get_noise_sampler_for_id("surface_secondary");
|
||||
Self {
|
||||
@@ -164,7 +165,8 @@ impl TerrainCache {
|
||||
|
||||
impl ProtoChunk {
|
||||
pub fn new(
|
||||
chunk_pos: Vector2<i32>,
|
||||
x: i32,
|
||||
z: i32,
|
||||
settings: &GenerationSettings,
|
||||
default_block: &'static BlockState,
|
||||
biome_mixer_seed: i64,
|
||||
@@ -174,7 +176,8 @@ impl ProtoChunk {
|
||||
|
||||
let default_heightmap = vec![i16::MIN; CHUNK_AREA].into_boxed_slice();
|
||||
Self {
|
||||
chunk_pos,
|
||||
x,
|
||||
z,
|
||||
default_block,
|
||||
flat_block_map: vec![0; CHUNK_AREA * height as usize].into_boxed_slice(),
|
||||
flat_biome_map: vec![
|
||||
@@ -203,7 +206,8 @@ impl ProtoChunk {
|
||||
biome_mixer_seed: i64,
|
||||
) -> Self {
|
||||
let mut proto_chunk = ProtoChunk::new(
|
||||
chunk_data.position,
|
||||
chunk_data.x,
|
||||
chunk_data.z,
|
||||
settings,
|
||||
default_block,
|
||||
biome_mixer_seed,
|
||||
@@ -233,12 +237,11 @@ impl ProtoChunk {
|
||||
let biome = Biome::from_id(biome_id).unwrap();
|
||||
|
||||
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,
|
||||
biome_coords::from_block(relative_y_block),
|
||||
z as i32,
|
||||
);
|
||||
let index = proto_chunk.local_biome_pos_to_biome_index(&local_biome_pos);
|
||||
proto_chunk.flat_biome_map[index] = biome;
|
||||
}
|
||||
}
|
||||
@@ -290,87 +293,84 @@ impl ProtoChunk {
|
||||
self.bottom_y
|
||||
}
|
||||
|
||||
fn maybe_update_surface_height_map(&mut self, pos: &Vector3<i32>) {
|
||||
let local_x = pos.x & 15;
|
||||
let local_z = pos.z & 15;
|
||||
fn maybe_update_surface_height_map(&mut self, local_x: i32, y: i32, local_z: i32) {
|
||||
let index = Self::local_position_to_height_map_index(local_x, local_z);
|
||||
let current_height = self.flat_surface_height_map[index];
|
||||
|
||||
if pos.y > current_height as i32 {
|
||||
self.flat_surface_height_map[index] = pos.y as _;
|
||||
if y > current_height as i32 {
|
||||
self.flat_surface_height_map[index] = y as _;
|
||||
}
|
||||
}
|
||||
|
||||
fn maybe_update_ocean_floor_height_map(&mut self, pos: &Vector3<i32>) {
|
||||
let local_x = pos.x & 15;
|
||||
let local_z = pos.z & 15;
|
||||
fn maybe_update_ocean_floor_height_map(&mut self, local_x: i32, y: i32, local_z: i32) {
|
||||
let index = Self::local_position_to_height_map_index(local_x, local_z);
|
||||
let current_height = self.flat_ocean_floor_height_map[index];
|
||||
|
||||
if pos.y > current_height as i32 {
|
||||
self.flat_ocean_floor_height_map[index] = pos.y as _;
|
||||
if y > current_height as i32 {
|
||||
self.flat_ocean_floor_height_map[index] = y as _;
|
||||
}
|
||||
}
|
||||
|
||||
fn maybe_update_motion_blocking_height_map(&mut self, pos: &Vector3<i32>) {
|
||||
let local_x = pos.x & 15;
|
||||
let local_z = pos.z & 15;
|
||||
fn maybe_update_motion_blocking_height_map(&mut self, local_x: i32, y: i32, local_z: i32) {
|
||||
let index = Self::local_position_to_height_map_index(local_x, local_z);
|
||||
let current_height = self.flat_motion_blocking_height_map[index];
|
||||
|
||||
if pos.y > current_height as i32 {
|
||||
self.flat_motion_blocking_height_map[index] = pos.y as _;
|
||||
if y > current_height as i32 {
|
||||
self.flat_motion_blocking_height_map[index] = y as _;
|
||||
}
|
||||
}
|
||||
|
||||
fn maybe_update_motion_blocking_no_leaves_height_map(&mut self, pos: &Vector3<i32>) {
|
||||
let local_x = pos.x & 15;
|
||||
let local_z = pos.z & 15;
|
||||
fn maybe_update_motion_blocking_no_leaves_height_map(
|
||||
&mut self,
|
||||
local_x: i32,
|
||||
y: i32,
|
||||
local_z: i32,
|
||||
) {
|
||||
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];
|
||||
|
||||
if pos.y > current_height as i32 {
|
||||
self.flat_motion_blocking_no_leaves_height_map[index] = pos.y as _;
|
||||
if y > current_height as i32 {
|
||||
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 {
|
||||
HeightMap::WorldSurfaceWg => self.top_block_height_exclusive(pos),
|
||||
HeightMap::WorldSurface => self.top_block_height_exclusive(pos),
|
||||
HeightMap::OceanFloorWg => self.ocean_floor_height_exclusive(pos),
|
||||
HeightMap::OceanFloor => self.ocean_floor_height_exclusive(pos),
|
||||
HeightMap::MotionBlocking => self.top_motion_blocking_block_height_exclusive(pos),
|
||||
HeightMap::WorldSurfaceWg => self.top_block_height_exclusive(x, z),
|
||||
HeightMap::WorldSurface => self.top_block_height_exclusive(x, z),
|
||||
HeightMap::OceanFloorWg => self.ocean_floor_height_exclusive(x, z),
|
||||
HeightMap::OceanFloor => self.ocean_floor_height_exclusive(x, z),
|
||||
HeightMap::MotionBlocking => self.top_motion_blocking_block_height_exclusive(x, z),
|
||||
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 {
|
||||
let local_x = pos.x & 15;
|
||||
let local_z = pos.y & 15;
|
||||
pub fn top_block_height_exclusive(&self, x: i32, z: i32) -> i32 {
|
||||
let local_x = x & 15;
|
||||
let local_z = z & 15;
|
||||
let index = Self::local_position_to_height_map_index(local_x, local_z);
|
||||
self.flat_surface_height_map[index] as i32 + 1
|
||||
}
|
||||
|
||||
pub fn ocean_floor_height_exclusive(&self, pos: &Vector2<i32>) -> i32 {
|
||||
let local_x = pos.x & 15;
|
||||
let local_z = pos.y & 15;
|
||||
pub fn ocean_floor_height_exclusive(&self, x: i32, z: i32) -> i32 {
|
||||
let local_x = x & 15;
|
||||
let local_z = z & 15;
|
||||
let index = Self::local_position_to_height_map_index(local_x, local_z);
|
||||
self.flat_ocean_floor_height_map[index] as i32 + 1
|
||||
}
|
||||
|
||||
pub fn top_motion_blocking_block_height_exclusive(&self, pos: &Vector2<i32>) -> i32 {
|
||||
let local_x = pos.x & 15;
|
||||
let local_z = pos.y & 15;
|
||||
pub fn top_motion_blocking_block_height_exclusive(&self, x: i32, z: i32) -> i32 {
|
||||
let local_x = x & 15;
|
||||
let local_z = z & 15;
|
||||
let index = Self::local_position_to_height_map_index(local_x, local_z);
|
||||
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 {
|
||||
let local_x = pos.x & 15;
|
||||
let local_z = pos.y & 15;
|
||||
pub fn top_motion_blocking_block_no_leaves_height_exclusive(&self, x: i32, z: i32) -> i32 {
|
||||
let local_x = x & 15;
|
||||
let local_z = z & 15;
|
||||
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
|
||||
}
|
||||
@@ -381,40 +381,39 @@ impl ProtoChunk {
|
||||
}
|
||||
|
||||
#[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)]
|
||||
{
|
||||
assert!(local_pos.x >= 0 && local_pos.x <= 15);
|
||||
assert!(local_pos.y < self.height() as i32);
|
||||
assert!(local_pos.y >= 0);
|
||||
assert!(local_pos.z >= 0 && local_pos.z <= 15);
|
||||
assert!((0..=15).contains(&x));
|
||||
assert!(y < self.height() as i32);
|
||||
assert!(y >= 0);
|
||||
assert!((0..=15).contains(&z));
|
||||
}
|
||||
self.height() as usize * CHUNK_DIM as usize * local_pos.x as usize
|
||||
+ CHUNK_DIM as usize * local_pos.y as usize
|
||||
+ local_pos.z as usize
|
||||
self.height() as usize * CHUNK_DIM as usize * x as usize
|
||||
+ CHUNK_DIM as usize * y as usize
|
||||
+ z as usize
|
||||
}
|
||||
|
||||
#[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)]
|
||||
{
|
||||
assert!(local_biome_pos.x >= 0 && local_biome_pos.x <= 3);
|
||||
assert!((0..=3).contains(&x));
|
||||
assert!(
|
||||
local_biome_pos.y < biome_coords::from_chunk(self.height() as i32)
|
||||
&& local_biome_pos.y >= 0,
|
||||
y < biome_coords::from_chunk(self.height() as i32) && y >= 0,
|
||||
"{} - {} vs {}",
|
||||
0,
|
||||
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(CHUNK_DIM as usize)
|
||||
* local_biome_pos.x as usize
|
||||
+ biome_coords::from_block(CHUNK_DIM as usize) * local_biome_pos.y as usize
|
||||
+ local_biome_pos.z as usize
|
||||
* x as usize
|
||||
+ biome_coords::from_block(CHUNK_DIM as usize) * y as usize
|
||||
+ z as usize
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@@ -424,76 +423,70 @@ impl ProtoChunk {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_block_state_raw(&self, local_pos: &Vector3<i32>) -> u16 {
|
||||
let index = self.local_pos_to_block_index(local_pos);
|
||||
pub fn get_block_state_raw(&self, x: i32, y: i32, z: i32) -> u16 {
|
||||
let index = self.local_pos_to_block_index(x, y, z);
|
||||
self.flat_block_map[index]
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_block_state(&self, local_pos: &Vector3<i32>) -> RawBlockState {
|
||||
let local_pos = Vector3::new(
|
||||
local_pos.x & 15,
|
||||
local_pos.y - self.bottom_y() as i32,
|
||||
local_pos.z & 15,
|
||||
);
|
||||
if local_pos.y < 0 || local_pos.y >= self.height() as i32 {
|
||||
let local_y = local_pos.y - self.bottom_y() as i32;
|
||||
if local_y < 0 || local_y >= self.height() as i32 {
|
||||
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) {
|
||||
let local_pos = Vector3::new(pos.x & 15, pos.y - self.bottom_y() as i32, pos.z & 15);
|
||||
if local_pos.y < 0 || local_pos.y >= self.height() as i32 {
|
||||
let local_x = pos.x & 15;
|
||||
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;
|
||||
}
|
||||
if !block_state.is_air() {
|
||||
self.maybe_update_surface_height_map(pos);
|
||||
}
|
||||
|
||||
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);
|
||||
self.maybe_update_surface_height_map(local_x, pos.y, local_z);
|
||||
let block = Block::from_state_id(block_state.id);
|
||||
if !block.has_tag(&tag::Block::MINECRAFT_LEAVES) {
|
||||
{
|
||||
self.maybe_update_motion_blocking_no_leaves_height_map(pos);
|
||||
|
||||
let blocks_movement = blocks_movement(block_state, block);
|
||||
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;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_biome(&self, global_biome_pos: &Vector3<i32>) -> &'static Biome {
|
||||
let local_pos = Vector3::new(
|
||||
global_biome_pos.x & biome_coords::from_block(15),
|
||||
global_biome_pos.y - biome_coords::from_block(self.bottom_y() as i32),
|
||||
global_biome_pos.z & biome_coords::from_block(15),
|
||||
pub fn get_biome(&self, x: i32, y: i32, z: i32) -> &'static Biome {
|
||||
let index = self.local_biome_pos_to_biome_index(
|
||||
x & biome_coords::from_block(15),
|
||||
y - biome_coords::from_block(self.bottom_y() as i32),
|
||||
z & biome_coords::from_block(15),
|
||||
);
|
||||
let index = self.local_biome_pos_to_biome_index(&local_pos);
|
||||
self.flat_biome_map[index]
|
||||
}
|
||||
|
||||
pub fn step_to_biomes(&mut self, dimension: Dimension, noise_router: &ProtoNoiseRouters) {
|
||||
debug_assert_eq!(self.stage, StagedChunkEnum::Empty);
|
||||
let chunk_pos = self.chunk_pos;
|
||||
let start_x = start_block_x(&chunk_pos);
|
||||
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 start_x = start_block_x(self.x);
|
||||
let start_z = start_block_z(self.z);
|
||||
let horizontal_biome_end = biome_coords::from_block(16);
|
||||
let multi_noise_config =
|
||||
super::noise::router::multi_noise_sampler::MultiNoiseSamplerBuilderOptions::new(
|
||||
biome_pos.x,
|
||||
biome_pos.y,
|
||||
biome_coords::from_block(start_x),
|
||||
biome_coords::from_block(start_z),
|
||||
horizontal_biome_end as usize,
|
||||
);
|
||||
let mut multi_noise_sampler =
|
||||
@@ -510,16 +503,15 @@ impl ProtoChunk {
|
||||
) {
|
||||
debug_assert_eq!(self.stage, StagedChunkEnum::Biomes);
|
||||
|
||||
let chunk_pos = self.chunk_pos;
|
||||
let generation_shape = &settings.shape;
|
||||
let horizontal_cell_count = CHUNK_DIM / generation_shape.horizontal_cell_block_count();
|
||||
let start_x = start_block_x(&chunk_pos);
|
||||
let start_z = start_block_z(&chunk_pos);
|
||||
let start_x = start_block_x(self.x);
|
||||
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(-54, &Block::LAVA),
|
||||
)));
|
||||
));
|
||||
|
||||
let mut noise_sampler = ChunkNoiseGenerator::new(
|
||||
&noise_router.noise,
|
||||
@@ -532,16 +524,13 @@ impl ProtoChunk {
|
||||
settings.aquifers_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(
|
||||
horizontal_cell_count * generation_shape.horizontal_cell_block_count(),
|
||||
);
|
||||
let surface_config = SurfaceHeightSamplerBuilderOptions::new(
|
||||
biome_pos.x,
|
||||
biome_pos.y,
|
||||
biome_coords::from_block(start_x),
|
||||
biome_coords::from_block(start_z),
|
||||
horizontal_biome_end as usize,
|
||||
generation_shape.min_y as i32,
|
||||
generation_shape.max_y() as i32,
|
||||
@@ -565,22 +554,17 @@ impl ProtoChunk {
|
||||
) {
|
||||
debug_assert_eq!(self.stage, StagedChunkEnum::Noise);
|
||||
// Build surface
|
||||
let chunk_pos = self.chunk_pos;
|
||||
let start_x = start_block_x(&chunk_pos);
|
||||
let start_z = start_block_z(&chunk_pos);
|
||||
let start_x = start_block_x(self.x);
|
||||
let start_z = start_block_z(self.z);
|
||||
let generation_shape = &settings.shape;
|
||||
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(
|
||||
horizontal_cell_count * generation_shape.horizontal_cell_block_count(),
|
||||
);
|
||||
let surface_config = SurfaceHeightSamplerBuilderOptions::new(
|
||||
biome_pos.x,
|
||||
biome_pos.y,
|
||||
biome_coords::from_block(start_x),
|
||||
biome_coords::from_block(start_z),
|
||||
horizontal_biome_end as usize,
|
||||
generation_shape.min_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 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_z = chunk_pos::start_block_z(&self.chunk_pos);
|
||||
let start_block_x = start_block_x(self.x);
|
||||
let start_block_z = start_block_z(self.z);
|
||||
|
||||
let start_biome_x = biome_coords::from_block(start_block_x);
|
||||
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 y 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 {
|
||||
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 {
|
||||
MultiNoiseBiomeSupplier::biome(
|
||||
&biome_pos,
|
||||
start_biome_x + x,
|
||||
start_biome_y + y,
|
||||
start_biome_z + z,
|
||||
multi_noise_sampler,
|
||||
dimension,
|
||||
)
|
||||
};
|
||||
//dbg!("Populating biome: {:?} -> {:?}", biome_pos, biome);
|
||||
|
||||
let local_biome_pos = Vector3 {
|
||||
let index = self.local_biome_pos_to_biome_index(
|
||||
x,
|
||||
// Make the y start from 0
|
||||
y: start_biome_y + y - biome_coords::from_block(min_y as i32),
|
||||
start_biome_y + y - biome_coords::from_block(min_y as i32),
|
||||
z,
|
||||
};
|
||||
let index = self.local_biome_pos_to_biome_index(&local_biome_pos);
|
||||
);
|
||||
|
||||
self.flat_biome_map[index] = biome;
|
||||
}
|
||||
@@ -722,12 +710,12 @@ impl ProtoChunk {
|
||||
|
||||
let block_state = noise_sampler
|
||||
.sample_block_state(
|
||||
Vector3::new(
|
||||
sample_start_x,
|
||||
sample_start_y,
|
||||
sample_start_z,
|
||||
),
|
||||
Vector3::new(cell_offset_x, cell_offset_y, cell_offset_z),
|
||||
sample_start_x,
|
||||
sample_start_y,
|
||||
sample_start_z,
|
||||
cell_offset_x,
|
||||
cell_offset_y,
|
||||
cell_offset_z,
|
||||
surface_height_estimate_sampler,
|
||||
)
|
||||
.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
|
||||
let seed_biome_pos = biome::get_biome_blend(
|
||||
self.bottom_y(),
|
||||
self.height(),
|
||||
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.
|
||||
@@ -767,8 +757,8 @@ impl ProtoChunk {
|
||||
terrain_cache: &TerrainCache,
|
||||
surface_height_estimate_sampler: &mut SurfaceHeightEstimateSampler,
|
||||
) {
|
||||
let start_x = chunk_pos::start_block_x(&self.chunk_pos);
|
||||
let start_z = chunk_pos::start_block_z(&self.chunk_pos);
|
||||
let start_x = chunk_pos::start_block_x(self.x);
|
||||
let start_z = chunk_pos::start_block_z(self.z);
|
||||
let min_y = self.bottom_y();
|
||||
|
||||
let random = &random_config.base_random_deriver;
|
||||
@@ -788,8 +778,7 @@ impl ProtoChunk {
|
||||
let x = start_x + local_x;
|
||||
let z = start_z + local_z;
|
||||
|
||||
let mut top_block =
|
||||
self.top_block_height_exclusive(&Vector2::new(local_x, local_z));
|
||||
let mut top_block = self.top_block_height_exclusive(local_x, local_z);
|
||||
|
||||
let biome_y = if settings.legacy_random_source {
|
||||
0
|
||||
@@ -797,14 +786,14 @@ impl ProtoChunk {
|
||||
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 {
|
||||
terrain_cache
|
||||
.terrain_builder
|
||||
.place_badlands_pillar(self, x, z, top_block);
|
||||
|
||||
// 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);
|
||||
@@ -858,7 +847,11 @@ impl ProtoChunk {
|
||||
// panic!("Blending with biome {:?} at: {:?}", biome, biome_pos);
|
||||
|
||||
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(
|
||||
self,
|
||||
&mut context,
|
||||
@@ -905,15 +898,14 @@ impl ProtoChunk {
|
||||
) {
|
||||
let chunk = cache.get_center_chunk_mut();
|
||||
debug_assert_eq!(chunk.stage, StagedChunkEnum::Surface);
|
||||
let chunk_pos = chunk.chunk_pos;
|
||||
let min_y = chunk.bottom_y();
|
||||
let height = chunk.height();
|
||||
|
||||
let bottom_section = section_coords::block_to_section(min_y) as i32;
|
||||
let block_pos = BlockPos(Vector3::new(
|
||||
section_coords::section_to_block(chunk_pos.x),
|
||||
section_coords::section_to_block(chunk.x),
|
||||
bottom_section,
|
||||
section_coords::section_to_block(chunk_pos.y),
|
||||
section_coords::section_to_block(chunk.z),
|
||||
));
|
||||
|
||||
let population_seed =
|
||||
@@ -953,7 +945,7 @@ impl ProtoChunk {
|
||||
// for structure in &set.structures {
|
||||
// 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; // ??
|
||||
}
|
||||
|
||||
@@ -976,9 +968,8 @@ impl ProtoChunk {
|
||||
}
|
||||
|
||||
fn get_block_box_for_chunk(&self) -> BlockBox {
|
||||
let pos = self.chunk_pos;
|
||||
let x = start_block_x(&pos);
|
||||
let z = start_block_z(&pos);
|
||||
let x = start_block_x(self.x);
|
||||
let z = start_block_z(self.z);
|
||||
let bottom = self.bottom_y() as i32 + 1;
|
||||
let top = self.top_y() as i32;
|
||||
BlockBox::new(x, bottom, z, x + 15, top, z + 15)
|
||||
@@ -993,11 +984,11 @@ impl ProtoChunk {
|
||||
}
|
||||
|
||||
fn start_block_x(&self) -> i32 {
|
||||
start_block_x(&self.chunk_pos)
|
||||
start_block_x(self.x)
|
||||
}
|
||||
|
||||
fn start_block_z(&self) -> i32 {
|
||||
start_block_z(&self.chunk_pos)
|
||||
start_block_z(self.z)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -48,7 +48,11 @@ impl StructureType {
|
||||
StructureType::NetherFortress(generator) => generator.get_structure_position(chunk),
|
||||
};
|
||||
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)
|
||||
.unwrap()
|
||||
.contains(¤t_biome.registry_id)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use pumpkin_util::{
|
||||
math::{floor_div, vector2::Vector2},
|
||||
math::floor_div,
|
||||
random::{
|
||||
RandomGenerator, RandomImpl, get_carver_seed, get_region_seed, xoroshiro128::Xoroshiro,
|
||||
},
|
||||
@@ -19,22 +19,23 @@ impl StructurePlacement {
|
||||
pub fn should_generate(
|
||||
&self,
|
||||
calculator: StructurePlacementCalculator,
|
||||
chunk_pos: Vector2<i32>,
|
||||
chunk_x: i32,
|
||||
chunk_z: i32,
|
||||
) -> bool {
|
||||
self.r#type
|
||||
.is_start_chunk(&calculator, chunk_pos, self.salt)
|
||||
&& self.apply_frequency_reduction(calculator.seed, chunk_pos)
|
||||
.is_start_chunk(&calculator, chunk_x, chunk_z, self.salt)
|
||||
&& self.apply_frequency_reduction(calculator.seed, chunk_x, chunk_z)
|
||||
// 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);
|
||||
frequency >= 1.0
|
||||
|| self
|
||||
.frequency_reduction_method
|
||||
.as_ref()
|
||||
.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(
|
||||
&self,
|
||||
seed: i64,
|
||||
chunk_pos: Vector2<i32>,
|
||||
chunk_x: i32,
|
||||
chunk_z: i32,
|
||||
salt: i32,
|
||||
frequency: f32,
|
||||
) -> bool {
|
||||
match self {
|
||||
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));
|
||||
random.next_f32() < frequency
|
||||
}
|
||||
FrequencyReductionMethod::LegacyType1 => {
|
||||
let x = chunk_pos.x >> 4;
|
||||
let z = chunk_pos.y >> 4;
|
||||
let x = chunk_x >> 4;
|
||||
let z = chunk_z >> 4;
|
||||
let mut random = RandomGenerator::Xoroshiro(Xoroshiro::from_seed(
|
||||
(x ^ z << 4) as u64 ^ seed as u64,
|
||||
));
|
||||
@@ -71,15 +73,14 @@ impl FrequencyReductionMethod {
|
||||
random.next_bounded_i32((1.0 / frequency) as i32) == 0
|
||||
}
|
||||
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));
|
||||
random.next_f32() < frequency
|
||||
}
|
||||
FrequencyReductionMethod::LegacyType3 => {
|
||||
let mut random: RandomGenerator =
|
||||
RandomGenerator::Xoroshiro(Xoroshiro::from_seed(seed as u64));
|
||||
let carver_seed =
|
||||
get_carver_seed(&mut random, seed as u64, chunk_pos.x, chunk_pos.y);
|
||||
let carver_seed = get_carver_seed(&mut random, seed as u64, chunk_x, chunk_z);
|
||||
let mut random: RandomGenerator =
|
||||
RandomGenerator::Xoroshiro(Xoroshiro::from_seed(carver_seed));
|
||||
|
||||
@@ -102,12 +103,13 @@ impl StructurePlacementType {
|
||||
pub fn is_start_chunk(
|
||||
&self,
|
||||
calculator: &StructurePlacementCalculator,
|
||||
chunk_pos: Vector2<i32>,
|
||||
chunk_x: i32,
|
||||
chunk_z: i32,
|
||||
salt: i32,
|
||||
) -> bool {
|
||||
match self {
|
||||
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
|
||||
}
|
||||
@@ -140,25 +142,26 @@ impl SpreadType {
|
||||
}
|
||||
|
||||
impl RandomSpreadStructurePlacement {
|
||||
fn get_start_chunk(&self, seed: i64, chunk_pos: Vector2<i32>, salt: i32) -> Vector2<i32> {
|
||||
let x = floor_div(chunk_pos.x, self.spacing);
|
||||
let z = floor_div(chunk_pos.y, self.spacing);
|
||||
fn get_start_chunk(&self, seed: i64, chunk_x: i32, chunk_z: i32, salt: i32) -> (i32, i32) {
|
||||
let x = floor_div(chunk_x, self.spacing);
|
||||
let z = floor_div(chunk_z, self.spacing);
|
||||
let region_seed = get_region_seed(seed as u64, x, z, salt);
|
||||
let mut random = RandomGenerator::Xoroshiro(Xoroshiro::from_seed(region_seed));
|
||||
let bound = self.spacing - self.separation;
|
||||
let rand_x = 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(
|
||||
&self,
|
||||
calculator: &StructurePlacementCalculator,
|
||||
chunk_pos: Vector2<i32>,
|
||||
chunk_x: i32,
|
||||
chunk_z: i32,
|
||||
salt: i32,
|
||||
) -> bool {
|
||||
let pos = self.get_start_chunk(calculator.seed, chunk_pos, salt);
|
||||
pos == chunk_pos
|
||||
let pos = self.get_start_chunk(calculator.seed, chunk_x, chunk_z, salt);
|
||||
(chunk_x == pos.0) && (chunk_z == pos.1)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use pumpkin_data::{Block, BlockDirection};
|
||||
use pumpkin_util::{
|
||||
HeightMap,
|
||||
math::{block_box::BlockBox, position::BlockPos, vector2::Vector2, vector3::Vector3},
|
||||
math::{block_box::BlockBox, position::BlockPos, vector3::Vector3},
|
||||
};
|
||||
use serde::Deserialize;
|
||||
|
||||
@@ -18,14 +18,14 @@ pub struct BuriedTreasureGenerator;
|
||||
|
||||
impl StructureGenerator for BuriedTreasureGenerator {
|
||||
fn get_structure_position(&self, chunk: &ProtoChunk) -> super::StructurePosition {
|
||||
let x = get_center_x(chunk.chunk_pos.x);
|
||||
let z = get_center_z(chunk.chunk_pos.y);
|
||||
let y = chunk.get_top_y(&HeightMap::OceanFloorWg, &Vector2::new(x, z)) - 1;
|
||||
let x = get_center_x(chunk.x);
|
||||
let z = get_center_z(chunk.z);
|
||||
let y = chunk.get_top_y(&HeightMap::OceanFloorWg, x, z) - 1;
|
||||
let generator = StructurePiecesCollector {
|
||||
pieces_positions: vec![BlockBox::from_pos(BlockPos::new(
|
||||
get_offset_x(chunk.chunk_pos.x, 9),
|
||||
get_offset_x(chunk.x, 9),
|
||||
90,
|
||||
get_offset_z(chunk.chunk_pos.y, 9),
|
||||
get_offset_z(chunk.z, 9),
|
||||
))],
|
||||
};
|
||||
StructurePosition {
|
||||
@@ -37,7 +37,8 @@ impl StructureGenerator for BuriedTreasureGenerator {
|
||||
fn generate(&self, bounding_box: BlockBox, chunk: &mut crate::ProtoChunk) {
|
||||
let y = chunk.get_top_y(
|
||||
&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);
|
||||
for _ in y..chunk.bottom_y() as i32 {
|
||||
|
||||
@@ -17,9 +17,8 @@ pub struct NetherFortressGenerator;
|
||||
|
||||
impl StructureGenerator for NetherFortressGenerator {
|
||||
fn get_structure_position(&self, chunk: &ProtoChunk) -> StructurePosition {
|
||||
let chunk_pos = chunk.chunk_pos;
|
||||
let start_x = chunk_pos::start_block_x(&chunk_pos);
|
||||
let start_z = chunk_pos::start_block_z(&chunk_pos);
|
||||
let start_x = chunk_pos::start_block_x(chunk.x);
|
||||
let start_z = chunk_pos::start_block_z(chunk.z);
|
||||
let generator = StructurePiecesCollector {
|
||||
pieces_positions: vec![], // TODO
|
||||
};
|
||||
|
||||
@@ -3,7 +3,7 @@ use std::{cell::RefCell, num::NonZeroUsize};
|
||||
use lru::LruCache;
|
||||
use pumpkin_data::chunk::Biome;
|
||||
use pumpkin_util::{
|
||||
math::{lerp2, vector2::Vector2, vector3::Vector3, vertical_surface_type::VerticalSurfaceType},
|
||||
math::{lerp2, vertical_surface_type::VerticalSurfaceType},
|
||||
random::{RandomDeriver, RandomDeriverImpl, RandomImpl},
|
||||
};
|
||||
use serde::Deserialize;
|
||||
@@ -33,7 +33,9 @@ pub struct MaterialRuleContext<'a> {
|
||||
pub height: u16,
|
||||
pub random_deriver: &'a RandomDeriver,
|
||||
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 run_depth: i32,
|
||||
pub secondary_depth: f64,
|
||||
@@ -77,7 +79,9 @@ impl<'a> MaterialRuleContext<'a> {
|
||||
random_deriver,
|
||||
terrain_builder,
|
||||
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,
|
||||
run_depth: 0,
|
||||
secondary_depth: 0.0,
|
||||
@@ -93,20 +97,20 @@ impl<'a> MaterialRuleContext<'a> {
|
||||
fn sample_run_depth(&self) -> i32 {
|
||||
let 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
|
||||
+ 3.0
|
||||
+ self
|
||||
.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()
|
||||
* 0.25) as i32
|
||||
}
|
||||
|
||||
pub fn init_horizontal(&mut self, x: i32, z: i32) {
|
||||
self.unique_horizontal_pos_value += 1;
|
||||
self.block_pos.x = x;
|
||||
self.block_pos.z = z;
|
||||
self.block_pos_x = x;
|
||||
self.block_pos_z = z;
|
||||
self.run_depth = self.sample_run_depth();
|
||||
}
|
||||
|
||||
@@ -117,7 +121,7 @@ impl<'a> MaterialRuleContext<'a> {
|
||||
y: i32,
|
||||
fluid_height: i32,
|
||||
) {
|
||||
self.block_pos.y = y;
|
||||
self.block_pos_y = y;
|
||||
self.fluid_height = fluid_height;
|
||||
self.stone_depth_below = stone_depth_below;
|
||||
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.secondary_depth =
|
||||
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
|
||||
}
|
||||
@@ -178,23 +182,23 @@ impl MaterialCondition {
|
||||
MaterialCondition::YAbove(above_y) => above_y.test(context),
|
||||
MaterialCondition::Water(water) => water.test(context),
|
||||
MaterialCondition::Temperature => {
|
||||
let temperature = context
|
||||
.biome
|
||||
.weather
|
||||
.compute_temperature(&context.block_pos, context.sea_level);
|
||||
let temperature = context.biome.weather.compute_temperature(
|
||||
context.block_pos_x as f64,
|
||||
context.block_pos_y,
|
||||
context.block_pos_z as f64,
|
||||
context.sea_level,
|
||||
);
|
||||
temperature < 0.15f32
|
||||
}
|
||||
MaterialCondition::Steep => {
|
||||
let local_x = context.block_pos.x & 15;
|
||||
let local_z = context.block_pos.z & 15;
|
||||
let local_x = context.block_pos_x & 15;
|
||||
let local_z = context.block_pos_z & 15;
|
||||
|
||||
let local_z_sub = 0.max(local_z - 1);
|
||||
let local_z_add = 15.min(local_z + 1);
|
||||
|
||||
let sub_height =
|
||||
chunk.top_block_height_exclusive(&Vector2::new(local_x, local_z_sub));
|
||||
let add_height =
|
||||
chunk.top_block_height_exclusive(&Vector2::new(local_x, local_z_add));
|
||||
let sub_height = chunk.top_block_height_exclusive(local_x, local_z_sub);
|
||||
let add_height = chunk.top_block_height_exclusive(local_x, local_z_add);
|
||||
|
||||
if add_height >= sub_height + 4 {
|
||||
true
|
||||
@@ -202,10 +206,8 @@ impl MaterialCondition {
|
||||
let local_x_sub = 0.max(local_x - 1);
|
||||
let local_x_add = 15.min(local_x + 1);
|
||||
|
||||
let sub_height =
|
||||
chunk.top_block_height_exclusive(&Vector2::new(local_x_sub, local_z));
|
||||
let add_height =
|
||||
chunk.top_block_height_exclusive(&Vector2::new(local_x_add, local_z));
|
||||
let sub_height = chunk.top_block_height_exclusive(local_x_sub, local_z);
|
||||
let add_height = chunk.top_block_height_exclusive(local_x_add, local_z);
|
||||
|
||||
sub_height >= add_height + 4
|
||||
}
|
||||
@@ -240,13 +242,13 @@ pub struct AboveYMaterialCondition {
|
||||
|
||||
impl AboveYMaterialCondition {
|
||||
pub fn test(&self, context: &MaterialRuleContext) -> bool {
|
||||
context.block_pos.y
|
||||
context.block_pos_y
|
||||
+ if self.add_stone_depth {
|
||||
context.stone_depth_above
|
||||
} else {
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -279,7 +281,7 @@ impl SurfaceMaterialCondition {
|
||||
surface_height_estimate_sampler: &mut SurfaceHeightEstimateSampler,
|
||||
) -> bool {
|
||||
// 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 {
|
||||
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;
|
||||
let x = section_coords::block_to_section(context.block_pos.x);
|
||||
let z = section_coords::block_to_section(context.block_pos.z);
|
||||
let packed = chunk_pos::packed(&Vector2::new(x, z)) as i64;
|
||||
let x = section_coords::block_to_section(context.block_pos_x);
|
||||
let z = section_coords::block_to_section(context.block_pos_z);
|
||||
let packed = chunk_pos::packed(x as u64, z as u64) as i64;
|
||||
if context.packed_chunk_pos != packed {
|
||||
context.packed_chunk_pos = packed;
|
||||
context.estimated_surface_heights[0] = surface_height_estimate_sampler.estimate_height(
|
||||
@@ -312,8 +314,8 @@ pub fn estimate_surface_height(
|
||||
);
|
||||
}
|
||||
let surface = lerp2(
|
||||
((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_x & 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[1] as f64,
|
||||
context.estimated_surface_heights[2] as f64,
|
||||
@@ -349,7 +351,7 @@ impl NoiseThresholdMaterialCondition {
|
||||
let sampler = context
|
||||
.noise_builder
|
||||
.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
|
||||
}
|
||||
}
|
||||
@@ -398,7 +400,7 @@ pub struct WaterMaterialCondition {
|
||||
impl WaterMaterialCondition {
|
||||
pub fn test(&self, context: &MaterialRuleContext) -> bool {
|
||||
context.fluid_height == i32::MIN
|
||||
|| context.block_pos.y
|
||||
|| context.block_pos_y
|
||||
+ (if self.add_stone_depth {
|
||||
context.stone_depth_above
|
||||
} else {
|
||||
@@ -421,8 +423,12 @@ pub struct VerticalGradientMaterialCondition {
|
||||
|
||||
impl VerticalGradientMaterialCondition {
|
||||
pub fn test(&self, context: &MaterialRuleContext) -> bool {
|
||||
let true_at = self.true_at_and_below.get_y(context.min_y, context.height);
|
||||
let false_at = self.false_at_and_above.get_y(context.min_y, context.height);
|
||||
let true_at = self
|
||||
.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 key = context_pointer.addr();
|
||||
@@ -443,16 +449,16 @@ impl VerticalGradientMaterialCondition {
|
||||
.next_splitter()
|
||||
});
|
||||
|
||||
let block_y = context.block_pos.y;
|
||||
if block_y <= true_at as i32 {
|
||||
let block_y = context.block_pos_y;
|
||||
if block_y <= true_at {
|
||||
return true;
|
||||
}
|
||||
if block_y >= false_at as i32 {
|
||||
if block_y >= false_at {
|
||||
return false;
|
||||
}
|
||||
let mapped =
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ pub enum MaterialRule {
|
||||
#[serde(rename = "minecraft:sequence")]
|
||||
Sequence(SequenceMaterialRule),
|
||||
#[serde(rename = "minecraft:condition")]
|
||||
Condition(Box<ConditionMaterialRule>),
|
||||
Condition(ConditionMaterialRule),
|
||||
}
|
||||
|
||||
impl MaterialRule {
|
||||
@@ -45,11 +45,11 @@ pub struct BadLandsMaterialRule;
|
||||
|
||||
impl BadLandsMaterialRule {
|
||||
pub fn try_apply(&self, context: &mut MaterialRuleContext) -> Option<&'static BlockState> {
|
||||
Some(
|
||||
context
|
||||
.terrain_builder
|
||||
.get_terracotta_block(&context.block_pos),
|
||||
)
|
||||
Some(context.terrain_builder.get_terracotta_block(
|
||||
context.block_pos_x,
|
||||
context.block_pos_y,
|
||||
context.block_pos_z,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -27,10 +27,7 @@ pub struct SurfaceTerrainBuilder {
|
||||
}
|
||||
|
||||
impl SurfaceTerrainBuilder {
|
||||
pub fn new(
|
||||
noise_builder: &mut DoublePerlinNoiseBuilder,
|
||||
random_deriver: &RandomDeriver,
|
||||
) -> Self {
|
||||
pub fn new(noise_builder: &DoublePerlinNoiseBuilder, random_deriver: &RandomDeriver) -> Self {
|
||||
Self {
|
||||
terracotta_bands: Self::create_terracotta_bands(
|
||||
random_deriver.split_string("minecraft:clay_bands"),
|
||||
@@ -217,8 +214,9 @@ impl SurfaceTerrainBuilder {
|
||||
let mut block_threshold = scaled_threshold.min(scaled_roof_noise);
|
||||
|
||||
// TODO: Cache this
|
||||
let pos = Vector3::new(x, sea_level, z);
|
||||
let temperature = biome.weather.compute_temperature(&pos, sea_level);
|
||||
let temperature = biome
|
||||
.weather
|
||||
.compute_temperature(x as f64, sea_level, z as f64, sea_level);
|
||||
if temperature > 0.1f32 {
|
||||
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
|
||||
.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)
|
||||
.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.len() as u64) as usize]
|
||||
.to_state()
|
||||
|
||||
@@ -9,13 +9,13 @@ pub enum 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 {
|
||||
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) => {
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -237,7 +237,8 @@ impl Level {
|
||||
// );
|
||||
|
||||
let chunk = ChunkEntityData {
|
||||
chunk_position: pos,
|
||||
x: pos.x,
|
||||
z: pos.y,
|
||||
data: HashMap::new(),
|
||||
dirty: true,
|
||||
};
|
||||
@@ -508,8 +509,8 @@ impl Level {
|
||||
|
||||
let chunk = chunk.downgrade();
|
||||
|
||||
let chunk_x_base = chunk.position.x * 16;
|
||||
let chunk_z_base = chunk.position.y * 16;
|
||||
let chunk_x_base = chunk.x * 16;
|
||||
let chunk_z_base = chunk.z * 16;
|
||||
|
||||
let mut section_blocks = Vec::new();
|
||||
for i in 0..chunk.section.sections.len() {
|
||||
@@ -669,7 +670,9 @@ impl Level {
|
||||
while let Some(data) = rx.recv().await {
|
||||
match data {
|
||||
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());
|
||||
let _ = sender.send((chunk, false));
|
||||
}
|
||||
|
||||
@@ -67,23 +67,18 @@ pub fn bench_create_and_populate_noise(
|
||||
};
|
||||
|
||||
let biome_mixer_seed = hash_seed(random_config.seed);
|
||||
let mut chunk = ProtoChunk::new(
|
||||
Vector2::new(0, 0),
|
||||
settings,
|
||||
default_block,
|
||||
biome_mixer_seed,
|
||||
);
|
||||
let mut chunk = ProtoChunk::new(0, 0, settings, default_block, biome_mixer_seed);
|
||||
|
||||
// Create noise sampler and other required components
|
||||
let generation_shape = &settings.shape;
|
||||
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(-54, &pumpkin_data::Block::LAVA),
|
||||
)));
|
||||
));
|
||||
|
||||
let start_x = chunk_pos::start_block_x(&Vector2::new(0, 0));
|
||||
let start_z = chunk_pos::start_block_z(&Vector2::new(0, 0));
|
||||
let start_x = chunk_pos::start_block_x(0);
|
||||
let start_z = chunk_pos::start_block_z(0);
|
||||
|
||||
let mut noise_sampler = ChunkNoiseGenerator::new(
|
||||
&base_router.noise,
|
||||
@@ -133,18 +128,13 @@ pub fn bench_create_and_populate_biome(
|
||||
use crate::generation::{biome_coords, positions::chunk_pos};
|
||||
|
||||
let biome_mixer_seed = hash_seed(random_config.seed);
|
||||
let mut chunk = ProtoChunk::new(
|
||||
Vector2::new(0, 0),
|
||||
settings,
|
||||
default_block,
|
||||
biome_mixer_seed,
|
||||
);
|
||||
let mut chunk = ProtoChunk::new(0, 0, settings, default_block, biome_mixer_seed);
|
||||
|
||||
// Create multi-noise sampler
|
||||
let generation_shape = &settings.shape;
|
||||
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_z = chunk_pos::start_block_z(&Vector2::new(0, 0));
|
||||
let start_x = chunk_pos::start_block_x(0);
|
||||
let start_z = chunk_pos::start_block_z(0);
|
||||
let biome_pos = Vector2::new(
|
||||
biome_coords::from_block(start_x),
|
||||
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 mut chunk = ProtoChunk::new(
|
||||
Vector2::new(0, 0),
|
||||
settings,
|
||||
default_block,
|
||||
biome_mixer_seed,
|
||||
);
|
||||
let mut chunk = ProtoChunk::new(0, 0, settings, default_block, biome_mixer_seed);
|
||||
|
||||
// Create all required components
|
||||
let generation_shape = &settings.shape;
|
||||
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_z = chunk_pos::start_block_z(&Vector2::new(0, 0));
|
||||
let start_x = chunk_pos::start_block_x(0);
|
||||
let start_z = chunk_pos::start_block_z(0);
|
||||
|
||||
// Multi-noise sampler for biomes
|
||||
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);
|
||||
|
||||
// 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(-54, &pumpkin_data::Block::LAVA),
|
||||
)));
|
||||
));
|
||||
|
||||
let mut noise_sampler = ChunkNoiseGenerator::new(
|
||||
&base_router.noise,
|
||||
|
||||
@@ -376,12 +376,12 @@ pub async fn calc_block_breaking(
|
||||
return 0.0;
|
||||
}
|
||||
let i = if player.can_harvest(state, block).await {
|
||||
30
|
||||
30.0
|
||||
} else {
|
||||
100
|
||||
100.0
|
||||
};
|
||||
|
||||
player.get_mining_speed(block).await / hardness / i as f32
|
||||
player.get_mining_speed(block).await / hardness / i
|
||||
}
|
||||
|
||||
#[derive(PartialEq)]
|
||||
|
||||
@@ -55,18 +55,14 @@ impl<'a> FindArg<'a> for BlockArgumentConsumer {
|
||||
Some(Arg::Block(name)) => Block::from_name(name).map_or_else(
|
||||
|| {
|
||||
if name.starts_with("minecraft:") {
|
||||
Err(CommandError::CommandFailed(Box::new(
|
||||
TextComponent::translate(
|
||||
"argument.block.id.invalid",
|
||||
[TextComponent::text((*name).to_string())],
|
||||
),
|
||||
Err(CommandError::CommandFailed(TextComponent::translate(
|
||||
"argument.block.id.invalid",
|
||||
[TextComponent::text((*name).to_string())],
|
||||
)))
|
||||
} else {
|
||||
Err(CommandError::CommandFailed(Box::new(
|
||||
TextComponent::translate(
|
||||
"argument.block.id.invalid",
|
||||
[TextComponent::text("minecraft:".to_string() + *name)],
|
||||
),
|
||||
Err(CommandError::CommandFailed(TextComponent::translate(
|
||||
"argument.block.id.invalid",
|
||||
[TextComponent::text("minecraft:".to_string() + *name)],
|
||||
)))
|
||||
}
|
||||
},
|
||||
@@ -125,18 +121,14 @@ impl<'a> FindArg<'a> for BlockPredicateArgumentConsumer {
|
||||
Block::from_name(name).map_or_else(
|
||||
|| {
|
||||
if name.starts_with("minecraft:") {
|
||||
Err(CommandError::CommandFailed(Box::new(
|
||||
TextComponent::translate(
|
||||
"argument.block.id.invalid",
|
||||
[TextComponent::text((*name).to_string())],
|
||||
),
|
||||
Err(CommandError::CommandFailed(TextComponent::translate(
|
||||
"argument.block.id.invalid",
|
||||
[TextComponent::text((*name).to_string())],
|
||||
)))
|
||||
} else {
|
||||
Err(CommandError::CommandFailed(Box::new(
|
||||
TextComponent::translate(
|
||||
"argument.block.id.invalid",
|
||||
[TextComponent::text("minecraft:".to_string() + *name)],
|
||||
),
|
||||
Err(CommandError::CommandFailed(TextComponent::translate(
|
||||
"argument.block.id.invalid",
|
||||
[TextComponent::text("minecraft:".to_string() + *name)],
|
||||
)))
|
||||
}
|
||||
},
|
||||
@@ -146,11 +138,9 @@ impl<'a> FindArg<'a> for BlockPredicateArgumentConsumer {
|
||||
|tag| {
|
||||
get_tag_ids(RegistryKey::Block, tag).map_or_else(
|
||||
|| {
|
||||
Err(CommandError::CommandFailed(Box::new(
|
||||
TextComponent::translate(
|
||||
"arguments.block.tag.unknown",
|
||||
[TextComponent::text((*tag).to_string())],
|
||||
),
|
||||
Err(CommandError::CommandFailed(TextComponent::translate(
|
||||
"arguments.block.tag.unknown",
|
||||
[TextComponent::text((*tag).to_string())],
|
||||
)))
|
||||
},
|
||||
|blocks| Ok(Some(BlockPredicate::Tag(blocks.to_vec()))),
|
||||
|
||||
@@ -90,22 +90,18 @@ pub enum NotInBounds {
|
||||
impl From<NotInBounds> for CommandError {
|
||||
fn from(value: NotInBounds) -> Self {
|
||||
match value {
|
||||
NotInBounds::LowerBound(val, min) => {
|
||||
Self::CommandFailed(Box::new(TextComponent::text(format!(
|
||||
"{} must not be less than {}, found {}",
|
||||
val.qualifier(),
|
||||
min,
|
||||
val
|
||||
))))
|
||||
}
|
||||
NotInBounds::UpperBound(val, max) => {
|
||||
Self::CommandFailed(Box::new(TextComponent::text(format!(
|
||||
"{} must not be more than {}, found {}",
|
||||
val.qualifier(),
|
||||
max,
|
||||
val
|
||||
))))
|
||||
}
|
||||
NotInBounds::LowerBound(val, min) => Self::CommandFailed(TextComponent::text(format!(
|
||||
"{} must not be less than {}, found {}",
|
||||
val.qualifier(),
|
||||
min,
|
||||
val
|
||||
))),
|
||||
NotInBounds::UpperBound(val, max) => Self::CommandFailed(TextComponent::text(format!(
|
||||
"{} must not be more than {}, found {}",
|
||||
val.qualifier(),
|
||||
max,
|
||||
val
|
||||
))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,18 +56,14 @@ impl<'a> FindArg<'a> for ItemArgumentConsumer {
|
||||
.map_or_else(
|
||||
|| {
|
||||
if name.starts_with("minecraft:") {
|
||||
Err(CommandError::CommandFailed(Box::new(
|
||||
TextComponent::translate(
|
||||
"argument.item.id.invalid",
|
||||
[TextComponent::text((*name).to_string())],
|
||||
),
|
||||
Err(CommandError::CommandFailed(TextComponent::translate(
|
||||
"argument.item.id.invalid",
|
||||
[TextComponent::text((*name).to_string())],
|
||||
)))
|
||||
} else {
|
||||
Err(CommandError::CommandFailed(Box::new(
|
||||
TextComponent::translate(
|
||||
"argument.item.id.invalid",
|
||||
[TextComponent::text("minecraft:".to_string() + *name)],
|
||||
),
|
||||
Err(CommandError::CommandFailed(TextComponent::translate(
|
||||
"argument.item.id.invalid",
|
||||
[TextComponent::text("minecraft:".to_string() + *name)],
|
||||
)))
|
||||
}
|
||||
},
|
||||
|
||||
@@ -54,8 +54,8 @@ impl<'a> FindArg<'a> for SoundArgumentConsumer {
|
||||
Some(Arg::Block(name)) => {
|
||||
Sound::from_name(name.strip_prefix("minecraft:").unwrap_or(name)).map_or_else(
|
||||
|| {
|
||||
Err(CommandError::CommandFailed(Box::new(TextComponent::text(
|
||||
format!("Sound {name} does not exist."),
|
||||
Err(CommandError::CommandFailed(TextComponent::text(format!(
|
||||
"Sound {name} does not exist."
|
||||
))))
|
||||
},
|
||||
Result::Ok,
|
||||
|
||||
@@ -54,9 +54,9 @@ impl<'a> FindArg<'a> for SummonableEntitiesArgumentConsumer {
|
||||
Some(Arg::Block(name)) => {
|
||||
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",
|
||||
))))
|
||||
)))
|
||||
},
|
||||
Result::Ok,
|
||||
)
|
||||
|
||||
@@ -62,9 +62,9 @@ impl CommandExecutor for ListExecutor {
|
||||
handle_banlist(entries, sender).await;
|
||||
}
|
||||
_ => {
|
||||
return Err(CommandError::CommandFailed(Box::new(TextComponent::text(
|
||||
"Incorrect argument for command".to_string(),
|
||||
))));
|
||||
return Err(CommandError::CommandFailed(TextComponent::text(
|
||||
"Incorrect argument for command",
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -225,7 +225,7 @@ async fn display_data(
|
||||
let mut nbt = NbtCompound::new();
|
||||
storage.write_nbt(&mut nbt).await;
|
||||
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(
|
||||
"commands.data.entity.query",
|
||||
[target_name, display],
|
||||
|
||||
@@ -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()),
|
||||
],
|
||||
);
|
||||
return Err(CommandError::CommandFailed(Box::new(msg)));
|
||||
return Err(CommandError::CommandFailed(msg));
|
||||
}
|
||||
|
||||
let only_one = targets.len() == 1;
|
||||
@@ -88,7 +88,7 @@ impl CommandExecutor for Executor {
|
||||
"commands.enchant.failed.itemless",
|
||||
[targets[0].get_display_name().await],
|
||||
);
|
||||
return Err(CommandError::CommandFailed(Box::new(msg)));
|
||||
return Err(CommandError::CommandFailed(msg));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@@ -98,7 +98,7 @@ impl CommandExecutor for Executor {
|
||||
"commands.enchant.failed.incompatible",
|
||||
[item.item.translated_name()],
|
||||
);
|
||||
return Err(CommandError::CommandFailed(Box::new(msg)));
|
||||
return Err(CommandError::CommandFailed(msg));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@@ -111,7 +111,7 @@ impl CommandExecutor for Executor {
|
||||
"commands.enchant.failed.incompatible",
|
||||
[item.item.translated_name()],
|
||||
);
|
||||
return Err(CommandError::CommandFailed(Box::new(msg)));
|
||||
return Err(CommandError::CommandFailed(msg));
|
||||
}
|
||||
} else {
|
||||
item.enchant(enchantment, level);
|
||||
@@ -120,7 +120,7 @@ impl CommandExecutor for Executor {
|
||||
}
|
||||
if success == 0 {
|
||||
let msg = TextComponent::translate("commands.enchant.failed", []);
|
||||
return Err(CommandError::CommandFailed(Box::new(msg)));
|
||||
return Err(CommandError::CommandFailed(msg));
|
||||
}
|
||||
if only_one {
|
||||
let msg = TextComponent::translate(
|
||||
|
||||
@@ -27,9 +27,9 @@ impl CommandExecutor for Executor {
|
||||
_ => match server.worlds.read().await.first() {
|
||||
Some(world) => world.level.seed.0,
|
||||
None => {
|
||||
return Err(CommandError::CommandFailed(Box::new(TextComponent::text(
|
||||
return Err(CommandError::CommandFailed(TextComponent::text(
|
||||
"Unable to get Seed",
|
||||
))));
|
||||
)));
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
@@ -102,9 +102,9 @@ async fn setworldspawn(
|
||||
yaw: f32,
|
||||
) -> Result<(), CommandError> {
|
||||
let Some(world) = sender.world() else {
|
||||
return Err(CommandError::CommandFailed(Box::new(TextComponent::text(
|
||||
return Err(CommandError::CommandFailed(TextComponent::text(
|
||||
"Failed to get world.",
|
||||
))));
|
||||
)));
|
||||
};
|
||||
|
||||
match world.dimension_type {
|
||||
|
||||
@@ -66,8 +66,9 @@ impl CommandExecutor for EntitiesToEntityExecutor {
|
||||
let destination = EntityArgumentConsumer::find_arg(args, ARG_DESTINATION)?;
|
||||
let pos = destination.get_entity().pos.load();
|
||||
if !World::is_valid(pos) {
|
||||
return Err(CommandError::CommandFailed(Box::new(
|
||||
TextComponent::translate("argument.pos.outofbounds", []),
|
||||
return Err(CommandError::CommandFailed(TextComponent::translate(
|
||||
"argument.pos.outofbounds",
|
||||
[],
|
||||
)));
|
||||
}
|
||||
for target in targets {
|
||||
@@ -100,8 +101,9 @@ impl CommandExecutor for EntitiesToPosFacingPosExecutor {
|
||||
|
||||
let pos = Position3DArgumentConsumer::find_arg(args, ARG_LOCATION)?;
|
||||
if !World::is_valid(pos) {
|
||||
return Err(CommandError::CommandFailed(Box::new(
|
||||
TextComponent::translate("argument.pos.outofbounds", []),
|
||||
return Err(CommandError::CommandFailed(TextComponent::translate(
|
||||
"argument.pos.outofbounds",
|
||||
[],
|
||||
)));
|
||||
}
|
||||
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)?;
|
||||
if !World::is_valid(pos) {
|
||||
return Err(CommandError::CommandFailed(Box::new(
|
||||
TextComponent::translate("argument.pos.outofbounds", []),
|
||||
return Err(CommandError::CommandFailed(TextComponent::translate(
|
||||
"argument.pos.outofbounds",
|
||||
[],
|
||||
)));
|
||||
}
|
||||
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)?;
|
||||
if !World::is_valid(pos) {
|
||||
return Err(CommandError::CommandFailed(Box::new(
|
||||
TextComponent::translate("argument.pos.outofbounds", []),
|
||||
return Err(CommandError::CommandFailed(TextComponent::translate(
|
||||
"argument.pos.outofbounds",
|
||||
[],
|
||||
)));
|
||||
}
|
||||
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)?;
|
||||
if !World::is_valid(pos) {
|
||||
return Err(CommandError::CommandFailed(Box::new(
|
||||
TextComponent::translate("argument.pos.outofbounds", []),
|
||||
return Err(CommandError::CommandFailed(TextComponent::translate(
|
||||
"argument.pos.outofbounds",
|
||||
[],
|
||||
)));
|
||||
}
|
||||
// todo command context
|
||||
@@ -257,8 +262,9 @@ impl CommandExecutor for SelfToEntityExecutor {
|
||||
let yaw = player.living_entity.entity.yaw.load();
|
||||
let pitch = player.living_entity.entity.pitch.load();
|
||||
if !World::is_valid(pos) {
|
||||
return Err(CommandError::CommandFailed(Box::new(
|
||||
TextComponent::translate("argument.pos.outofbounds", []),
|
||||
return Err(CommandError::CommandFailed(TextComponent::translate(
|
||||
"argument.pos.outofbounds",
|
||||
[],
|
||||
)));
|
||||
}
|
||||
player
|
||||
@@ -293,8 +299,9 @@ impl CommandExecutor for SelfToPosExecutor {
|
||||
let yaw = player.living_entity.entity.yaw.load();
|
||||
let pitch = player.living_entity.entity.pitch.load();
|
||||
if !World::is_valid(pos) {
|
||||
return Err(CommandError::CommandFailed(Box::new(
|
||||
TextComponent::translate("argument.pos.outofbounds", []),
|
||||
return Err(CommandError::CommandFailed(TextComponent::translate(
|
||||
"argument.pos.outofbounds",
|
||||
[],
|
||||
)));
|
||||
}
|
||||
player
|
||||
|
||||
@@ -24,7 +24,7 @@ pub enum CommandError {
|
||||
PermissionDenied,
|
||||
/// A general error occurred during command execution that doesn't fit into
|
||||
/// more specific `CommandError` variants.
|
||||
CommandFailed(Box<TextComponent>),
|
||||
CommandFailed(TextComponent),
|
||||
}
|
||||
|
||||
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.",
|
||||
)
|
||||
}
|
||||
CommandFailed(s) => *s,
|
||||
CommandFailed(s) => s,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -138,9 +138,7 @@ impl CommandDispatcher {
|
||||
|
||||
pub(crate) fn split_parts(cmd: &str) -> Result<(&str, Vec<&str>), CommandError> {
|
||||
if cmd.is_empty() {
|
||||
return Err(CommandFailed(Box::new(TextComponent::text(
|
||||
"Empty Command",
|
||||
))));
|
||||
return Err(CommandFailed(TextComponent::text("Empty Command")));
|
||||
}
|
||||
let mut args = Vec::new();
|
||||
let mut current_arg_start = 0usize;
|
||||
@@ -167,9 +165,7 @@ impl CommandDispatcher {
|
||||
'}' => {
|
||||
if !in_single_quotes && !in_double_quotes {
|
||||
if in_braces == 0 {
|
||||
return Err(CommandFailed(Box::new(TextComponent::text(
|
||||
"Unmatched braces",
|
||||
))));
|
||||
return Err(CommandFailed(TextComponent::text("Unmatched braces")));
|
||||
}
|
||||
in_braces -= 1;
|
||||
}
|
||||
@@ -182,9 +178,7 @@ impl CommandDispatcher {
|
||||
']' => {
|
||||
if !in_single_quotes && !in_double_quotes {
|
||||
if in_brackets == 0 {
|
||||
return Err(CommandFailed(Box::new(TextComponent::text(
|
||||
"Unmatched brackets",
|
||||
))));
|
||||
return Err(CommandFailed(TextComponent::text("Unmatched brackets")));
|
||||
}
|
||||
in_brackets -= 1;
|
||||
}
|
||||
@@ -216,24 +210,22 @@ impl CommandDispatcher {
|
||||
args.push(&cmd[current_arg_start..]);
|
||||
}
|
||||
if in_single_quotes || in_double_quotes {
|
||||
return Err(CommandFailed(Box::new(TextComponent::text(
|
||||
return Err(CommandFailed(TextComponent::text(
|
||||
"Unmatched quotes at the end",
|
||||
))));
|
||||
)));
|
||||
}
|
||||
if in_braces != 0 {
|
||||
return Err(CommandFailed(Box::new(TextComponent::text(
|
||||
return Err(CommandFailed(TextComponent::text(
|
||||
"Unmatched braces at the end",
|
||||
))));
|
||||
)));
|
||||
}
|
||||
if in_brackets != 0 {
|
||||
return Err(CommandFailed(Box::new(TextComponent::text(
|
||||
return Err(CommandFailed(TextComponent::text(
|
||||
"Unmatched brackets at the end",
|
||||
))));
|
||||
)));
|
||||
}
|
||||
if args.is_empty() {
|
||||
return Err(CommandFailed(Box::new(TextComponent::text(
|
||||
"Empty Command",
|
||||
))));
|
||||
return Err(CommandFailed(TextComponent::text("Empty Command")));
|
||||
}
|
||||
let key = args.remove(0);
|
||||
Ok((key, args.into_iter().rev().collect()))
|
||||
@@ -249,15 +241,15 @@ impl CommandDispatcher {
|
||||
let (key, raw_args) = Self::split_parts(cmd)?;
|
||||
|
||||
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"
|
||||
)))));
|
||||
))));
|
||||
}
|
||||
|
||||
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(),
|
||||
))));
|
||||
)));
|
||||
};
|
||||
|
||||
if !src.has_permission(permission.as_str()).await {
|
||||
@@ -272,18 +264,16 @@ impl CommandDispatcher {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
Err(CommandFailed(Box::new(TextComponent::text(format!(
|
||||
Err(CommandFailed(TextComponent::text(format!(
|
||||
"Invalid Syntax. Usage: {tree}"
|
||||
)))))
|
||||
))))
|
||||
}
|
||||
|
||||
pub fn get_tree<'a>(&'a self, key: &str) -> Result<&'a CommandTree, CommandError> {
|
||||
let command =
|
||||
self.commands
|
||||
.get(key)
|
||||
.ok_or(CommandFailed(Box::new(TextComponent::text(
|
||||
"Command not found",
|
||||
))))?;
|
||||
let command = self
|
||||
.commands
|
||||
.get(key)
|
||||
.ok_or(CommandFailed(TextComponent::text("Command not found")))?;
|
||||
|
||||
match command {
|
||||
Command::Tree(tree) => Ok(tree),
|
||||
@@ -292,9 +282,9 @@ impl CommandDispatcher {
|
||||
log::error!(
|
||||
"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)",
|
||||
))));
|
||||
)));
|
||||
};
|
||||
Ok(tree)
|
||||
}
|
||||
|
||||
@@ -1935,7 +1935,9 @@ impl World {
|
||||
let Some((chunk, _first_load)) = recv_result else {
|
||||
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) {
|
||||
chunk
|
||||
|
||||
@@ -373,10 +373,6 @@ pub async fn spawn_category_for_position(
|
||||
new_pos = BlockPos::new(new_x, new_pos.0.y, new_z);
|
||||
let new_pos_center = new_pos.to_centered_f64();
|
||||
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(
|
||||
&new_pos,
|
||||
player_distance,
|
||||
|
||||
Reference in New Issue
Block a user