chore: move chunk gen settings from runtime to compile time parsing
Bin size decreased, Startup time decreased by a lot in debug, lower memory usage
This commit is contained in:
parent
2f29fcef8d
commit
835262a85a
@ -27,6 +27,9 @@ separated_literal_suffix = "deny"
|
|||||||
semicolon_outside_block = "deny"
|
semicolon_outside_block = "deny"
|
||||||
redundant_test_prefix = "deny"
|
redundant_test_prefix = "deny"
|
||||||
non_zero_suggestions = "deny"
|
non_zero_suggestions = "deny"
|
||||||
|
dbg_macro = "deny"
|
||||||
|
rc_buffer = "deny"
|
||||||
|
verbose_file_reads = "deny"
|
||||||
string_lit_chars_any = "deny"
|
string_lit_chars_any = "deny"
|
||||||
use_self = "deny"
|
use_self = "deny"
|
||||||
useless_let_if_seq = "deny"
|
useless_let_if_seq = "deny"
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -30,12 +30,12 @@ pub(crate) fn build() -> TokenStream {
|
|||||||
let id_lit = LitInt::new(&raw_value.id.to_string(), Span::call_site());
|
let id_lit = LitInt::new(&raw_value.id.to_string(), Span::call_site());
|
||||||
let default_value_lit = raw_value.default_value;
|
let default_value_lit = raw_value.default_value;
|
||||||
|
|
||||||
constant_defs.push(quote! {
|
constant_defs.push(quote!(
|
||||||
pub const #constant_ident: Self = Self {
|
pub const #constant_ident: Self = Self {
|
||||||
id: #id_lit,
|
id: #id_lit,
|
||||||
default_value: #default_value_lit,
|
default_value: #default_value_lit,
|
||||||
};
|
};
|
||||||
});
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
|
|||||||
@ -13,6 +13,7 @@ mod attributes;
|
|||||||
mod biome;
|
mod biome;
|
||||||
mod bitsets;
|
mod bitsets;
|
||||||
mod block;
|
mod block;
|
||||||
|
mod chunk_gen_settings;
|
||||||
mod chunk_status;
|
mod chunk_status;
|
||||||
mod composter_increase_chance;
|
mod composter_increase_chance;
|
||||||
mod damage_type;
|
mod damage_type;
|
||||||
@ -54,9 +55,7 @@ mod world_event;
|
|||||||
pub const OUT_DIR: &str = "src/generated";
|
pub const OUT_DIR: &str = "src/generated";
|
||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
if let Err(e) = fs::create_dir_all(OUT_DIR) {
|
fs::create_dir_all(OUT_DIR).expect("Failed to create output directory");
|
||||||
eprintln!("Failed to create output directory {OUT_DIR}: {e}");
|
|
||||||
}
|
|
||||||
|
|
||||||
type BuilderFn = fn() -> TokenStream;
|
type BuilderFn = fn() -> TokenStream;
|
||||||
|
|
||||||
@ -85,6 +84,7 @@ pub fn main() {
|
|||||||
(spawn_egg::build, "spawn_egg.rs"),
|
(spawn_egg::build, "spawn_egg.rs"),
|
||||||
(block::build, "block.rs"),
|
(block::build, "block.rs"),
|
||||||
(item::build, "item.rs"),
|
(item::build, "item.rs"),
|
||||||
|
(chunk_gen_settings::build, "chunk_gen_settings.rs"),
|
||||||
(fluid::build, "fluid.rs"),
|
(fluid::build, "fluid.rs"),
|
||||||
(entity_status::build, "entity_status.rs"),
|
(entity_status::build, "entity_status.rs"),
|
||||||
(tag::build, "tag.rs"),
|
(tag::build, "tag.rs"),
|
||||||
@ -110,8 +110,14 @@ pub fn main() {
|
|||||||
|
|
||||||
build_functions.par_iter().for_each(|(build_fn, file)| {
|
build_functions.par_iter().for_each(|(build_fn, file)| {
|
||||||
let raw_code = build_fn().to_string();
|
let raw_code = build_fn().to_string();
|
||||||
let final_code = format_code(&raw_code);
|
|
||||||
write_generated_file(&final_code.unwrap_or(raw_code), file);
|
let header = "/* This file is generated. Do not edit manually. */\n";
|
||||||
|
|
||||||
|
let final_code = format_code(&raw_code)
|
||||||
|
.map(|formatted| format!("{}{}", header, formatted))
|
||||||
|
.unwrap_or_else(|_| format!("{}{}", header, raw_code));
|
||||||
|
|
||||||
|
write_generated_file(&final_code, file);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
536
pumpkin-data/build/chunk_gen_settings.rs
Normal file
536
pumpkin-data/build/chunk_gen_settings.rs
Normal file
@ -0,0 +1,536 @@
|
|||||||
|
use proc_macro2::TokenStream;
|
||||||
|
use quote::{ToTokens, format_ident, quote};
|
||||||
|
use serde::Deserialize;
|
||||||
|
use std::{
|
||||||
|
collections::{BTreeMap, HashMap},
|
||||||
|
fs,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
pub struct BlockStateCodecStruct {
|
||||||
|
#[serde(rename = "Name")]
|
||||||
|
pub name: String,
|
||||||
|
#[serde(rename = "Properties")]
|
||||||
|
pub properties: Option<HashMap<String, String>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
pub struct GenerationSettingsStruct {
|
||||||
|
#[serde(default)]
|
||||||
|
pub aquifers_enabled: bool,
|
||||||
|
#[serde(default)]
|
||||||
|
pub ore_veins_enabled: bool,
|
||||||
|
#[serde(default)]
|
||||||
|
pub legacy_random_source: bool,
|
||||||
|
pub sea_level: i32,
|
||||||
|
pub default_fluid: BlockStateCodecStruct,
|
||||||
|
pub default_block: BlockStateCodecStruct,
|
||||||
|
#[serde(rename = "noise")]
|
||||||
|
pub shape: GenerationShapeConfigStruct,
|
||||||
|
pub surface_rule: MaterialRuleStruct,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
pub struct GenerationShapeConfigStruct {
|
||||||
|
pub min_y: i8,
|
||||||
|
pub height: u16,
|
||||||
|
pub size_horizontal: u8,
|
||||||
|
pub size_vertical: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(tag = "type")]
|
||||||
|
pub enum MaterialRuleStruct {
|
||||||
|
#[serde(rename = "minecraft:block")]
|
||||||
|
Block { result_state: BlockStateCodecStruct },
|
||||||
|
#[serde(rename = "minecraft:sequence")]
|
||||||
|
Sequence { sequence: Vec<MaterialRuleStruct> },
|
||||||
|
#[serde(rename = "minecraft:condition")]
|
||||||
|
Condition {
|
||||||
|
if_true: MaterialConditionStruct,
|
||||||
|
then_run: Box<MaterialRuleStruct>,
|
||||||
|
},
|
||||||
|
#[serde(rename = "minecraft:bandlands")]
|
||||||
|
Badlands,
|
||||||
|
#[serde(other)]
|
||||||
|
Unsupported,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(tag = "type")]
|
||||||
|
pub enum MaterialConditionStruct {
|
||||||
|
#[serde(rename = "minecraft:biome")]
|
||||||
|
Biome { biome_is: Vec<String> },
|
||||||
|
#[serde(rename = "minecraft:noise_threshold")]
|
||||||
|
NoiseThreshold {
|
||||||
|
noise: String,
|
||||||
|
min_threshold: f64,
|
||||||
|
max_threshold: f64,
|
||||||
|
},
|
||||||
|
#[serde(rename = "minecraft:vertical_gradient")]
|
||||||
|
VerticalGradient {
|
||||||
|
random_name: String,
|
||||||
|
true_at_and_below: YOffsetStruct,
|
||||||
|
false_at_and_above: YOffsetStruct,
|
||||||
|
},
|
||||||
|
#[serde(rename = "minecraft:y_above")]
|
||||||
|
YAbove {
|
||||||
|
anchor: YOffsetStruct,
|
||||||
|
surface_depth_multiplier: i32,
|
||||||
|
add_stone_depth: bool,
|
||||||
|
},
|
||||||
|
#[serde(rename = "minecraft:water")]
|
||||||
|
Water {
|
||||||
|
offset: i32,
|
||||||
|
surface_depth_multiplier: i32,
|
||||||
|
add_stone_depth: bool,
|
||||||
|
},
|
||||||
|
#[serde(rename = "minecraft:temperature")]
|
||||||
|
Temperature,
|
||||||
|
#[serde(rename = "minecraft:steep")]
|
||||||
|
Steep,
|
||||||
|
#[serde(rename = "minecraft:not")]
|
||||||
|
Not {
|
||||||
|
invert: Box<MaterialConditionStruct>,
|
||||||
|
},
|
||||||
|
#[serde(rename = "minecraft:hole")]
|
||||||
|
Hole,
|
||||||
|
#[serde(rename = "minecraft:above_preliminary_surface")]
|
||||||
|
AbovePreliminarySurface,
|
||||||
|
#[serde(rename = "minecraft:stone_depth")]
|
||||||
|
StoneDepth {
|
||||||
|
offset: i32,
|
||||||
|
add_surface_depth: bool,
|
||||||
|
secondary_depth_range: i32,
|
||||||
|
surface_type: String, // "ceiling" or "floor"
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
pub enum YOffsetStruct {
|
||||||
|
Absolute { absolute: i16 },
|
||||||
|
AboveBottom { above_bottom: i8 },
|
||||||
|
BelowTop { below_top: i8 },
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- ToTokens Implementations ---
|
||||||
|
|
||||||
|
impl ToTokens for BlockStateCodecStruct {
|
||||||
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||||
|
let name = &self.name.strip_prefix("minecraft:").unwrap_or(&self.name);
|
||||||
|
|
||||||
|
let props_gen = if let Some(props) = &self.properties {
|
||||||
|
let keys = props.keys();
|
||||||
|
let values = props.values();
|
||||||
|
quote!(Some(&[#((#keys, #values)),*]))
|
||||||
|
} else {
|
||||||
|
quote!(None)
|
||||||
|
};
|
||||||
|
|
||||||
|
tokens.extend(quote!(
|
||||||
|
BlockBlueprint {
|
||||||
|
name: #name,
|
||||||
|
properties: #props_gen,
|
||||||
|
}
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToTokens for GenerationSettingsStruct {
|
||||||
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||||
|
let aquifers = self.aquifers_enabled;
|
||||||
|
let ores = self.ore_veins_enabled;
|
||||||
|
let legacy = self.legacy_random_source;
|
||||||
|
let sea_level = self.sea_level;
|
||||||
|
let fluid = &self.default_fluid;
|
||||||
|
let block = &self.default_block;
|
||||||
|
let shape = &self.shape;
|
||||||
|
let rule = &self.surface_rule;
|
||||||
|
|
||||||
|
tokens.extend(quote!(
|
||||||
|
GenerationSettings {
|
||||||
|
aquifers_enabled: #aquifers,
|
||||||
|
ore_veins_enabled: #ores,
|
||||||
|
legacy_random_source: #legacy,
|
||||||
|
sea_level: #sea_level,
|
||||||
|
default_fluid: #fluid,
|
||||||
|
shape: #shape,
|
||||||
|
surface_rule: #rule,
|
||||||
|
default_block: #block,
|
||||||
|
}
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToTokens for GenerationShapeConfigStruct {
|
||||||
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||||
|
let min_y = self.min_y;
|
||||||
|
let height = self.height;
|
||||||
|
let hor = self.size_horizontal;
|
||||||
|
let ver = self.size_vertical;
|
||||||
|
tokens.extend(quote!(
|
||||||
|
GenerationShapeConfig { min_y: #min_y, height: #height, size_horizontal: #hor, size_vertical: #ver }
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToTokens for YOffsetStruct {
|
||||||
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||||
|
match self {
|
||||||
|
Self::Absolute { absolute } => {
|
||||||
|
tokens.extend(quote!(YOffset::Absolute(pumpkin_util::y_offset::Absolute { absolute: #absolute })));
|
||||||
|
}
|
||||||
|
Self::AboveBottom { above_bottom } => {
|
||||||
|
tokens.extend(quote!(YOffset::AboveBottom(pumpkin_util::y_offset::AboveBottom { above_bottom: #above_bottom })));
|
||||||
|
}
|
||||||
|
Self::BelowTop { below_top } => {
|
||||||
|
tokens.extend(quote!(YOffset::BelowTop(pumpkin_util::y_offset::BelowTop { below_top: #below_top })));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToTokens for MaterialConditionStruct {
|
||||||
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||||
|
match self {
|
||||||
|
Self::Biome { biome_is } => {
|
||||||
|
let biomes = biome_is
|
||||||
|
.iter()
|
||||||
|
.map(|b| b.strip_prefix("minecraft:").unwrap_or(b).to_uppercase());
|
||||||
|
let biome_refs: Vec<TokenStream> = biomes
|
||||||
|
.map(|b| {
|
||||||
|
let ident = format_ident!("{}", b);
|
||||||
|
quote!(&crate::biome::Biome::#ident)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
tokens.extend(quote!(
|
||||||
|
MaterialCondition::Biome(BiomeMaterialCondition {
|
||||||
|
biome_is: &[#(#biome_refs),*],
|
||||||
|
})
|
||||||
|
));
|
||||||
|
}
|
||||||
|
Self::NoiseThreshold {
|
||||||
|
noise,
|
||||||
|
min_threshold,
|
||||||
|
max_threshold,
|
||||||
|
} => {
|
||||||
|
tokens.extend(quote!(
|
||||||
|
MaterialCondition::NoiseThreshold(NoiseThresholdMaterialCondition {
|
||||||
|
noise: #noise,
|
||||||
|
min_threshold: #min_threshold,
|
||||||
|
max_threshold: #max_threshold,
|
||||||
|
})
|
||||||
|
));
|
||||||
|
}
|
||||||
|
Self::VerticalGradient {
|
||||||
|
random_name,
|
||||||
|
true_at_and_below,
|
||||||
|
false_at_and_above,
|
||||||
|
} => {
|
||||||
|
tokens.extend(quote!(
|
||||||
|
MaterialCondition::VerticalGradient(VerticalGradientMaterialCondition {
|
||||||
|
random_name: #random_name,
|
||||||
|
true_at_and_below: #true_at_and_below,
|
||||||
|
false_at_and_above: #false_at_and_above,
|
||||||
|
})
|
||||||
|
));
|
||||||
|
}
|
||||||
|
Self::YAbove {
|
||||||
|
anchor,
|
||||||
|
surface_depth_multiplier,
|
||||||
|
add_stone_depth,
|
||||||
|
} => {
|
||||||
|
tokens.extend(quote!(
|
||||||
|
MaterialCondition::YAbove(AboveYMaterialCondition {
|
||||||
|
anchor: #anchor,
|
||||||
|
surface_depth_multiplier: #surface_depth_multiplier,
|
||||||
|
add_stone_depth: #add_stone_depth,
|
||||||
|
})
|
||||||
|
));
|
||||||
|
}
|
||||||
|
Self::Water {
|
||||||
|
offset,
|
||||||
|
surface_depth_multiplier,
|
||||||
|
add_stone_depth,
|
||||||
|
} => {
|
||||||
|
tokens.extend(quote!(
|
||||||
|
MaterialCondition::Water(WaterMaterialCondition {
|
||||||
|
offset: #offset,
|
||||||
|
surface_depth_multiplier: #surface_depth_multiplier,
|
||||||
|
add_stone_depth: #add_stone_depth,
|
||||||
|
})
|
||||||
|
));
|
||||||
|
}
|
||||||
|
Self::Temperature => {
|
||||||
|
tokens.extend(quote!(MaterialCondition::Temperature));
|
||||||
|
}
|
||||||
|
Self::Steep => {
|
||||||
|
tokens.extend(quote!(MaterialCondition::Steep));
|
||||||
|
}
|
||||||
|
Self::Not { invert } => {
|
||||||
|
tokens.extend(quote!(
|
||||||
|
MaterialCondition::Not(NotMaterialCondition {
|
||||||
|
invert: &#invert,
|
||||||
|
})
|
||||||
|
));
|
||||||
|
}
|
||||||
|
Self::Hole => {
|
||||||
|
tokens.extend(quote!(MaterialCondition::Hole(HoleMaterialCondition)));
|
||||||
|
}
|
||||||
|
Self::AbovePreliminarySurface => {
|
||||||
|
tokens.extend(quote!(MaterialCondition::AbovePreliminarySurface(
|
||||||
|
SurfaceMaterialCondition
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
Self::StoneDepth {
|
||||||
|
offset,
|
||||||
|
add_surface_depth,
|
||||||
|
secondary_depth_range,
|
||||||
|
surface_type,
|
||||||
|
} => {
|
||||||
|
let surface_type_token = match surface_type.as_str() {
|
||||||
|
"ceiling" => quote!(
|
||||||
|
pumpkin_util::math::vertical_surface_type::VerticalSurfaceType::Ceiling
|
||||||
|
),
|
||||||
|
"floor" => quote!(
|
||||||
|
pumpkin_util::math::vertical_surface_type::VerticalSurfaceType::Floor
|
||||||
|
),
|
||||||
|
_ => quote!(
|
||||||
|
pumpkin_util::math::vertical_surface_type::VerticalSurfaceType::Floor
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
tokens.extend(quote!(
|
||||||
|
MaterialCondition::StoneDepth(StoneDepthMaterialCondition {
|
||||||
|
offset: #offset,
|
||||||
|
add_surface_depth: #add_surface_depth,
|
||||||
|
secondary_depth_range: #secondary_depth_range,
|
||||||
|
surface_type: #surface_type_token,
|
||||||
|
})
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToTokens for MaterialRuleStruct {
|
||||||
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||||
|
match self {
|
||||||
|
Self::Block { result_state } => {
|
||||||
|
tokens.extend(quote!(
|
||||||
|
MaterialRule::Block(BlockMaterialRule {
|
||||||
|
result_state: #result_state
|
||||||
|
})
|
||||||
|
));
|
||||||
|
}
|
||||||
|
Self::Sequence { sequence } => {
|
||||||
|
tokens.extend(quote!(
|
||||||
|
MaterialRule::Sequence(SequenceMaterialRule {
|
||||||
|
sequence: &[#(#sequence),*]
|
||||||
|
})
|
||||||
|
));
|
||||||
|
}
|
||||||
|
Self::Condition { if_true, then_run } => {
|
||||||
|
tokens.extend(quote!(
|
||||||
|
MaterialRule::Condition(ConditionMaterialRule {
|
||||||
|
if_true: #if_true,
|
||||||
|
then_run: &#then_run
|
||||||
|
})
|
||||||
|
));
|
||||||
|
}
|
||||||
|
Self::Badlands => {
|
||||||
|
tokens.extend(quote!(MaterialRule::Badlands(BadLandsMaterialRule)));
|
||||||
|
}
|
||||||
|
Self::Unsupported => {
|
||||||
|
tokens.extend(quote!(MaterialRule::Unsupported));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn build() -> TokenStream {
|
||||||
|
println!("cargo:rerun-if-changed=../assets/chunk_gen_settings.json");
|
||||||
|
|
||||||
|
let json: BTreeMap<String, GenerationSettingsStruct> =
|
||||||
|
serde_json::from_str(&fs::read_to_string("../assets/chunk_gen_settings.json").unwrap())
|
||||||
|
.expect("Failed to parse settings.json");
|
||||||
|
|
||||||
|
let mut const_defs = TokenStream::new();
|
||||||
|
|
||||||
|
for (name, settings) in &json {
|
||||||
|
let upper_name = name.to_uppercase();
|
||||||
|
let const_name = format_ident!("{}", upper_name);
|
||||||
|
|
||||||
|
const_defs.extend(quote!(
|
||||||
|
pub const #const_name: GenerationSettings = #settings;
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
quote!(
|
||||||
|
use crate::dimension::Dimension;
|
||||||
|
use std::{cell::RefCell, num::NonZeroUsize};
|
||||||
|
use pumpkin_util::random::RandomDeriver;
|
||||||
|
use pumpkin_util::y_offset::YOffset;
|
||||||
|
use crate::biome::Biome;
|
||||||
|
use pumpkin_util::y_offset::Absolute;
|
||||||
|
|
||||||
|
pub struct BlockBlueprint {
|
||||||
|
pub name: &'static str,
|
||||||
|
pub properties: Option<&'static [(&'static str, &'static str)]>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct GenerationSettings {
|
||||||
|
pub aquifers_enabled: bool,
|
||||||
|
pub ore_veins_enabled: bool,
|
||||||
|
pub legacy_random_source: bool,
|
||||||
|
pub sea_level: i32,
|
||||||
|
pub default_fluid: BlockBlueprint,
|
||||||
|
pub shape: GenerationShapeConfig,
|
||||||
|
pub surface_rule: MaterialRule,
|
||||||
|
pub default_block: BlockBlueprint,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct GenerationShapeConfig {
|
||||||
|
pub min_y: i8,
|
||||||
|
pub height: u16,
|
||||||
|
pub size_horizontal: u8,
|
||||||
|
pub size_vertical: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GenerationShapeConfig {
|
||||||
|
#[inline] #[must_use]
|
||||||
|
pub fn vertical_cell_block_count(&self) -> u8 { self.size_vertical << 2 }
|
||||||
|
|
||||||
|
#[inline] #[must_use]
|
||||||
|
pub fn horizontal_cell_block_count(&self) -> u8 { self.size_horizontal << 2 }
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub const fn max_y(&self) -> u16 {
|
||||||
|
if self.min_y >= 0 {
|
||||||
|
self.height + self.min_y as u16
|
||||||
|
} else {
|
||||||
|
(self.height as i32 + self.min_y as i32) as u16
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn trim_height(&self, bottom_y: i8, top_y: u16) -> Self {
|
||||||
|
let new_min = self.min_y.max(bottom_y);
|
||||||
|
let this_top = if self.min_y >= 0 {
|
||||||
|
self.height + self.min_y as u16
|
||||||
|
} else {
|
||||||
|
self.height - self.min_y.unsigned_abs() as u16
|
||||||
|
};
|
||||||
|
let new_top = this_top.min(top_y);
|
||||||
|
let new_height = if new_min >= 0 {
|
||||||
|
new_top - new_min as u16
|
||||||
|
} else {
|
||||||
|
new_top + new_min.unsigned_abs() as u16
|
||||||
|
};
|
||||||
|
|
||||||
|
Self {
|
||||||
|
min_y: new_min,
|
||||||
|
height: new_height,
|
||||||
|
size_horizontal: self.size_horizontal,
|
||||||
|
size_vertical: self.size_vertical,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct BlockMaterialRule {
|
||||||
|
pub result_state: BlockBlueprint,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SequenceMaterialRule {
|
||||||
|
pub sequence: &'static [MaterialRule],
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ConditionMaterialRule {
|
||||||
|
pub if_true: MaterialCondition,
|
||||||
|
pub then_run: &'static MaterialRule,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct BadLandsMaterialRule;
|
||||||
|
|
||||||
|
pub enum MaterialRule {
|
||||||
|
Block(BlockMaterialRule),
|
||||||
|
Sequence(SequenceMaterialRule),
|
||||||
|
Condition(ConditionMaterialRule),
|
||||||
|
Badlands(BadLandsMaterialRule),
|
||||||
|
Unsupported,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub struct BiomeMaterialCondition {
|
||||||
|
pub biome_is: &'static [&'static Biome],
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct NoiseThresholdMaterialCondition {
|
||||||
|
pub noise: &'static str,
|
||||||
|
pub min_threshold: f64,
|
||||||
|
pub max_threshold: f64,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct VerticalGradientMaterialCondition {
|
||||||
|
pub random_name: &'static str,
|
||||||
|
pub true_at_and_below: YOffset,
|
||||||
|
pub false_at_and_above: YOffset,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct AboveYMaterialCondition {
|
||||||
|
pub anchor: YOffset,
|
||||||
|
pub surface_depth_multiplier: i32,
|
||||||
|
pub add_stone_depth: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct WaterMaterialCondition {
|
||||||
|
pub offset: i32,
|
||||||
|
pub surface_depth_multiplier: i32,
|
||||||
|
pub add_stone_depth: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct HoleMaterialCondition;
|
||||||
|
|
||||||
|
pub struct NotMaterialCondition {
|
||||||
|
pub invert: &'static MaterialCondition,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SurfaceMaterialCondition;
|
||||||
|
|
||||||
|
pub struct StoneDepthMaterialCondition {
|
||||||
|
pub offset: i32,
|
||||||
|
pub add_surface_depth: bool,
|
||||||
|
pub secondary_depth_range: i32,
|
||||||
|
pub surface_type: pumpkin_util::math::vertical_surface_type::VerticalSurfaceType,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum MaterialCondition {
|
||||||
|
Biome(BiomeMaterialCondition),
|
||||||
|
NoiseThreshold(NoiseThresholdMaterialCondition),
|
||||||
|
VerticalGradient(VerticalGradientMaterialCondition),
|
||||||
|
YAbove(AboveYMaterialCondition),
|
||||||
|
Water(WaterMaterialCondition),
|
||||||
|
Temperature,
|
||||||
|
Steep,
|
||||||
|
Not(NotMaterialCondition),
|
||||||
|
Hole(HoleMaterialCondition),
|
||||||
|
AbovePreliminarySurface(SurfaceMaterialCondition),
|
||||||
|
StoneDepth(StoneDepthMaterialCondition),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GenerationSettings {
|
||||||
|
#const_defs
|
||||||
|
|
||||||
|
pub fn from_dimension(dimension: &Dimension) -> &'static Self {
|
||||||
|
if dimension == &Dimension::OVERWORLD {
|
||||||
|
&Self::OVERWORLD
|
||||||
|
} else if dimension == &Dimension::THE_NETHER {
|
||||||
|
&Self::NETHER
|
||||||
|
} else {
|
||||||
|
&Self::END
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
@ -102,7 +102,7 @@ pub(crate) fn build() -> TokenStream {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
quote! {
|
quote!(
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct Dimension {
|
pub struct Dimension {
|
||||||
pub id: u8,
|
pub id: u8,
|
||||||
@ -134,5 +134,5 @@ pub(crate) fn build() -> TokenStream {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Eq for Dimension {}
|
impl Eq for Dimension {}
|
||||||
}
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -771,13 +771,13 @@ pub(crate) fn build() -> TokenStream {
|
|||||||
|
|
||||||
impl ToResourceLocation for &'static Fluid {
|
impl ToResourceLocation for &'static Fluid {
|
||||||
fn to_resource_location(&self) -> ResourceLocation {
|
fn to_resource_location(&self) -> ResourceLocation {
|
||||||
ResourceLocation::vanilla(self.name)
|
format!("minecraft:{}", self.name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromResourceLocation for &'static Fluid {
|
impl FromResourceLocation for &'static Fluid {
|
||||||
fn from_resource_location(resource_location: &ResourceLocation) -> Option<Self> {
|
fn from_resource_location(resource_location: &ResourceLocation) -> Option<Self> {
|
||||||
Fluid::from_registry_key(&resource_location.path)
|
Fluid::from_registry_key(&resource_location.strip_prefix(resource_location).unwrap_or(resource_location))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -92,14 +92,13 @@ pub(crate) fn build() -> TokenStream {
|
|||||||
|
|
||||||
static_regs.iter().map(|static_reg| {
|
static_regs.iter().map(|static_reg| {
|
||||||
let registry_id = if static_reg.registry_id.contains(':') {
|
let registry_id = if static_reg.registry_id.contains(':') {
|
||||||
ResourceLocation::from(static_reg.registry_id)
|
static_reg.registry_id.to_string()
|
||||||
} else {
|
} else {
|
||||||
ResourceLocation::vanilla(static_reg.registry_id)
|
format!("minecraft:{}", static_reg.registry_id)
|
||||||
};
|
};
|
||||||
|
|
||||||
let registry_entries = static_reg.entries.iter().map(|entry| {
|
let registry_entries = static_reg.entries.iter().map(|entry| {
|
||||||
let entry_id =
|
let entry_id = format!("minecraft:{}", entry.name);
|
||||||
ResourceLocation::vanilla(entry.name);
|
|
||||||
|
|
||||||
RegistryEntryData {
|
RegistryEntryData {
|
||||||
entry_id,
|
entry_id,
|
||||||
|
|||||||
@ -91,13 +91,17 @@ impl Taggable for Block {
|
|||||||
|
|
||||||
impl ToResourceLocation for &'static Block {
|
impl ToResourceLocation for &'static Block {
|
||||||
fn to_resource_location(&self) -> ResourceLocation {
|
fn to_resource_location(&self) -> ResourceLocation {
|
||||||
ResourceLocation::vanilla(self.name)
|
format!("minecraft:{}", self.name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromResourceLocation for &'static Block {
|
impl FromResourceLocation for &'static Block {
|
||||||
fn from_resource_location(resource_location: &ResourceLocation) -> Option<Self> {
|
fn from_resource_location(resource_location: &ResourceLocation) -> Option<Self> {
|
||||||
Block::from_registry_key(&resource_location.path)
|
Block::from_registry_key(
|
||||||
|
resource_location
|
||||||
|
.strip_prefix(resource_location)
|
||||||
|
.unwrap_or(resource_location),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -20,6 +20,7 @@ pub mod registry;
|
|||||||
#[path = "generated/screen.rs"]
|
#[path = "generated/screen.rs"]
|
||||||
pub mod screen;
|
pub mod screen;
|
||||||
|
|
||||||
|
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
#[path = "generated/particle.rs"]
|
#[path = "generated/particle.rs"]
|
||||||
pub mod particle;
|
pub mod particle;
|
||||||
@ -193,3 +194,7 @@ pub use block_state::BlockState;
|
|||||||
pub use block_state::BlockStateRef;
|
pub use block_state::BlockStateRef;
|
||||||
pub use blocks::Block;
|
pub use blocks::Block;
|
||||||
pub use collision_shape::CollisionShape;
|
pub use collision_shape::CollisionShape;
|
||||||
|
|
||||||
|
#[rustfmt::skip]
|
||||||
|
#[path = "generated/chunk_gen_settings.rs"]
|
||||||
|
pub mod chunk_gen_settings;
|
||||||
|
|||||||
@ -51,7 +51,6 @@ macro_rules! define_get_number_be {
|
|||||||
impl<R: Read + Seek> NbtReadHelper<R> {
|
impl<R: Read + Seek> NbtReadHelper<R> {
|
||||||
pub fn skip_bytes(&mut self, count: i64) -> Result<()> {
|
pub fn skip_bytes(&mut self, count: i64) -> Result<()> {
|
||||||
self.reader
|
self.reader
|
||||||
.by_ref()
|
|
||||||
.seek(SeekFrom::Current(count))
|
.seek(SeekFrom::Current(count))
|
||||||
.map_err(Error::Incomplete)?;
|
.map_err(Error::Incomplete)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@ -28,34 +28,9 @@ pub struct RegistryEntry {
|
|||||||
pub data: Option<Box<[u8]>>,
|
pub data: Option<Box<[u8]>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: No unwraps
|
|
||||||
impl RegistryEntry {
|
impl RegistryEntry {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn new(entry_id: ResourceLocation, data: Option<Box<[u8]>>) -> Self {
|
pub const fn new(entry_id: ResourceLocation, data: Option<Box<[u8]>>) -> Self {
|
||||||
Self { entry_id, data }
|
Self { entry_id, data }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_nbt(name: &str, nbt: &impl Serialize) -> Self {
|
|
||||||
let mut data_buf = Vec::new();
|
|
||||||
pumpkin_nbt::serializer::to_bytes_unnamed(nbt, &mut data_buf).unwrap();
|
|
||||||
Self {
|
|
||||||
entry_id: ResourceLocation::vanilla(name),
|
|
||||||
data: Some(data_buf.into_boxed_slice()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[must_use]
|
|
||||||
pub fn none(name: &str) -> Self {
|
|
||||||
Self {
|
|
||||||
entry_id: ResourceLocation::vanilla(name),
|
|
||||||
data: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn from_nbt_custom(name: &str, nbt: &impl Serialize) -> Self {
|
|
||||||
let mut data_buf = Vec::new();
|
|
||||||
pumpkin_nbt::serializer::to_bytes_unnamed(nbt, &mut data_buf).unwrap();
|
|
||||||
Self {
|
|
||||||
entry_id: ResourceLocation::pumpkin(name),
|
|
||||||
data: Some(data_buf.into_boxed_slice()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,7 +8,6 @@ use pumpkin_data::{
|
|||||||
tag::{RegistryKey, get_registry_key_tags},
|
tag::{RegistryKey, get_registry_key_tags},
|
||||||
};
|
};
|
||||||
use pumpkin_macros::java_packet;
|
use pumpkin_macros::java_packet;
|
||||||
use pumpkin_util::resource_location::ResourceLocation;
|
|
||||||
use pumpkin_util::version::MinecraftVersion;
|
use pumpkin_util::version::MinecraftVersion;
|
||||||
|
|
||||||
#[java_packet(CONFIG_UPDATE_TAGS)]
|
#[java_packet(CONFIG_UPDATE_TAGS)]
|
||||||
@ -31,9 +30,7 @@ impl ClientPacket for CUpdateTags<'_> {
|
|||||||
) -> Result<(), WritingError> {
|
) -> Result<(), WritingError> {
|
||||||
let mut write = write;
|
let mut write = write;
|
||||||
write.write_list(self.tags, |p, registry_key| {
|
write.write_list(self.tags, |p, registry_key| {
|
||||||
p.write_resource_location(&ResourceLocation::vanilla(
|
p.write_string(&format!("minecraft:{}", registry_key.identifier_string(),))?;
|
||||||
registry_key.identifier_string(),
|
|
||||||
))?;
|
|
||||||
|
|
||||||
let values = get_registry_key_tags(*version, *registry_key).unwrap();
|
let values = get_registry_key_tags(*version, *registry_key).unwrap();
|
||||||
p.write_var_int(&values.len().try_into().map_err(|_| {
|
p.write_var_int(&values.len().try_into().map_err(|_| {
|
||||||
|
|||||||
@ -37,7 +37,7 @@ impl ClientPacket for CStopSound {
|
|||||||
(Some(category), Some(sound_id)) => {
|
(Some(category), Some(sound_id)) => {
|
||||||
write.write_u8(CATEGORY_AND_SOUND)?;
|
write.write_u8(CATEGORY_AND_SOUND)?;
|
||||||
write.write_var_int(&VarInt(category as i32))?;
|
write.write_var_int(&VarInt(category as i32))?;
|
||||||
write.write_resource_location(sound_id)
|
write.write_string(sound_id)
|
||||||
}
|
}
|
||||||
(Some(category), None) => {
|
(Some(category), None) => {
|
||||||
write.write_u8(CATEGORY_ONLY)?;
|
write.write_u8(CATEGORY_ONLY)?;
|
||||||
@ -45,7 +45,7 @@ impl ClientPacket for CStopSound {
|
|||||||
}
|
}
|
||||||
(None, Some(sound_id)) => {
|
(None, Some(sound_id)) => {
|
||||||
write.write_u8(SOUND_ONLY)?;
|
write.write_u8(SOUND_ONLY)?;
|
||||||
write.write_resource_location(sound_id)
|
write.write_string(sound_id)
|
||||||
}
|
}
|
||||||
(None, None) => write.write_u8(NO_CATEGORY_NO_SOUND),
|
(None, None) => write.write_u8(NO_CATEGORY_NO_SOUND),
|
||||||
}
|
}
|
||||||
|
|||||||
@ -26,7 +26,7 @@ pub struct SConfigCookieResponse {
|
|||||||
impl ServerPacket for SConfigCookieResponse {
|
impl ServerPacket for SConfigCookieResponse {
|
||||||
fn read(read: impl Read) -> Result<Self, ReadingError> {
|
fn read(read: impl Read) -> Result<Self, ReadingError> {
|
||||||
let mut read = read;
|
let mut read = read;
|
||||||
let key = read.get_resource_location()?;
|
let key = read.get_string()?;
|
||||||
let has_payload = read.get_bool()?;
|
let has_payload = read.get_bool()?;
|
||||||
|
|
||||||
if !has_payload {
|
if !has_payload {
|
||||||
|
|||||||
@ -26,7 +26,7 @@ impl ServerPacket for SPluginMessage {
|
|||||||
fn read(read: impl Read) -> Result<Self, ReadingError> {
|
fn read(read: impl Read) -> Result<Self, ReadingError> {
|
||||||
let mut read = read;
|
let mut read = read;
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
channel: read.get_resource_location()?,
|
channel: read.get_string()?,
|
||||||
data: read.read_remaining_to_boxed_slice(MAX_PAYLOAD_SIZE)?,
|
data: read.read_remaining_to_boxed_slice(MAX_PAYLOAD_SIZE)?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,7 +22,7 @@ impl ServerPacket for SLoginCookieResponse {
|
|||||||
fn read(read: impl Read) -> Result<Self, ReadingError> {
|
fn read(read: impl Read) -> Result<Self, ReadingError> {
|
||||||
let mut read = read;
|
let mut read = read;
|
||||||
|
|
||||||
let key = read.get_resource_location()?;
|
let key = read.get_string()?;
|
||||||
let has_payload = read.get_bool()?;
|
let has_payload = read.get_bool()?;
|
||||||
|
|
||||||
if !has_payload {
|
if !has_payload {
|
||||||
|
|||||||
@ -23,7 +23,7 @@ impl ServerPacket for SCookieResponse {
|
|||||||
fn read(read: impl Read) -> Result<Self, ReadingError> {
|
fn read(read: impl Read) -> Result<Self, ReadingError> {
|
||||||
let mut read = read;
|
let mut read = read;
|
||||||
|
|
||||||
let key = read.get_resource_location()?;
|
let key = read.get_string()?;
|
||||||
let has_payload = read.get_bool()?;
|
let has_payload = read.get_bool()?;
|
||||||
|
|
||||||
if !has_payload {
|
if !has_payload {
|
||||||
|
|||||||
@ -526,7 +526,6 @@ impl Serialize for LinkType {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use pumpkin_util::resource_location::ResourceLocation;
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -551,7 +550,7 @@ mod test {
|
|||||||
fn serde_id_or_value() {
|
fn serde_id_or_value() {
|
||||||
let mut buf = Vec::new();
|
let mut buf = Vec::new();
|
||||||
let event = SoundEvent {
|
let event = SoundEvent {
|
||||||
sound_name: ResourceLocation::vanilla("test"),
|
sound_name: "test".to_string(),
|
||||||
range: Some(1.0),
|
range: Some(1.0),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -10,7 +10,7 @@ use crate::{
|
|||||||
|
|
||||||
pub mod deserializer;
|
pub mod deserializer;
|
||||||
use pumpkin_nbt::{serializer::WriteAdaptor, tag::NbtTag};
|
use pumpkin_nbt::{serializer::WriteAdaptor, tag::NbtTag};
|
||||||
use pumpkin_util::{math::position::BlockPos, resource_location::ResourceLocation};
|
use pumpkin_util::math::position::BlockPos;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
pub mod serializer;
|
pub mod serializer;
|
||||||
|
|
||||||
@ -71,7 +71,6 @@ pub trait NetworkReadExt {
|
|||||||
fn get_var_ulong(&mut self) -> Result<VarULong, ReadingError>;
|
fn get_var_ulong(&mut self) -> Result<VarULong, ReadingError>;
|
||||||
fn get_string_bounded(&mut self, bound: usize) -> Result<String, ReadingError>;
|
fn get_string_bounded(&mut self, bound: usize) -> Result<String, ReadingError>;
|
||||||
fn get_string(&mut self) -> Result<String, ReadingError>;
|
fn get_string(&mut self) -> Result<String, ReadingError>;
|
||||||
fn get_resource_location(&mut self) -> Result<ResourceLocation, ReadingError>;
|
|
||||||
fn get_uuid(&mut self) -> Result<uuid::Uuid, ReadingError>;
|
fn get_uuid(&mut self) -> Result<uuid::Uuid, ReadingError>;
|
||||||
fn get_fixed_bitset(&mut self, bits: usize) -> Result<FixedBitSet, ReadingError>;
|
fn get_fixed_bitset(&mut self, bits: usize) -> Result<FixedBitSet, ReadingError>;
|
||||||
|
|
||||||
@ -171,17 +170,6 @@ impl<R: Read> NetworkReadExt for R {
|
|||||||
self.get_string_bounded(i32::MAX as usize)
|
self.get_string_bounded(i32::MAX as usize)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_resource_location(&mut self) -> Result<ResourceLocation, ReadingError> {
|
|
||||||
let resource_location = self.get_string_bounded(ResourceLocation::MAX_SIZE.get())?;
|
|
||||||
match resource_location.split_once(':') {
|
|
||||||
Some((namespace, path)) => Ok(ResourceLocation {
|
|
||||||
namespace: namespace.to_string(),
|
|
||||||
path: path.to_string(),
|
|
||||||
}),
|
|
||||||
None => Err(ReadingError::Incomplete("ResourceLocation".to_string())),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_uuid(&mut self) -> Result<uuid::Uuid, ReadingError> {
|
fn get_uuid(&mut self) -> Result<uuid::Uuid, ReadingError> {
|
||||||
let mut bytes = [0u8; 16];
|
let mut bytes = [0u8; 16];
|
||||||
self.read_exact(&mut bytes)
|
self.read_exact(&mut bytes)
|
||||||
@ -245,7 +233,6 @@ pub trait NetworkWriteExt {
|
|||||||
fn write_var_long(&mut self, data: &VarLong) -> Result<(), WritingError>;
|
fn write_var_long(&mut self, data: &VarLong) -> Result<(), WritingError>;
|
||||||
fn write_string_bounded(&mut self, data: &str, bound: usize) -> Result<(), WritingError>;
|
fn write_string_bounded(&mut self, data: &str, bound: usize) -> Result<(), WritingError>;
|
||||||
fn write_string(&mut self, data: &str) -> Result<(), WritingError>;
|
fn write_string(&mut self, data: &str) -> Result<(), WritingError>;
|
||||||
fn write_resource_location(&mut self, data: &ResourceLocation) -> Result<(), WritingError>;
|
|
||||||
fn write_block_pos(&mut self, pos: &BlockPos) -> Result<(), WritingError>;
|
fn write_block_pos(&mut self, pos: &BlockPos) -> Result<(), WritingError>;
|
||||||
|
|
||||||
fn write_uuid(&mut self, data: &uuid::Uuid) -> Result<(), WritingError> {
|
fn write_uuid(&mut self, data: &uuid::Uuid) -> Result<(), WritingError> {
|
||||||
@ -366,10 +353,6 @@ impl<W: Write> NetworkWriteExt for W {
|
|||||||
self.write_i64_be(pos.as_long())
|
self.write_i64_be(pos.as_long())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_resource_location(&mut self, data: &ResourceLocation) -> Result<(), WritingError> {
|
|
||||||
self.write_string_bounded(&data.to_string(), ResourceLocation::MAX_SIZE.get())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write_bitset(&mut self, data: &BitSet) -> Result<(), WritingError> {
|
fn write_bitset(&mut self, data: &BitSet) -> Result<(), WritingError> {
|
||||||
data.encode(self)
|
data.encode(self)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,6 +22,7 @@ pub mod text;
|
|||||||
pub mod translation;
|
pub mod translation;
|
||||||
pub mod version;
|
pub mod version;
|
||||||
pub mod world_seed;
|
pub mod world_seed;
|
||||||
|
pub mod y_offset;
|
||||||
|
|
||||||
pub mod jwt;
|
pub mod jwt;
|
||||||
|
|
||||||
|
|||||||
@ -1,99 +1,4 @@
|
|||||||
use std::{num::NonZeroUsize, str::FromStr};
|
pub type ResourceLocation = String;
|
||||||
|
|
||||||
use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Visitor};
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
|
||||||
pub struct ResourceLocation {
|
|
||||||
pub namespace: String,
|
|
||||||
pub path: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ResourceLocation {
|
|
||||||
/// The maximum number of bytes for a [`ResourceLocation`] is the same as for a normal [`String`].
|
|
||||||
pub const MAX_SIZE: NonZeroUsize = NonZeroUsize::new(i16::MAX as usize).unwrap();
|
|
||||||
|
|
||||||
#[must_use]
|
|
||||||
pub fn from(location: &str) -> Self {
|
|
||||||
let names = location.split_once(':').unwrap_or_default();
|
|
||||||
Self {
|
|
||||||
namespace: names.0.to_string(),
|
|
||||||
path: names.1.to_string(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[must_use]
|
|
||||||
pub fn vanilla(path: &str) -> Self {
|
|
||||||
Self {
|
|
||||||
namespace: "minecraft".to_string(),
|
|
||||||
path: path.to_string(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[must_use]
|
|
||||||
pub fn pumpkin(path: &str) -> Self {
|
|
||||||
Self {
|
|
||||||
namespace: "pumpkin".to_string(),
|
|
||||||
path: path.to_string(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::fmt::Display for ResourceLocation {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
write!(f, "{}:{}", self.namespace, self.path)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FromStr for ResourceLocation {
|
|
||||||
type Err = ();
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
||||||
match s.split_once(':') {
|
|
||||||
Some((namespace, path)) => Ok(Self {
|
|
||||||
namespace: namespace.to_string(),
|
|
||||||
path: path.to_string(),
|
|
||||||
}),
|
|
||||||
None => Err(()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Serialize for ResourceLocation {
|
|
||||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
|
||||||
serializer.serialize_str(&self.to_string())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'de> Deserialize<'de> for ResourceLocation {
|
|
||||||
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
|
|
||||||
struct ResourceLocationVisitor;
|
|
||||||
|
|
||||||
impl Visitor<'_> for ResourceLocationVisitor {
|
|
||||||
type Value = ResourceLocation;
|
|
||||||
|
|
||||||
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
||||||
formatter.write_str("a valid resource location (namespace:path)")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_string<E: serde::de::Error>(self, v: String) -> Result<Self::Value, E> {
|
|
||||||
self.visit_str(&v)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_str<E: serde::de::Error>(
|
|
||||||
self,
|
|
||||||
resource_location: &str,
|
|
||||||
) -> Result<Self::Value, E> {
|
|
||||||
match resource_location.split_once(':') {
|
|
||||||
Some((namespace, path)) => Ok(ResourceLocation {
|
|
||||||
namespace: namespace.to_string(),
|
|
||||||
path: path.to_string(),
|
|
||||||
}),
|
|
||||||
None => Err(serde::de::Error::custom("resource location can't be split")),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
deserializer.deserialize_str(ResourceLocationVisitor)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait ToResourceLocation: Sized {
|
pub trait ToResourceLocation: Sized {
|
||||||
fn to_resource_location(&self) -> ResourceLocation;
|
fn to_resource_location(&self) -> ResourceLocation;
|
||||||
|
|||||||
@ -23,14 +23,14 @@ impl YOffset {
|
|||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct Absolute {
|
pub struct Absolute {
|
||||||
absolute: i16,
|
pub absolute: i16,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct AboveBottom {
|
pub struct AboveBottom {
|
||||||
above_bottom: i8,
|
pub above_bottom: i8,
|
||||||
}
|
}
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct BelowTop {
|
pub struct BelowTop {
|
||||||
below_top: i8,
|
pub below_top: i8,
|
||||||
}
|
}
|
||||||
@ -1,20 +1,21 @@
|
|||||||
use criterion::{Criterion, criterion_group, criterion_main};
|
use criterion::{Criterion, criterion_group, criterion_main};
|
||||||
use pumpkin_data::noise_router::OVERWORLD_BASE_NOISE_ROUTER;
|
use pumpkin_data::{
|
||||||
|
chunk_gen_settings::GenerationSettings, dimension::Dimension,
|
||||||
|
noise_router::OVERWORLD_BASE_NOISE_ROUTER,
|
||||||
|
};
|
||||||
use pumpkin_world::{
|
use pumpkin_world::{
|
||||||
GENERATION_SETTINGS, GeneratorSetting, GlobalRandomConfig, ProtoNoiseRouters,
|
GlobalRandomConfig, ProtoNoiseRouters, bench_create_and_populate_biome,
|
||||||
bench_create_and_populate_biome, bench_create_and_populate_noise,
|
bench_create_and_populate_noise, bench_create_and_populate_noise_with_surface,
|
||||||
bench_create_and_populate_noise_with_surface, generation::proto_chunk::TerrainCache,
|
block::to_state_from_blueprint, generation::proto_chunk::TerrainCache,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn bench_terrain_gen(c: &mut Criterion) {
|
fn bench_terrain_gen(c: &mut Criterion) {
|
||||||
let seed = 0;
|
let seed = 0;
|
||||||
let random_config = GlobalRandomConfig::new(seed, false);
|
let random_config = GlobalRandomConfig::new(seed, false);
|
||||||
let base_router = ProtoNoiseRouters::generate(&OVERWORLD_BASE_NOISE_ROUTER, &random_config);
|
let base_router = ProtoNoiseRouters::generate(&OVERWORLD_BASE_NOISE_ROUTER, &random_config);
|
||||||
let surface_config = GENERATION_SETTINGS
|
let surface_config = GenerationSettings::from_dimension(&Dimension::OVERWORLD);
|
||||||
.get(&GeneratorSetting::Overworld)
|
|
||||||
.unwrap();
|
|
||||||
let terrain_cache = TerrainCache::from_random(&random_config);
|
let terrain_cache = TerrainCache::from_random(&random_config);
|
||||||
let default_block = surface_config.default_block.get_state();
|
let default_state = to_state_from_blueprint(&surface_config.default_block);
|
||||||
|
|
||||||
c.bench_function("overworld biome", |b| {
|
c.bench_function("overworld biome", |b| {
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
@ -23,7 +24,7 @@ fn bench_terrain_gen(c: &mut Criterion) {
|
|||||||
&random_config,
|
&random_config,
|
||||||
surface_config,
|
surface_config,
|
||||||
&terrain_cache,
|
&terrain_cache,
|
||||||
default_block,
|
default_state,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -35,7 +36,7 @@ fn bench_terrain_gen(c: &mut Criterion) {
|
|||||||
&random_config,
|
&random_config,
|
||||||
surface_config,
|
surface_config,
|
||||||
&terrain_cache,
|
&terrain_cache,
|
||||||
default_block,
|
default_state,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -47,7 +48,7 @@ fn bench_terrain_gen(c: &mut Criterion) {
|
|||||||
&random_config,
|
&random_config,
|
||||||
surface_config,
|
surface_config,
|
||||||
&terrain_cache,
|
&terrain_cache,
|
||||||
default_block,
|
default_state,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -60,13 +60,15 @@ pub fn hash_seed(seed: u64) -> i64 {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use pumpkin_data::{
|
use pumpkin_data::{
|
||||||
chunk::Biome, dimension::Dimension, noise_router::OVERWORLD_BASE_NOISE_ROUTER,
|
chunk::Biome, chunk_gen_settings::GenerationSettings, dimension::Dimension,
|
||||||
|
noise_router::OVERWORLD_BASE_NOISE_ROUTER,
|
||||||
};
|
};
|
||||||
use pumpkin_util::read_data_from_file;
|
use pumpkin_util::read_data_from_file;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
GENERATION_SETTINGS, GeneratorSetting, GlobalRandomConfig, ProtoChunk,
|
GlobalRandomConfig, ProtoChunk,
|
||||||
|
block::to_state_from_blueprint,
|
||||||
chunk::palette::BIOME_NETWORK_MAX_BITS,
|
chunk::palette::BIOME_NETWORK_MAX_BITS,
|
||||||
generation::noise::router::{
|
generation::noise::router::{
|
||||||
multi_noise_sampler::{MultiNoiseSampler, MultiNoiseSamplerBuilderOptions},
|
multi_noise_sampler::{MultiNoiseSampler, MultiNoiseSamplerBuilderOptions},
|
||||||
@ -110,11 +112,10 @@ mod test {
|
|||||||
let random_config = GlobalRandomConfig::new(seed, false);
|
let random_config = GlobalRandomConfig::new(seed, false);
|
||||||
let noise_router =
|
let noise_router =
|
||||||
ProtoNoiseRouters::generate(&OVERWORLD_BASE_NOISE_ROUTER, &random_config);
|
ProtoNoiseRouters::generate(&OVERWORLD_BASE_NOISE_ROUTER, &random_config);
|
||||||
let surface_settings = GENERATION_SETTINGS
|
let surface_settings = GenerationSettings::from_dimension(&Dimension::OVERWORLD);
|
||||||
.get(&GeneratorSetting::Overworld)
|
|
||||||
.unwrap();
|
|
||||||
//let _terrain_cache = TerrainCache::from_random(&random_config);
|
//let _terrain_cache = TerrainCache::from_random(&random_config);
|
||||||
let default_block = surface_settings.default_block.get_state();
|
let default_block = to_state_from_blueprint(&surface_settings.default_block);
|
||||||
|
|
||||||
for data in expected_data {
|
for data in expected_data {
|
||||||
let chunk_x = data.x;
|
let chunk_x = data.x;
|
||||||
|
|||||||
@ -33,13 +33,15 @@ impl NoiseValuePoint {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use pumpkin_data::{
|
use pumpkin_data::{
|
||||||
chunk::Biome, dimension::Dimension, noise_router::OVERWORLD_BASE_NOISE_ROUTER,
|
chunk::Biome, chunk_gen_settings::GenerationSettings, dimension::Dimension,
|
||||||
|
noise_router::OVERWORLD_BASE_NOISE_ROUTER,
|
||||||
};
|
};
|
||||||
use pumpkin_util::read_data_from_file;
|
use pumpkin_util::read_data_from_file;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
GENERATION_SETTINGS, GeneratorSetting, GlobalRandomConfig, ProtoChunk,
|
GlobalRandomConfig, ProtoChunk,
|
||||||
biome::{BiomeSupplier, MultiNoiseBiomeSupplier},
|
biome::{BiomeSupplier, MultiNoiseBiomeSupplier},
|
||||||
|
block::to_state_from_blueprint,
|
||||||
generation::{
|
generation::{
|
||||||
noise::router::{
|
noise::router::{
|
||||||
multi_noise_sampler::{MultiNoiseSampler, MultiNoiseSamplerBuilderOptions},
|
multi_noise_sampler::{MultiNoiseSampler, MultiNoiseSamplerBuilderOptions},
|
||||||
@ -68,9 +70,8 @@ mod test {
|
|||||||
let noise_router =
|
let noise_router =
|
||||||
ProtoNoiseRouters::generate(&OVERWORLD_BASE_NOISE_ROUTER, &random_config);
|
ProtoNoiseRouters::generate(&OVERWORLD_BASE_NOISE_ROUTER, &random_config);
|
||||||
|
|
||||||
let surface_config = GENERATION_SETTINGS
|
let surface_config = GenerationSettings::from_dimension(&Dimension::OVERWORLD);
|
||||||
.get(&GeneratorSetting::Overworld)
|
|
||||||
.unwrap();
|
|
||||||
let _terrain_cache = TerrainCache::from_random(&random_config);
|
let _terrain_cache = TerrainCache::from_random(&random_config);
|
||||||
// Calculate biome mixer seed
|
// Calculate biome mixer seed
|
||||||
let biome_mixer_seed = hash_seed(random_config.seed);
|
let biome_mixer_seed = hash_seed(random_config.seed);
|
||||||
@ -79,7 +80,7 @@ mod test {
|
|||||||
chunk_x,
|
chunk_x,
|
||||||
chunk_z,
|
chunk_z,
|
||||||
&Dimension::OVERWORLD,
|
&Dimension::OVERWORLD,
|
||||||
surface_config.default_block.get_state(),
|
to_state_from_blueprint(&surface_config.default_block),
|
||||||
biome_mixer_seed,
|
biome_mixer_seed,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@ -76,7 +76,7 @@ impl BlockEntity for BarrelBlockEntity {
|
|||||||
|
|
||||||
fn tick<'a>(
|
fn tick<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
world: Arc<dyn SimpleWorld>,
|
world: &'a Arc<dyn SimpleWorld>,
|
||||||
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
|
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
self.viewers
|
self.viewers
|
||||||
|
|||||||
@ -76,7 +76,7 @@ impl BlockEntity for ChestBlockEntity {
|
|||||||
|
|
||||||
fn tick<'a>(
|
fn tick<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
world: Arc<dyn SimpleWorld>,
|
world: &'a Arc<dyn SimpleWorld>,
|
||||||
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
|
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
self.viewers
|
self.viewers
|
||||||
|
|||||||
@ -47,7 +47,7 @@ impl BlockEntity for EnderChestBlockEntity {
|
|||||||
|
|
||||||
fn tick<'a>(
|
fn tick<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
world: Arc<dyn SimpleWorld>,
|
world: &'a Arc<dyn SimpleWorld>,
|
||||||
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
|
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
self.viewers
|
self.viewers
|
||||||
|
|||||||
@ -315,7 +315,7 @@ macro_rules! impl_block_entity_for_cooking {
|
|||||||
impl $crate::block::entities::BlockEntity for $struct_name {
|
impl $crate::block::entities::BlockEntity for $struct_name {
|
||||||
fn tick<'a>(
|
fn tick<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
world: Arc<dyn $crate::world::SimpleWorld>,
|
world: &'a Arc<dyn $crate::world::SimpleWorld>,
|
||||||
) -> std::pin::Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
|
) -> std::pin::Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let is_burning = self.is_burning();
|
let is_burning = self.is_burning();
|
||||||
|
|||||||
@ -77,7 +77,7 @@ impl BlockEntity for HopperBlockEntity {
|
|||||||
|
|
||||||
fn tick<'a>(
|
fn tick<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
world: Arc<dyn SimpleWorld>,
|
world: &'a Arc<dyn SimpleWorld>,
|
||||||
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
|
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
self.ticked_game_time.store(
|
self.ticked_game_time.store(
|
||||||
@ -95,7 +95,7 @@ impl BlockEntity for HopperBlockEntity {
|
|||||||
world.get_block_state(&self.position).await.id,
|
world.get_block_state(&self.position).await.id,
|
||||||
&Block::HOPPER,
|
&Block::HOPPER,
|
||||||
);
|
);
|
||||||
self.try_move_items(&state, &world).await;
|
self.try_move_items(&state, world).await;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -81,12 +81,12 @@ impl BlockEntity for MobSpawnerBlockEntity {
|
|||||||
|
|
||||||
fn tick<'a>(
|
fn tick<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
world: Arc<dyn SimpleWorld>,
|
world: &'a Arc<dyn SimpleWorld>,
|
||||||
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
|
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
if let Some(entity_type) = &self.entity_type.load() {
|
if let Some(entity_type) = &self.entity_type.load() {
|
||||||
if self.delay.load(Ordering::Relaxed) == -1 {
|
if self.delay.load(Ordering::Relaxed) == -1 {
|
||||||
self.update_spawns(&world).await;
|
self.update_spawns(world).await;
|
||||||
} else {
|
} else {
|
||||||
self.delay.fetch_sub(1, Ordering::Relaxed);
|
self.delay.fetch_sub(1, Ordering::Relaxed);
|
||||||
return;
|
return;
|
||||||
@ -128,7 +128,7 @@ impl BlockEntity for MobSpawnerBlockEntity {
|
|||||||
update_spawns = true;
|
update_spawns = true;
|
||||||
}
|
}
|
||||||
if update_spawns {
|
if update_spawns {
|
||||||
self.update_spawns(&world).await;
|
self.update_spawns(world).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@ -55,7 +55,7 @@ pub trait BlockEntity: Send + Sync {
|
|||||||
Self: Sized;
|
Self: Sized;
|
||||||
fn tick<'a>(
|
fn tick<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
_world: Arc<dyn SimpleWorld>,
|
_world: &'a Arc<dyn SimpleWorld>,
|
||||||
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
|
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
|
||||||
Box::pin(async {})
|
Box::pin(async {})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -60,7 +60,7 @@ impl BlockEntity for PistonBlockEntity {
|
|||||||
|
|
||||||
fn tick<'a>(
|
fn tick<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
world: Arc<dyn SimpleWorld>,
|
world: &'a Arc<dyn SimpleWorld>,
|
||||||
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
|
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let current_progress = self.current_progress.load();
|
let current_progress = self.current_progress.load();
|
||||||
|
|||||||
@ -71,7 +71,7 @@ impl BlockEntity for ShulkerBoxBlockEntity {
|
|||||||
|
|
||||||
fn tick<'a>(
|
fn tick<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
world: Arc<dyn SimpleWorld>,
|
world: &'a Arc<dyn SimpleWorld>,
|
||||||
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
|
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
self.viewers
|
self.viewers
|
||||||
|
|||||||
@ -4,7 +4,7 @@ pub mod viewer;
|
|||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use pumpkin_data::{Block, BlockState};
|
use pumpkin_data::{Block, BlockState, chunk_gen_settings::BlockBlueprint};
|
||||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||||
pub use state::RawBlockState;
|
pub use state::RawBlockState;
|
||||||
|
|
||||||
@ -69,6 +69,23 @@ impl BlockStateCodec {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn to_state_id_from_blueprint(print: &BlockBlueprint) -> BlockStateId {
|
||||||
|
let block = Block::from_name(print.name)
|
||||||
|
.unwrap_or_else(|| panic!("Invalid block name in blueprint: {}", print.name));
|
||||||
|
|
||||||
|
match print.properties {
|
||||||
|
Some(props) => block.from_properties(props).to_state_id(block),
|
||||||
|
None => block.default_state.id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Helper to get the full BlockState reference from the blueprint
|
||||||
|
#[must_use]
|
||||||
|
pub fn to_state_from_blueprint(print: &BlockBlueprint) -> &'static BlockState {
|
||||||
|
BlockState::from_id(to_state_id_from_blueprint(print))
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use pumpkin_data::Block;
|
use pumpkin_data::Block;
|
||||||
|
|||||||
@ -42,7 +42,7 @@ impl ViewerCountTracker {
|
|||||||
pub async fn update_viewer_count<T>(
|
pub async fn update_viewer_count<T>(
|
||||||
&self,
|
&self,
|
||||||
entity: &T,
|
entity: &T,
|
||||||
world: Arc<dyn SimpleWorld>,
|
world: &Arc<dyn SimpleWorld>,
|
||||||
position: &BlockPos,
|
position: &BlockPos,
|
||||||
) where
|
) where
|
||||||
T: BlockEntity + ViewerCountListener + 'static,
|
T: BlockEntity + ViewerCountListener + 'static,
|
||||||
@ -52,12 +52,12 @@ impl ViewerCountTracker {
|
|||||||
if old != current {
|
if old != current {
|
||||||
match (old, current) {
|
match (old, current) {
|
||||||
(n, 0) if n > 0 => {
|
(n, 0) if n > 0 => {
|
||||||
entity.on_container_close(&world, position).await;
|
entity.on_container_close(world, position).await;
|
||||||
// TODO: world.emitGameEvent(player, GameEvent.CONTAINER_CLOSE, pos);
|
// TODO: world.emitGameEvent(player, GameEvent.CONTAINER_CLOSE, pos);
|
||||||
// TODO: this.maxBlockInteractionRange = 0.0;
|
// TODO: this.maxBlockInteractionRange = 0.0;
|
||||||
}
|
}
|
||||||
(0, n) if n > 0 => {
|
(0, n) if n > 0 => {
|
||||||
entity.on_container_open(&world, position).await;
|
entity.on_container_open(world, position).await;
|
||||||
// TODO: world.emitGameEvent(player, GameEvent.CONTAINER_OPEN, pos);
|
// TODO: world.emitGameEvent(player, GameEvent.CONTAINER_OPEN, pos);
|
||||||
// TODO: scheduleBlockTick(world, pos, state);
|
// TODO: scheduleBlockTick(world, pos, state);
|
||||||
}
|
}
|
||||||
@ -65,7 +65,7 @@ impl ViewerCountTracker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
entity
|
entity
|
||||||
.on_viewer_count_update(&world, position, old, current)
|
.on_viewer_count_update(world, position, old, current)
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -351,7 +351,6 @@ impl<S: SingleChunkDataSerializer> AnvilChunkFile<S> {
|
|||||||
log::trace!("Writing in place: {}", path.display());
|
log::trace!("Writing in place: {}", path.display());
|
||||||
|
|
||||||
let file = tokio::fs::OpenOptions::new()
|
let file = tokio::fs::OpenOptions::new()
|
||||||
.read(false)
|
|
||||||
.write(true)
|
.write(true)
|
||||||
.create(true)
|
.create(true)
|
||||||
.truncate(false)
|
.truncate(false)
|
||||||
@ -450,13 +449,7 @@ impl<S: SingleChunkDataSerializer> AnvilChunkFile<S> {
|
|||||||
let temp_path = path.with_extension("tmp");
|
let temp_path = path.with_extension("tmp");
|
||||||
log::trace!("Writing tmp file to disk: {temp_path:?}");
|
log::trace!("Writing tmp file to disk: {temp_path:?}");
|
||||||
|
|
||||||
let file = tokio::fs::OpenOptions::new()
|
let file = tokio::fs::File::create(&temp_path).await?;
|
||||||
.read(false)
|
|
||||||
.write(true)
|
|
||||||
.create(true)
|
|
||||||
.truncate(true)
|
|
||||||
.open(&temp_path)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
let mut write = BufWriter::new(file);
|
let mut write = BufWriter::new(file);
|
||||||
|
|
||||||
|
|||||||
@ -179,14 +179,7 @@ impl<S: SingleChunkDataSerializer> ChunkSerializer for LinearFile<S> {
|
|||||||
let temp_path = path.with_extension("tmp");
|
let temp_path = path.with_extension("tmp");
|
||||||
log::trace!("Writing tmp file to disk: {}", temp_path.display());
|
log::trace!("Writing tmp file to disk: {}", temp_path.display());
|
||||||
|
|
||||||
let file = tokio::fs::OpenOptions::new()
|
let file = tokio::fs::File::create(&temp_path).await?;
|
||||||
.read(false)
|
|
||||||
.write(true)
|
|
||||||
.create(true)
|
|
||||||
.truncate(true)
|
|
||||||
.open(&temp_path)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
let mut write = BufWriter::new(file);
|
let mut write = BufWriter::new(file);
|
||||||
|
|
||||||
// Parse the headers to a buffer
|
// Parse the headers to a buffer
|
||||||
|
|||||||
@ -1,9 +1,10 @@
|
|||||||
use std::{collections::HashMap, io::Cursor, path::PathBuf, pin::Pin};
|
use std::{io::Cursor, path::PathBuf, pin::Pin};
|
||||||
|
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use futures::future::join_all;
|
use futures::future::join_all;
|
||||||
use pumpkin_data::{Block, chunk::ChunkStatus, fluid::Fluid};
|
use pumpkin_data::{Block, chunk::ChunkStatus, fluid::Fluid};
|
||||||
use pumpkin_nbt::{compound::NbtCompound, from_bytes, nbt_long_array};
|
use pumpkin_nbt::{compound::NbtCompound, from_bytes, nbt_long_array};
|
||||||
|
use rustc_hash::FxHashMap;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -170,7 +171,7 @@ impl ChunkData {
|
|||||||
block_ticks: ChunkTickScheduler::from_iter(chunk_data.block_ticks),
|
block_ticks: ChunkTickScheduler::from_iter(chunk_data.block_ticks),
|
||||||
fluid_ticks: ChunkTickScheduler::from_iter(chunk_data.fluid_ticks),
|
fluid_ticks: ChunkTickScheduler::from_iter(chunk_data.fluid_ticks),
|
||||||
block_entities: {
|
block_entities: {
|
||||||
let mut block_entities = HashMap::new();
|
let mut block_entities = FxHashMap::default();
|
||||||
for nbt in chunk_data.block_entities {
|
for nbt in chunk_data.block_entities {
|
||||||
let block_entity = block_entity_from_nbt(&nbt);
|
let block_entity = block_entity_from_nbt(&nbt);
|
||||||
if let Some(block_entity) = block_entity {
|
if let Some(block_entity) = block_entity {
|
||||||
@ -289,7 +290,7 @@ impl ChunkEntityData {
|
|||||||
chunk_entity_data.position[1],
|
chunk_entity_data.position[1],
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
let mut map = HashMap::new();
|
let mut map = FxHashMap::default();
|
||||||
for entity_nbt in chunk_entity_data.entities {
|
for entity_nbt in chunk_entity_data.entities {
|
||||||
let uuid = if let Some(uuid) = entity_nbt.get_int_array("UUID") {
|
let uuid = if let Some(uuid) = entity_nbt.get_int_array("UUID") {
|
||||||
Uuid::from_u128(
|
Uuid::from_u128(
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
use std::{
|
use std::{
|
||||||
collections::BTreeMap,
|
collections::BTreeMap,
|
||||||
io::ErrorKind,
|
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
@ -9,7 +8,6 @@ use futures::future::join_all;
|
|||||||
use log::{error, trace};
|
use log::{error, trace};
|
||||||
use pumpkin_util::math::vector2::Vector2;
|
use pumpkin_util::math::vector2::Vector2;
|
||||||
use tokio::{
|
use tokio::{
|
||||||
io::AsyncReadExt,
|
|
||||||
join,
|
join,
|
||||||
sync::{OnceCell, RwLock, mpsc},
|
sync::{OnceCell, RwLock, mpsc},
|
||||||
};
|
};
|
||||||
@ -86,39 +84,31 @@ impl<S: ChunkSerializer<WriteBackend = PathBuf>> ChunkSerializerLazyLoader<S> {
|
|||||||
|
|
||||||
async fn read_from_disk(&self) -> Result<S, ChunkReadingError> {
|
async fn read_from_disk(&self) -> Result<S, ChunkReadingError> {
|
||||||
trace!("Opening file from Disk: {}", self.path.display());
|
trace!("Opening file from Disk: {}", self.path.display());
|
||||||
let file = tokio::fs::OpenOptions::new()
|
|
||||||
.read(true)
|
let file_bytes = tokio::fs::read(&self.path).await.map_err(|err| {
|
||||||
.write(false)
|
if err.kind() == std::io::ErrorKind::NotFound {
|
||||||
.create(false)
|
ChunkReadingError::ChunkNotExist
|
||||||
.truncate(false)
|
} else {
|
||||||
.open(&self.path)
|
ChunkReadingError::IoError(err.kind())
|
||||||
.await
|
}
|
||||||
.map_err(|err| match err.kind() {
|
|
||||||
ErrorKind::NotFound => ChunkReadingError::ChunkNotExist,
|
|
||||||
kind => ChunkReadingError::IoError(kind),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
let value = match file {
|
match file_bytes {
|
||||||
Ok(mut file) => {
|
Ok(bytes) => {
|
||||||
let capacity = match file.metadata().await {
|
let value = S::read(bytes.into())?;
|
||||||
Ok(metadata) => metadata.len() as usize,
|
|
||||||
Err(_) => 4096, // A sane default
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO: Memmap?
|
|
||||||
let mut file_bytes = Vec::with_capacity(capacity);
|
|
||||||
file.read_to_end(&mut file_bytes)
|
|
||||||
.await
|
|
||||||
.map_err(|err| ChunkReadingError::IoError(err.kind()))?;
|
|
||||||
S::read(file_bytes.into())?
|
|
||||||
}
|
|
||||||
Err(ChunkReadingError::ChunkNotExist) => S::default(),
|
|
||||||
Err(err) => return Err(err),
|
|
||||||
};
|
|
||||||
|
|
||||||
trace!("Successfully read file from Disk: {}", self.path.display());
|
trace!("Successfully read file from Disk: {}", self.path.display());
|
||||||
Ok(value)
|
Ok(value)
|
||||||
}
|
}
|
||||||
|
Err(ChunkReadingError::ChunkNotExist) => {
|
||||||
|
trace!(
|
||||||
|
"Chunk not found, using default for: {}",
|
||||||
|
self.path.display()
|
||||||
|
);
|
||||||
|
Ok(S::default())
|
||||||
|
}
|
||||||
|
Err(err) => Err(err),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: ChunkSerializer<WriteBackend = PathBuf>> ChunkFileManager<S> {
|
impl<S: ChunkSerializer<WriteBackend = PathBuf>> ChunkFileManager<S> {
|
||||||
@ -402,13 +392,6 @@ where
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clean_up_log(&self) -> BoxFuture<'_, ()> {
|
|
||||||
Box::pin(async move {
|
|
||||||
let locks = self.file_locks.read().await;
|
|
||||||
log::debug!("{} File locks remain in cache", locks.len());
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn block_and_await_ongoing_tasks(&self) -> BoxFuture<'_, ()> {
|
fn block_and_await_ongoing_tasks(&self) -> BoxFuture<'_, ()> {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
//we need to block any other operation
|
//we need to block any other operation
|
||||||
|
|||||||
@ -85,8 +85,6 @@ where
|
|||||||
/// Tells the `ChunkIO` that no more chunks are loaded in memory
|
/// Tells the `ChunkIO` that no more chunks are loaded in memory
|
||||||
fn clear_watched_chunks(&self) -> BoxFuture<'_, ()>;
|
fn clear_watched_chunks(&self) -> BoxFuture<'_, ()>;
|
||||||
|
|
||||||
fn clean_up_log(&self) -> BoxFuture<'_, ()>;
|
|
||||||
|
|
||||||
/// Ensure that all ongoing operations are finished
|
/// Ensure that all ongoing operations are finished
|
||||||
fn block_and_await_ongoing_tasks(&self) -> BoxFuture<'_, ()>;
|
fn block_and_await_ongoing_tasks(&self) -> BoxFuture<'_, ()>;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,10 +11,11 @@ use pumpkin_data::{Block, BlockState};
|
|||||||
use pumpkin_nbt::compound::NbtCompound;
|
use pumpkin_nbt::compound::NbtCompound;
|
||||||
use pumpkin_nbt::nbt_long_array;
|
use pumpkin_nbt::nbt_long_array;
|
||||||
use pumpkin_util::math::position::BlockPos;
|
use pumpkin_util::math::position::BlockPos;
|
||||||
|
use rustc_hash::FxHashMap;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
use std::ops::{BitAnd, BitOr};
|
use std::ops::{BitAnd, BitOr};
|
||||||
use std::{collections::HashMap, sync::Arc};
|
use std::sync::Arc;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
pub mod format;
|
pub mod format;
|
||||||
@ -76,7 +77,7 @@ pub struct ChunkData {
|
|||||||
pub z: i32,
|
pub z: i32,
|
||||||
pub block_ticks: ChunkTickScheduler<&'static Block>,
|
pub block_ticks: ChunkTickScheduler<&'static Block>,
|
||||||
pub fluid_ticks: ChunkTickScheduler<&'static Fluid>,
|
pub fluid_ticks: ChunkTickScheduler<&'static Fluid>,
|
||||||
pub block_entities: HashMap<BlockPos, Arc<dyn BlockEntity>>,
|
pub block_entities: FxHashMap<BlockPos, Arc<dyn BlockEntity>>,
|
||||||
pub light_engine: ChunkLight,
|
pub light_engine: ChunkLight,
|
||||||
pub status: ChunkStatus,
|
pub status: ChunkStatus,
|
||||||
pub dirty: bool,
|
pub dirty: bool,
|
||||||
@ -88,7 +89,7 @@ pub struct ChunkEntityData {
|
|||||||
pub x: i32,
|
pub x: i32,
|
||||||
/// Chunk Z
|
/// Chunk Z
|
||||||
pub z: i32,
|
pub z: i32,
|
||||||
pub data: HashMap<uuid::Uuid, NbtCompound>,
|
pub data: FxHashMap<uuid::Uuid, NbtCompound>,
|
||||||
|
|
||||||
pub dirty: bool,
|
pub dirty: bool,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,6 +11,7 @@ use crate::chunk::io::LoadedData::Loaded;
|
|||||||
use crate::chunk::{ChunkData, ChunkHeightmapType, ChunkLight, ChunkSections, SubChunk};
|
use crate::chunk::{ChunkData, ChunkHeightmapType, ChunkLight, ChunkSections, SubChunk};
|
||||||
use crate::generation::biome_coords;
|
use crate::generation::biome_coords;
|
||||||
use pumpkin_data::block_properties::is_air;
|
use pumpkin_data::block_properties::is_air;
|
||||||
|
use pumpkin_data::chunk_gen_settings::GenerationSettings;
|
||||||
use pumpkin_data::dimension::Dimension;
|
use pumpkin_data::dimension::Dimension;
|
||||||
use std::default::Default;
|
use std::default::Default;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
@ -18,7 +19,6 @@ use std::pin::Pin;
|
|||||||
use crate::generation::height_limit::HeightLimitView;
|
use crate::generation::height_limit::HeightLimitView;
|
||||||
|
|
||||||
use crate::generation::proto_chunk::{GenerationCache, TerrainCache};
|
use crate::generation::proto_chunk::{GenerationCache, TerrainCache};
|
||||||
use crate::generation::settings::{GenerationSettings, gen_settings_from_dimension};
|
|
||||||
use crate::level::{Level, SyncChunk};
|
use crate::level::{Level, SyncChunk};
|
||||||
use crate::world::{BlockAccessor, BlockRegistryExt};
|
use crate::world::{BlockAccessor, BlockRegistryExt};
|
||||||
use crate::{BlockStateId, GlobalRandomConfig, ProtoChunk, ProtoNoiseRouters};
|
use crate::{BlockStateId, GlobalRandomConfig, ProtoChunk, ProtoNoiseRouters};
|
||||||
@ -1769,7 +1769,7 @@ impl GenerationSchedule {
|
|||||||
thread::current().name().unwrap_or("unknown")
|
thread::current().name().unwrap_or("unknown")
|
||||||
);
|
);
|
||||||
|
|
||||||
let settings = gen_settings_from_dimension(&level.world_gen.dimension);
|
let settings = GenerationSettings::from_dimension(&level.world_gen.dimension);
|
||||||
while let Ok((pos, mut cache, stage)) = recv.recv() {
|
while let Ok((pos, mut cache, stage)) = recv.recv() {
|
||||||
// debug!("generation thread receive chunk pos {pos:?} to stage {stage:?}");
|
// debug!("generation thread receive chunk pos {pos:?} to stage {stage:?}");
|
||||||
cache.advance(
|
cache.advance(
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
use enum_dispatch::enum_dispatch;
|
use enum_dispatch::enum_dispatch;
|
||||||
|
use pumpkin_util::math::vector3::Vector3;
|
||||||
use super::noise::router::density_function::NoisePos;
|
|
||||||
|
|
||||||
pub struct BlendResult {
|
pub struct BlendResult {
|
||||||
alpha: f64,
|
alpha: f64,
|
||||||
@ -26,7 +25,7 @@ impl Blender {
|
|||||||
pub trait BlenderImpl {
|
pub trait BlenderImpl {
|
||||||
fn calculate(&self, block_x: i32, block_z: i32) -> BlendResult;
|
fn calculate(&self, block_x: i32, block_z: i32) -> BlendResult;
|
||||||
|
|
||||||
fn apply_blend_density(&self, pos: &impl NoisePos, density: f64) -> f64;
|
fn apply_blend_density(&self, pos: &Vector3<i32>, density: f64) -> f64;
|
||||||
|
|
||||||
fn get_biome_supplier(&self) {
|
fn get_biome_supplier(&self) {
|
||||||
todo!()
|
todo!()
|
||||||
@ -40,7 +39,7 @@ impl BlenderImpl for NoBlendBlender {
|
|||||||
BlendResult::new(1f64, 1f64)
|
BlendResult::new(1f64, 1f64)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_blend_density(&self, _pos: &impl NoisePos, density: f64) -> f64 {
|
fn apply_blend_density(&self, _pos: &Vector3<i32>, density: f64) -> f64 {
|
||||||
density
|
density
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,12 +1,12 @@
|
|||||||
use pumpkin_data::BlockState;
|
use pumpkin_data::BlockState;
|
||||||
|
use pumpkin_data::chunk_gen_settings::GenerationSettings;
|
||||||
use pumpkin_data::dimension::Dimension;
|
use pumpkin_data::dimension::Dimension;
|
||||||
use pumpkin_data::noise_router::{
|
use pumpkin_data::noise_router::{
|
||||||
END_BASE_NOISE_ROUTER, NETHER_BASE_NOISE_ROUTER, OVERWORLD_BASE_NOISE_ROUTER,
|
END_BASE_NOISE_ROUTER, NETHER_BASE_NOISE_ROUTER, OVERWORLD_BASE_NOISE_ROUTER,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::noise::router::proto_noise_router::ProtoNoiseRouters;
|
||||||
noise::router::proto_noise_router::ProtoNoiseRouters, settings::gen_settings_from_dimension,
|
use crate::block::to_state_from_blueprint;
|
||||||
};
|
|
||||||
use crate::generation::proto_chunk::TerrainCache;
|
use crate::generation::proto_chunk::TerrainCache;
|
||||||
use crate::generation::{GlobalRandomConfig, Seed};
|
use crate::generation::{GlobalRandomConfig, Seed};
|
||||||
|
|
||||||
@ -40,9 +40,9 @@ impl GeneratorInit for VanillaGenerator {
|
|||||||
unreachable!()
|
unreachable!()
|
||||||
};
|
};
|
||||||
let terrain_cache = TerrainCache::from_random(&random_config);
|
let terrain_cache = TerrainCache::from_random(&random_config);
|
||||||
let generation_settings = gen_settings_from_dimension(&dimension);
|
let generation_settings = GenerationSettings::from_dimension(&dimension);
|
||||||
|
|
||||||
let default_block = generation_settings.default_block.get_state();
|
let default_block = to_state_from_blueprint(&generation_settings.default_block);
|
||||||
let base_router = ProtoNoiseRouters::generate(&base, &random_config);
|
let base_router = ProtoNoiseRouters::generate(&base, &random_config);
|
||||||
Self {
|
Self {
|
||||||
random_config,
|
random_config,
|
||||||
|
|||||||
@ -1,10 +1,11 @@
|
|||||||
use std::num::NonZeroU32;
|
use std::num::NonZeroU32;
|
||||||
|
|
||||||
use pumpkin_util::random::{RandomGenerator, RandomImpl};
|
use pumpkin_util::{
|
||||||
|
random::{RandomGenerator, RandomImpl},
|
||||||
|
y_offset::YOffset,
|
||||||
|
};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
use super::y_offset::YOffset;
|
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
#[serde(tag = "type")]
|
#[serde(tag = "type")]
|
||||||
pub enum HeightProvider {
|
pub enum HeightProvider {
|
||||||
|
|||||||
@ -18,7 +18,6 @@ mod rule_test;
|
|||||||
pub mod settings;
|
pub mod settings;
|
||||||
pub mod structure;
|
pub mod structure;
|
||||||
mod surface;
|
mod surface;
|
||||||
pub mod y_offset;
|
|
||||||
|
|
||||||
use generator::{GeneratorInit, VanillaGenerator};
|
use generator::{GeneratorInit, VanillaGenerator};
|
||||||
use pumpkin_data::dimension::Dimension;
|
use pumpkin_data::dimension::Dimension;
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
use enum_dispatch::enum_dispatch;
|
use enum_dispatch::enum_dispatch;
|
||||||
use pumpkin_data::{Block, BlockState};
|
use pumpkin_data::{Block, BlockState};
|
||||||
use pumpkin_util::{
|
use pumpkin_util::{
|
||||||
math::{clamped_map, floor_div},
|
math::{clamped_map, floor_div, vector3::Vector3},
|
||||||
random::{RandomDeriver, RandomDeriverImpl, RandomImpl},
|
random::{RandomDeriver, RandomDeriverImpl, RandomImpl},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -11,7 +11,6 @@ use crate::generation::{
|
|||||||
router::{
|
router::{
|
||||||
chunk_density_function::ChunkNoiseFunctionSampleOptions,
|
chunk_density_function::ChunkNoiseFunctionSampleOptions,
|
||||||
chunk_noise_router::ChunkNoiseRouter,
|
chunk_noise_router::ChunkNoiseRouter,
|
||||||
density_function::{NoisePos, UnblendedNoisePos},
|
|
||||||
surface_height_sampler::SurfaceHeightEstimateSampler,
|
surface_height_sampler::SurfaceHeightEstimateSampler,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -237,13 +236,13 @@ impl WorldAquiferSampler {
|
|||||||
|
|
||||||
fn calculate_density(
|
fn calculate_density(
|
||||||
barrier_sample: &mut Option<f64>,
|
barrier_sample: &mut Option<f64>,
|
||||||
pos: &impl NoisePos,
|
pos: &Vector3<i32>,
|
||||||
router: &mut ChunkNoiseRouter,
|
router: &mut ChunkNoiseRouter,
|
||||||
sample_options: &ChunkNoiseFunctionSampleOptions,
|
sample_options: &ChunkNoiseFunctionSampleOptions,
|
||||||
level_1: &FluidLevel,
|
level_1: &FluidLevel,
|
||||||
level_2: &FluidLevel,
|
level_2: &FluidLevel,
|
||||||
) -> f64 {
|
) -> f64 {
|
||||||
let y = pos.y();
|
let y = pos.y;
|
||||||
let block_state1 = level_1.get_block(y);
|
let block_state1 = level_1.get_block(y);
|
||||||
let block_state2 = level_2.get_block(y);
|
let block_state2 = level_2.get_block(y);
|
||||||
|
|
||||||
@ -392,7 +391,7 @@ impl WorldAquiferSampler {
|
|||||||
router: &mut ChunkNoiseRouter,
|
router: &mut ChunkNoiseRouter,
|
||||||
sample_options: &ChunkNoiseFunctionSampleOptions,
|
sample_options: &ChunkNoiseFunctionSampleOptions,
|
||||||
) -> i32 {
|
) -> i32 {
|
||||||
let pos = UnblendedNoisePos::new(block_x, block_y, block_z);
|
let pos = Vector3::new(block_x, block_y, block_z);
|
||||||
|
|
||||||
let is_deep_dark = router.erosion(&pos, sample_options) < -0.225f32 as f64
|
let is_deep_dark = router.erosion(&pos, sample_options) < -0.225f32 as f64
|
||||||
&& router.depth(&pos, sample_options) > 0.9f32 as f64;
|
&& router.depth(&pos, sample_options) > 0.9f32 as f64;
|
||||||
@ -446,9 +445,8 @@ impl WorldAquiferSampler {
|
|||||||
|
|
||||||
let local_y = y * 40 + 20;
|
let local_y = y * 40 + 20;
|
||||||
|
|
||||||
let sample = router
|
let sample =
|
||||||
.fluid_level_spread_noise(&UnblendedNoisePos::new(x, y, z), sample_options)
|
router.fluid_level_spread_noise(&Vector3::new(x, y, z), sample_options) * 10f64;
|
||||||
* 10f64;
|
|
||||||
let to_nearest_multiple_of_three = (sample / 3f64).floor() as i32 * 3;
|
let to_nearest_multiple_of_three = (sample / 3f64).floor() as i32 * 3;
|
||||||
let local_height = to_nearest_multiple_of_three + local_y;
|
let local_height = to_nearest_multiple_of_three + local_y;
|
||||||
|
|
||||||
@ -469,7 +467,7 @@ impl WorldAquiferSampler {
|
|||||||
let y = floor_div(block_y, 40);
|
let y = floor_div(block_y, 40);
|
||||||
let z = floor_div(block_z, 64);
|
let z = floor_div(block_z, 64);
|
||||||
|
|
||||||
let sample = router.lava_noise(&UnblendedNoisePos::new(x, y, z), sample_options);
|
let sample = router.lava_noise(&Vector3::new(x, y, z), sample_options);
|
||||||
|
|
||||||
if sample.abs() > 0.3f64 {
|
if sample.abs() > 0.3f64 {
|
||||||
return &LAVA_BLOCK;
|
return &LAVA_BLOCK;
|
||||||
@ -482,7 +480,7 @@ impl WorldAquiferSampler {
|
|||||||
fn apply_internal(
|
fn apply_internal(
|
||||||
&mut self,
|
&mut self,
|
||||||
router: &mut ChunkNoiseRouter,
|
router: &mut ChunkNoiseRouter,
|
||||||
pos: &impl NoisePos,
|
pos: &Vector3<i32>,
|
||||||
sample_options: &ChunkNoiseFunctionSampleOptions,
|
sample_options: &ChunkNoiseFunctionSampleOptions,
|
||||||
height_estimator: &mut SurfaceHeightEstimateSampler,
|
height_estimator: &mut SurfaceHeightEstimateSampler,
|
||||||
density: f64,
|
density: f64,
|
||||||
@ -490,9 +488,9 @@ impl WorldAquiferSampler {
|
|||||||
if density > 0f64 {
|
if density > 0f64 {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
let sample_x = pos.x();
|
let sample_x = pos.x;
|
||||||
let sample_y = pos.y();
|
let sample_y = pos.y;
|
||||||
let sample_z = pos.z();
|
let sample_z = pos.z;
|
||||||
|
|
||||||
let fluid_level = self
|
let fluid_level = self
|
||||||
.fluid_level_sampler
|
.fluid_level_sampler
|
||||||
@ -639,7 +637,7 @@ impl AquiferSamplerImpl for WorldAquiferSampler {
|
|||||||
fn apply(
|
fn apply(
|
||||||
&mut self,
|
&mut self,
|
||||||
router: &mut ChunkNoiseRouter,
|
router: &mut ChunkNoiseRouter,
|
||||||
pos: &impl NoisePos,
|
pos: &Vector3<i32>,
|
||||||
sample_options: &ChunkNoiseFunctionSampleOptions,
|
sample_options: &ChunkNoiseFunctionSampleOptions,
|
||||||
height_estimator: &mut SurfaceHeightEstimateSampler,
|
height_estimator: &mut SurfaceHeightEstimateSampler,
|
||||||
) -> Option<&'static BlockState> {
|
) -> Option<&'static BlockState> {
|
||||||
@ -663,7 +661,7 @@ impl AquiferSamplerImpl for SeaLevelAquiferSampler {
|
|||||||
fn apply(
|
fn apply(
|
||||||
&mut self,
|
&mut self,
|
||||||
router: &mut ChunkNoiseRouter,
|
router: &mut ChunkNoiseRouter,
|
||||||
pos: &impl NoisePos,
|
pos: &Vector3<i32>,
|
||||||
sample_options: &ChunkNoiseFunctionSampleOptions,
|
sample_options: &ChunkNoiseFunctionSampleOptions,
|
||||||
_height_estimator: &mut SurfaceHeightEstimateSampler,
|
_height_estimator: &mut SurfaceHeightEstimateSampler,
|
||||||
) -> Option<&'static BlockState> {
|
) -> Option<&'static BlockState> {
|
||||||
@ -674,8 +672,8 @@ impl AquiferSamplerImpl for SeaLevelAquiferSampler {
|
|||||||
} else {
|
} else {
|
||||||
Some(
|
Some(
|
||||||
self.level_sampler
|
self.level_sampler
|
||||||
.get_fluid_level(pos.x(), pos.y(), pos.z())
|
.get_fluid_level(pos.x, pos.y, pos.z)
|
||||||
.get_block(pos.y())
|
.get_block(pos.y)
|
||||||
.default_state,
|
.default_state,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -687,7 +685,7 @@ pub trait AquiferSamplerImpl {
|
|||||||
fn apply(
|
fn apply(
|
||||||
&mut self,
|
&mut self,
|
||||||
router: &mut ChunkNoiseRouter,
|
router: &mut ChunkNoiseRouter,
|
||||||
pos: &impl NoisePos,
|
pos: &Vector3<i32>,
|
||||||
sample_options: &ChunkNoiseFunctionSampleOptions,
|
sample_options: &ChunkNoiseFunctionSampleOptions,
|
||||||
height_estimator: &mut SurfaceHeightEstimateSampler,
|
height_estimator: &mut SurfaceHeightEstimateSampler,
|
||||||
) -> Option<&'static BlockState>;
|
) -> Option<&'static BlockState>;
|
||||||
@ -697,7 +695,11 @@ pub trait AquiferSamplerImpl {
|
|||||||
mod random_positions_and_hypot {
|
mod random_positions_and_hypot {
|
||||||
use std::sync::LazyLock;
|
use std::sync::LazyLock;
|
||||||
|
|
||||||
use pumpkin_data::noise_router::OVERWORLD_BASE_NOISE_ROUTER;
|
use pumpkin_data::{
|
||||||
|
chunk_gen_settings::GenerationSettings, dimension::Dimension,
|
||||||
|
noise_router::OVERWORLD_BASE_NOISE_ROUTER,
|
||||||
|
};
|
||||||
|
use pumpkin_util::math::vector3::Vector3;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
block::RawBlockState,
|
block::RawBlockState,
|
||||||
@ -708,7 +710,6 @@ mod random_positions_and_hypot {
|
|||||||
router::{
|
router::{
|
||||||
chunk_density_function::{ChunkNoiseFunctionSampleOptions, SampleAction},
|
chunk_density_function::{ChunkNoiseFunctionSampleOptions, SampleAction},
|
||||||
chunk_noise_router::ChunkNoiseRouter,
|
chunk_noise_router::ChunkNoiseRouter,
|
||||||
density_function::UnblendedNoisePos,
|
|
||||||
proto_noise_router::ProtoNoiseRouters,
|
proto_noise_router::ProtoNoiseRouters,
|
||||||
surface_height_sampler::{
|
surface_height_sampler::{
|
||||||
SurfaceHeightEstimateSampler, SurfaceHeightSamplerBuilderOptions,
|
SurfaceHeightEstimateSampler, SurfaceHeightSamplerBuilderOptions,
|
||||||
@ -717,7 +718,6 @@ mod random_positions_and_hypot {
|
|||||||
},
|
},
|
||||||
positions::chunk_pos,
|
positions::chunk_pos,
|
||||||
proto_chunk::StandardChunkFluidLevelSampler,
|
proto_chunk::StandardChunkFluidLevelSampler,
|
||||||
settings::{GENERATION_SETTINGS, GeneratorSetting},
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -739,9 +739,7 @@ mod random_positions_and_hypot {
|
|||||||
SurfaceHeightEstimateSampler<'_>,
|
SurfaceHeightEstimateSampler<'_>,
|
||||||
ChunkNoiseFunctionSampleOptions,
|
ChunkNoiseFunctionSampleOptions,
|
||||||
) {
|
) {
|
||||||
let surface_config = GENERATION_SETTINGS
|
let surface_config = GenerationSettings::from_dimension(&Dimension::OVERWORLD);
|
||||||
.get(&GeneratorSetting::Overworld)
|
|
||||||
.unwrap();
|
|
||||||
let shape = &surface_config.shape;
|
let shape = &surface_config.shape;
|
||||||
let chunk_x = 7;
|
let chunk_x = 7;
|
||||||
let chunk_z = 4;
|
let chunk_z = 4;
|
||||||
@ -1668,7 +1666,7 @@ mod random_positions_and_hypot {
|
|||||||
for ((x, y, z, h1, h2), result) in values {
|
for ((x, y, z, h1, h2), result) in values {
|
||||||
let level1 = FluidLevel::new(h1, &WATER_BLOCK);
|
let level1 = FluidLevel::new(h1, &WATER_BLOCK);
|
||||||
let level2 = FluidLevel::new(h2, &WATER_BLOCK);
|
let level2 = FluidLevel::new(h2, &WATER_BLOCK);
|
||||||
let pos = UnblendedNoisePos::new(x, y, z);
|
let pos = Vector3::new(x, y, z);
|
||||||
let mut sample = None;
|
let mut sample = None;
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -2656,7 +2654,7 @@ mod random_positions_and_hypot {
|
|||||||
];
|
];
|
||||||
|
|
||||||
for ((x, y, z, sample), result) in values {
|
for ((x, y, z, sample), result) in values {
|
||||||
let pos = UnblendedNoisePos::new(x, y, z);
|
let pos = Vector3::new(x, y, z);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
aquifer.apply_internal(&mut router, &pos, &env, &mut height_estimator, sample),
|
aquifer.apply_internal(&mut router, &pos, &env, &mut height_estimator, sample),
|
||||||
result.map(|r| r.to_state())
|
result.map(|r| r.to_state())
|
||||||
|
|||||||
@ -3,8 +3,8 @@ pub mod ore_sampler;
|
|||||||
pub mod perlin;
|
pub mod perlin;
|
||||||
pub mod router;
|
pub mod router;
|
||||||
|
|
||||||
use pumpkin_data::{Block, BlockState};
|
use pumpkin_data::{Block, BlockState, chunk_gen_settings::GenerationShapeConfig};
|
||||||
use pumpkin_util::math::{floor_div, floor_mod};
|
use pumpkin_util::math::{floor_div, floor_mod, vector3::Vector3};
|
||||||
|
|
||||||
use crate::generation::{
|
use crate::generation::{
|
||||||
noise::{
|
noise::{
|
||||||
@ -25,11 +25,10 @@ use super::{
|
|||||||
WrapperData,
|
WrapperData,
|
||||||
},
|
},
|
||||||
chunk_noise_router::ChunkNoiseRouter,
|
chunk_noise_router::ChunkNoiseRouter,
|
||||||
density_function::{IndexToNoisePos, NoisePos, UnblendedNoisePos},
|
density_function::IndexToNoisePos,
|
||||||
proto_noise_router::ProtoNoiseRouter,
|
proto_noise_router::ProtoNoiseRouter,
|
||||||
surface_height_sampler::SurfaceHeightEstimateSampler,
|
surface_height_sampler::SurfaceHeightEstimateSampler,
|
||||||
},
|
},
|
||||||
settings::GenerationShapeConfig,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const LAVA_BLOCK: Block = Block::LAVA;
|
pub const LAVA_BLOCK: Block = Block::LAVA;
|
||||||
@ -47,7 +46,7 @@ impl BlockStateSampler {
|
|||||||
&mut self,
|
&mut self,
|
||||||
router: &mut ChunkNoiseRouter,
|
router: &mut ChunkNoiseRouter,
|
||||||
random_config: &GlobalRandomConfig,
|
random_config: &GlobalRandomConfig,
|
||||||
pos: &impl NoisePos,
|
pos: &Vector3<i32>,
|
||||||
sample_options: &ChunkNoiseFunctionSampleOptions,
|
sample_options: &ChunkNoiseFunctionSampleOptions,
|
||||||
height_estimator: &mut SurfaceHeightEstimateSampler,
|
height_estimator: &mut SurfaceHeightEstimateSampler,
|
||||||
) -> Option<&'static BlockState> {
|
) -> Option<&'static BlockState> {
|
||||||
@ -72,7 +71,7 @@ impl ChainedBlockStateSampler {
|
|||||||
&mut self,
|
&mut self,
|
||||||
router: &mut ChunkNoiseRouter,
|
router: &mut ChunkNoiseRouter,
|
||||||
random_config: &GlobalRandomConfig,
|
random_config: &GlobalRandomConfig,
|
||||||
pos: &impl NoisePos,
|
pos: &Vector3<i32>,
|
||||||
sample_options: &ChunkNoiseFunctionSampleOptions,
|
sample_options: &ChunkNoiseFunctionSampleOptions,
|
||||||
height_estimator: &mut SurfaceHeightEstimateSampler,
|
height_estimator: &mut SurfaceHeightEstimateSampler,
|
||||||
) -> Option<&'static BlockState> {
|
) -> Option<&'static BlockState> {
|
||||||
@ -100,7 +99,7 @@ impl IndexToNoisePos for InterpolationIndexMapper {
|
|||||||
&self,
|
&self,
|
||||||
index: usize,
|
index: usize,
|
||||||
sample_data: Option<&mut ChunkNoiseFunctionSampleOptions>,
|
sample_data: Option<&mut ChunkNoiseFunctionSampleOptions>,
|
||||||
) -> impl NoisePos + 'static {
|
) -> Vector3<i32> {
|
||||||
if let Some(sample_data) = sample_data {
|
if let Some(sample_data) = sample_data {
|
||||||
sample_data.cache_result_unique_id += 1;
|
sample_data.cache_result_unique_id += 1;
|
||||||
sample_data.fill_index = index;
|
sample_data.fill_index = index;
|
||||||
@ -109,7 +108,7 @@ impl IndexToNoisePos for InterpolationIndexMapper {
|
|||||||
let y = (index as i32 + self.minimum_cell_y) * self.vertical_cell_block_count;
|
let y = (index as i32 + self.minimum_cell_y) * self.vertical_cell_block_count;
|
||||||
|
|
||||||
// TODO: Change this when Blender is implemented
|
// TODO: Change this when Blender is implemented
|
||||||
UnblendedNoisePos::new(self.x, y, self.z)
|
Vector3::new(self.x, y, self.z)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,7 +126,7 @@ impl IndexToNoisePos for ChunkIndexMapper {
|
|||||||
&self,
|
&self,
|
||||||
index: usize,
|
index: usize,
|
||||||
sample_options: Option<&mut ChunkNoiseFunctionSampleOptions>,
|
sample_options: Option<&mut ChunkNoiseFunctionSampleOptions>,
|
||||||
) -> impl NoisePos + 'static {
|
) -> Vector3<i32> {
|
||||||
let cell_z_position = floor_mod(index, self.horizontal_cell_block_count);
|
let cell_z_position = floor_mod(index, self.horizontal_cell_block_count);
|
||||||
let xy_portion = floor_div(index, self.horizontal_cell_block_count);
|
let xy_portion = floor_div(index, self.horizontal_cell_block_count);
|
||||||
let cell_x_position = floor_mod(xy_portion, self.horizontal_cell_block_count);
|
let cell_x_position = floor_mod(xy_portion, self.horizontal_cell_block_count);
|
||||||
@ -143,7 +142,7 @@ impl IndexToNoisePos for ChunkIndexMapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Change this when Blender is implemented
|
// TODO: Change this when Blender is implemented
|
||||||
UnblendedNoisePos::new(
|
Vector3::new(
|
||||||
self.start_x + cell_x_position as i32,
|
self.start_x + cell_x_position as i32,
|
||||||
self.start_y + cell_y_position as i32,
|
self.start_y + cell_y_position as i32,
|
||||||
self.start_z + cell_z_position as i32,
|
self.start_z + cell_z_position as i32,
|
||||||
@ -382,7 +381,7 @@ impl<'a> ChunkNoiseGenerator<'a> {
|
|||||||
height_estimator: &mut SurfaceHeightEstimateSampler,
|
height_estimator: &mut SurfaceHeightEstimateSampler,
|
||||||
) -> Option<&'static BlockState> {
|
) -> Option<&'static BlockState> {
|
||||||
//TODO: Fix this when Blender is added
|
//TODO: Fix this when Blender is added
|
||||||
let pos = UnblendedNoisePos::new(start_x + cell_x, start_y + cell_y, start_z + cell_z);
|
let pos = Vector3::new(start_x + cell_x, start_y + cell_y, start_z + cell_z);
|
||||||
|
|
||||||
let options = ChunkNoiseFunctionSampleOptions::new(
|
let options = ChunkNoiseFunctionSampleOptions::new(
|
||||||
false,
|
false,
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
use pumpkin_data::{Block, BlockState};
|
use pumpkin_data::{Block, BlockState};
|
||||||
use pumpkin_util::{
|
use pumpkin_util::{
|
||||||
math::clamped_map,
|
math::{clamped_map, vector3::Vector3},
|
||||||
random::{RandomDeriverImpl, RandomImpl},
|
random::{RandomDeriverImpl, RandomImpl},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -8,7 +8,7 @@ use crate::{
|
|||||||
GlobalRandomConfig,
|
GlobalRandomConfig,
|
||||||
generation::noise::router::{
|
generation::noise::router::{
|
||||||
chunk_density_function::ChunkNoiseFunctionSampleOptions,
|
chunk_density_function::ChunkNoiseFunctionSampleOptions,
|
||||||
chunk_noise_router::ChunkNoiseRouter, density_function::NoisePos,
|
chunk_noise_router::ChunkNoiseRouter,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -19,7 +19,7 @@ impl OreVeinSampler {
|
|||||||
&self,
|
&self,
|
||||||
router: &mut ChunkNoiseRouter,
|
router: &mut ChunkNoiseRouter,
|
||||||
random_config: &GlobalRandomConfig,
|
random_config: &GlobalRandomConfig,
|
||||||
pos: &impl NoisePos,
|
pos: &Vector3<i32>,
|
||||||
sample_options: &ChunkNoiseFunctionSampleOptions,
|
sample_options: &ChunkNoiseFunctionSampleOptions,
|
||||||
) -> Option<&'static BlockState> {
|
) -> Option<&'static BlockState> {
|
||||||
let vein_toggle = router.vein_toggle(pos, sample_options);
|
let vein_toggle = router.vein_toggle(pos, sample_options);
|
||||||
@ -29,7 +29,7 @@ impl OreVeinSampler {
|
|||||||
&vein_type::IRON
|
&vein_type::IRON
|
||||||
};
|
};
|
||||||
|
|
||||||
let block_y = pos.y();
|
let block_y = pos.y;
|
||||||
let max_to_y = vein_type.max_y - block_y;
|
let max_to_y = vein_type.max_y - block_y;
|
||||||
let y_to_min = block_y - vein_type.min_y;
|
let y_to_min = block_y - vein_type.min_y;
|
||||||
if (max_to_y >= 0) && (y_to_min >= 0) {
|
if (max_to_y >= 0) && (y_to_min >= 0) {
|
||||||
@ -37,10 +37,9 @@ impl OreVeinSampler {
|
|||||||
let mapped_diff = clamped_map(closest_to_bound as f64, 0f64, 20f64, -0.2f64, 0f64);
|
let mapped_diff = clamped_map(closest_to_bound as f64, 0f64, 20f64, -0.2f64, 0f64);
|
||||||
let abs_sample = vein_toggle.abs();
|
let abs_sample = vein_toggle.abs();
|
||||||
if abs_sample + mapped_diff >= 0.4f32 as f64 {
|
if abs_sample + mapped_diff >= 0.4f32 as f64 {
|
||||||
let mut random =
|
let mut random = random_config
|
||||||
random_config
|
|
||||||
.ore_random_deriver
|
.ore_random_deriver
|
||||||
.split_pos(pos.x(), block_y, pos.z());
|
.split_pos(pos.x, block_y, pos.z);
|
||||||
|
|
||||||
let vein_ridged_sample = router.vein_ridged(pos, sample_options);
|
let vein_ridged_sample = router.vein_ridged(pos, sample_options);
|
||||||
if random.next_f32() <= 0.7f32 && vein_ridged_sample < 0f64 {
|
if random.next_f32() <= 0.7f32 && vein_ridged_sample < 0f64 {
|
||||||
|
|||||||
@ -3,10 +3,10 @@ use std::mem;
|
|||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
chunk_noise_router::{ChunkNoiseFunctionComponent, MutableChunkNoiseFunctionComponentImpl},
|
chunk_noise_router::{ChunkNoiseFunctionComponent, MutableChunkNoiseFunctionComponentImpl},
|
||||||
density_function::{IndexToNoisePos, NoiseFunctionComponentRange, NoisePos},
|
density_function::{IndexToNoisePos, NoiseFunctionComponentRange},
|
||||||
};
|
};
|
||||||
use enum_dispatch::enum_dispatch;
|
use enum_dispatch::enum_dispatch;
|
||||||
use pumpkin_util::math::{lerp, lerp3};
|
use pumpkin_util::math::{lerp, lerp3, vector3::Vector3};
|
||||||
|
|
||||||
use crate::generation::{biome_coords, positions::chunk_pos};
|
use crate::generation::{biome_coords, positions::chunk_pos};
|
||||||
|
|
||||||
@ -106,7 +106,7 @@ pub enum SampleAction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct ChunkNoiseFunctionSampleOptions {
|
pub struct ChunkNoiseFunctionSampleOptions {
|
||||||
populating_caches: bool,
|
pub(crate) populating_caches: bool,
|
||||||
pub(crate) action: SampleAction,
|
pub(crate) action: SampleAction,
|
||||||
|
|
||||||
// Global IDs for the `CacheOnce` wrapper
|
// Global IDs for the `CacheOnce` wrapper
|
||||||
@ -314,7 +314,7 @@ impl MutableChunkNoiseFunctionComponentImpl for DensityInterpolator {
|
|||||||
fn sample(
|
fn sample(
|
||||||
&mut self,
|
&mut self,
|
||||||
component_stack: &mut [ChunkNoiseFunctionComponent],
|
component_stack: &mut [ChunkNoiseFunctionComponent],
|
||||||
pos: &impl NoisePos,
|
pos: &Vector3<i32>,
|
||||||
sample_options: &ChunkNoiseFunctionSampleOptions,
|
sample_options: &ChunkNoiseFunctionSampleOptions,
|
||||||
) -> f64 {
|
) -> f64 {
|
||||||
match &sample_options.action {
|
match &sample_options.action {
|
||||||
@ -402,11 +402,11 @@ impl MutableChunkNoiseFunctionComponentImpl for FlatCache {
|
|||||||
fn sample(
|
fn sample(
|
||||||
&mut self,
|
&mut self,
|
||||||
component_stack: &mut [ChunkNoiseFunctionComponent],
|
component_stack: &mut [ChunkNoiseFunctionComponent],
|
||||||
pos: &impl NoisePos,
|
pos: &Vector3<i32>,
|
||||||
sample_options: &ChunkNoiseFunctionSampleOptions,
|
sample_options: &ChunkNoiseFunctionSampleOptions,
|
||||||
) -> f64 {
|
) -> f64 {
|
||||||
let absolute_biome_x_position = biome_coords::from_block(pos.x());
|
let absolute_biome_x_position = biome_coords::from_block(pos.x);
|
||||||
let absolute_biome_z_position = biome_coords::from_block(pos.z());
|
let absolute_biome_z_position = biome_coords::from_block(pos.z);
|
||||||
|
|
||||||
let relative_biome_x_position = absolute_biome_x_position - self.start_biome_x;
|
let relative_biome_x_position = absolute_biome_x_position - self.start_biome_x;
|
||||||
let relative_biome_z_position = absolute_biome_z_position - self.start_biome_z;
|
let relative_biome_z_position = absolute_biome_z_position - self.start_biome_z;
|
||||||
@ -498,10 +498,10 @@ impl MutableChunkNoiseFunctionComponentImpl for Cache2D {
|
|||||||
fn sample(
|
fn sample(
|
||||||
&mut self,
|
&mut self,
|
||||||
component_stack: &mut [ChunkNoiseFunctionComponent],
|
component_stack: &mut [ChunkNoiseFunctionComponent],
|
||||||
pos: &impl NoisePos,
|
pos: &Vector3<i32>,
|
||||||
sample_options: &ChunkNoiseFunctionSampleOptions,
|
sample_options: &ChunkNoiseFunctionSampleOptions,
|
||||||
) -> f64 {
|
) -> f64 {
|
||||||
let packed_column = chunk_pos::packed(pos.x() as u64, pos.z() as u64);
|
let packed_column = chunk_pos::packed(pos.x as u64, pos.z as u64);
|
||||||
if packed_column == self.last_sample_column {
|
if packed_column == self.last_sample_column {
|
||||||
self.last_sample_result
|
self.last_sample_result
|
||||||
} else {
|
} else {
|
||||||
@ -561,7 +561,7 @@ impl MutableChunkNoiseFunctionComponentImpl for CacheOnce {
|
|||||||
fn sample(
|
fn sample(
|
||||||
&mut self,
|
&mut self,
|
||||||
component_stack: &mut [ChunkNoiseFunctionComponent],
|
component_stack: &mut [ChunkNoiseFunctionComponent],
|
||||||
pos: &impl NoisePos,
|
pos: &Vector3<i32>,
|
||||||
sample_options: &ChunkNoiseFunctionSampleOptions,
|
sample_options: &ChunkNoiseFunctionSampleOptions,
|
||||||
) -> f64 {
|
) -> f64 {
|
||||||
match sample_options.action {
|
match sample_options.action {
|
||||||
@ -663,7 +663,7 @@ impl MutableChunkNoiseFunctionComponentImpl for CellCache {
|
|||||||
fn sample(
|
fn sample(
|
||||||
&mut self,
|
&mut self,
|
||||||
component_stack: &mut [ChunkNoiseFunctionComponent],
|
component_stack: &mut [ChunkNoiseFunctionComponent],
|
||||||
pos: &impl NoisePos,
|
pos: &Vector3<i32>,
|
||||||
sample_options: &ChunkNoiseFunctionSampleOptions,
|
sample_options: &ChunkNoiseFunctionSampleOptions,
|
||||||
) -> f64 {
|
) -> f64 {
|
||||||
match &sample_options.action {
|
match &sample_options.action {
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
use enum_dispatch::enum_dispatch;
|
use enum_dispatch::enum_dispatch;
|
||||||
use pumpkin_data::noise_router::WrapperType;
|
use pumpkin_data::noise_router::WrapperType;
|
||||||
|
use pumpkin_util::math::vector3::Vector3;
|
||||||
|
|
||||||
use crate::generation::biome_coords;
|
use crate::generation::biome_coords;
|
||||||
|
|
||||||
@ -10,8 +11,8 @@ use super::{
|
|||||||
FlatCache, SampleAction,
|
FlatCache, SampleAction,
|
||||||
},
|
},
|
||||||
density_function::{
|
density_function::{
|
||||||
IndexToNoisePos, NoiseFunctionComponentRange, NoisePos, PassThrough,
|
IndexToNoisePos, NoiseFunctionComponentRange, PassThrough,
|
||||||
StaticIndependentChunkNoiseFunctionComponentImpl, UnblendedNoisePos,
|
StaticIndependentChunkNoiseFunctionComponentImpl,
|
||||||
},
|
},
|
||||||
proto_noise_router::{
|
proto_noise_router::{
|
||||||
DependentProtoNoiseFunctionComponent, IndependentProtoNoiseFunctionComponent,
|
DependentProtoNoiseFunctionComponent, IndependentProtoNoiseFunctionComponent,
|
||||||
@ -24,7 +25,7 @@ pub trait StaticChunkNoiseFunctionComponentImpl {
|
|||||||
fn sample(
|
fn sample(
|
||||||
&self,
|
&self,
|
||||||
component_stack: &mut [ChunkNoiseFunctionComponent],
|
component_stack: &mut [ChunkNoiseFunctionComponent],
|
||||||
pos: &impl NoisePos,
|
pos: &Vector3<i32>,
|
||||||
sample_options: &ChunkNoiseFunctionSampleOptions,
|
sample_options: &ChunkNoiseFunctionSampleOptions,
|
||||||
) -> f64;
|
) -> f64;
|
||||||
|
|
||||||
@ -47,7 +48,7 @@ pub trait MutableChunkNoiseFunctionComponentImpl {
|
|||||||
fn sample(
|
fn sample(
|
||||||
&mut self,
|
&mut self,
|
||||||
component_stack: &mut [ChunkNoiseFunctionComponent],
|
component_stack: &mut [ChunkNoiseFunctionComponent],
|
||||||
pos: &impl NoisePos,
|
pos: &Vector3<i32>,
|
||||||
sample_options: &ChunkNoiseFunctionSampleOptions,
|
sample_options: &ChunkNoiseFunctionSampleOptions,
|
||||||
) -> f64;
|
) -> f64;
|
||||||
|
|
||||||
@ -189,7 +190,7 @@ impl MutableChunkNoiseFunctionComponentImpl for ChunkNoiseFunctionComponent<'_>
|
|||||||
fn sample(
|
fn sample(
|
||||||
&mut self,
|
&mut self,
|
||||||
component_stack: &mut [ChunkNoiseFunctionComponent],
|
component_stack: &mut [ChunkNoiseFunctionComponent],
|
||||||
pos: &impl NoisePos,
|
pos: &Vector3<i32>,
|
||||||
sample_options: &ChunkNoiseFunctionSampleOptions,
|
sample_options: &ChunkNoiseFunctionSampleOptions,
|
||||||
) -> f64 {
|
) -> f64 {
|
||||||
match self {
|
match self {
|
||||||
@ -225,7 +226,6 @@ impl MutableChunkNoiseFunctionComponentImpl for ChunkNoiseFunctionComponent<'_>
|
|||||||
mapper,
|
mapper,
|
||||||
sample_options,
|
sample_options,
|
||||||
),
|
),
|
||||||
//Self::Panic(message) => panic!("{}", message),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -233,7 +233,7 @@ impl MutableChunkNoiseFunctionComponentImpl for ChunkNoiseFunctionComponent<'_>
|
|||||||
impl ChunkNoiseFunctionComponent<'_> {
|
impl ChunkNoiseFunctionComponent<'_> {
|
||||||
pub fn sample_from_stack(
|
pub fn sample_from_stack(
|
||||||
component_stack: &mut [ChunkNoiseFunctionComponent],
|
component_stack: &mut [ChunkNoiseFunctionComponent],
|
||||||
pos: &impl NoisePos,
|
pos: &Vector3<i32>,
|
||||||
sample_options: &ChunkNoiseFunctionSampleOptions,
|
sample_options: &ChunkNoiseFunctionSampleOptions,
|
||||||
) -> f64 {
|
) -> f64 {
|
||||||
let (top_component, component_stack) = component_stack.split_last_mut().unwrap();
|
let (top_component, component_stack) = component_stack.split_last_mut().unwrap();
|
||||||
@ -259,7 +259,7 @@ impl ChunkNoiseDensityFunction<'_> {
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub fn sample(
|
pub fn sample(
|
||||||
&mut self,
|
&mut self,
|
||||||
pos: &impl NoisePos,
|
pos: &Vector3<i32>,
|
||||||
sample_options: &ChunkNoiseFunctionSampleOptions,
|
sample_options: &ChunkNoiseFunctionSampleOptions,
|
||||||
) -> f64 {
|
) -> f64 {
|
||||||
ChunkNoiseFunctionComponent::sample_from_stack(self.component_stack, pos, sample_options)
|
ChunkNoiseFunctionComponent::sample_from_stack(self.component_stack, pos, sample_options)
|
||||||
@ -286,7 +286,7 @@ macro_rules! sample_function {
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub fn $name(
|
pub fn $name(
|
||||||
&mut self,
|
&mut self,
|
||||||
pos: &impl NoisePos,
|
pos: &Vector3<i32>,
|
||||||
sample_options: &ChunkNoiseFunctionSampleOptions,
|
sample_options: &ChunkNoiseFunctionSampleOptions,
|
||||||
) -> f64 {
|
) -> f64 {
|
||||||
ChunkNoiseFunctionComponent::sample_from_stack(
|
ChunkNoiseFunctionComponent::sample_from_stack(
|
||||||
@ -421,11 +421,7 @@ impl<'a> ChunkNoiseRouter<'a> {
|
|||||||
let block_z_position =
|
let block_z_position =
|
||||||
biome_coords::to_block(absolute_biome_z_position);
|
biome_coords::to_block(absolute_biome_z_position);
|
||||||
|
|
||||||
let pos = UnblendedNoisePos::new(
|
let pos = Vector3::new(block_x_position, 0, block_z_position);
|
||||||
block_x_position,
|
|
||||||
0,
|
|
||||||
block_z_position,
|
|
||||||
);
|
|
||||||
|
|
||||||
//NOTE: Due to our stack invariant, what is on the stack is a
|
//NOTE: Due to our stack invariant, what is on the stack is a
|
||||||
// valid density function
|
// valid density function
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
use pumpkin_data::noise_router::{BinaryData, BinaryOperation, ClampData, LinearData, UnaryData};
|
use pumpkin_data::noise_router::{BinaryData, BinaryOperation, ClampData, LinearData, UnaryData};
|
||||||
|
use pumpkin_util::math::vector3::Vector3;
|
||||||
|
|
||||||
use crate::generation::noise::router::{
|
use crate::generation::noise::router::{
|
||||||
chunk_density_function::ChunkNoiseFunctionSampleOptions,
|
chunk_density_function::ChunkNoiseFunctionSampleOptions,
|
||||||
@ -6,8 +7,7 @@ use crate::generation::noise::router::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
IndexToNoisePos, NoiseFunctionComponentRange, NoisePos,
|
IndexToNoisePos, NoiseFunctionComponentRange, StaticIndependentChunkNoiseFunctionComponentImpl,
|
||||||
StaticIndependentChunkNoiseFunctionComponentImpl,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@ -34,7 +34,7 @@ impl NoiseFunctionComponentRange for Constant {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl StaticIndependentChunkNoiseFunctionComponentImpl for Constant {
|
impl StaticIndependentChunkNoiseFunctionComponentImpl for Constant {
|
||||||
fn sample(&self, _pos: &impl NoisePos) -> f64 {
|
fn sample(&self, _pos: &Vector3<i32>) -> f64 {
|
||||||
self.value
|
self.value
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,7 +67,7 @@ impl StaticChunkNoiseFunctionComponentImpl for Linear {
|
|||||||
fn sample(
|
fn sample(
|
||||||
&self,
|
&self,
|
||||||
component_stack: &mut [ChunkNoiseFunctionComponent],
|
component_stack: &mut [ChunkNoiseFunctionComponent],
|
||||||
pos: &impl NoisePos,
|
pos: &Vector3<i32>,
|
||||||
sample_options: &ChunkNoiseFunctionSampleOptions,
|
sample_options: &ChunkNoiseFunctionSampleOptions,
|
||||||
) -> f64 {
|
) -> f64 {
|
||||||
let input_density = ChunkNoiseFunctionComponent::sample_from_stack(
|
let input_density = ChunkNoiseFunctionComponent::sample_from_stack(
|
||||||
@ -120,7 +120,7 @@ impl StaticChunkNoiseFunctionComponentImpl for Binary {
|
|||||||
fn sample(
|
fn sample(
|
||||||
&self,
|
&self,
|
||||||
component_stack: &mut [ChunkNoiseFunctionComponent],
|
component_stack: &mut [ChunkNoiseFunctionComponent],
|
||||||
pos: &impl NoisePos,
|
pos: &Vector3<i32>,
|
||||||
sample_options: &ChunkNoiseFunctionSampleOptions,
|
sample_options: &ChunkNoiseFunctionSampleOptions,
|
||||||
) -> f64 {
|
) -> f64 {
|
||||||
let input1_density = ChunkNoiseFunctionComponent::sample_from_stack(
|
let input1_density = ChunkNoiseFunctionComponent::sample_from_stack(
|
||||||
@ -296,7 +296,7 @@ impl StaticChunkNoiseFunctionComponentImpl for Unary {
|
|||||||
fn sample(
|
fn sample(
|
||||||
&self,
|
&self,
|
||||||
component_stack: &mut [ChunkNoiseFunctionComponent],
|
component_stack: &mut [ChunkNoiseFunctionComponent],
|
||||||
pos: &impl NoisePos,
|
pos: &Vector3<i32>,
|
||||||
sample_options: &ChunkNoiseFunctionSampleOptions,
|
sample_options: &ChunkNoiseFunctionSampleOptions,
|
||||||
) -> f64 {
|
) -> f64 {
|
||||||
let input_density = ChunkNoiseFunctionComponent::sample_from_stack(
|
let input_density = ChunkNoiseFunctionComponent::sample_from_stack(
|
||||||
@ -370,7 +370,7 @@ impl StaticChunkNoiseFunctionComponentImpl for Clamp {
|
|||||||
fn sample(
|
fn sample(
|
||||||
&self,
|
&self,
|
||||||
component_stack: &mut [ChunkNoiseFunctionComponent],
|
component_stack: &mut [ChunkNoiseFunctionComponent],
|
||||||
pos: &impl NoisePos,
|
pos: &Vector3<i32>,
|
||||||
sample_options: &ChunkNoiseFunctionSampleOptions,
|
sample_options: &ChunkNoiseFunctionSampleOptions,
|
||||||
) -> f64 {
|
) -> f64 {
|
||||||
let input_density = ChunkNoiseFunctionComponent::sample_from_stack(
|
let input_density = ChunkNoiseFunctionComponent::sample_from_stack(
|
||||||
|
|||||||
@ -4,7 +4,7 @@ use pumpkin_data::noise_router::{
|
|||||||
ClampedYGradientData, RangeChoiceData, WeirdScaledData, WeirdScaledMapper,
|
ClampedYGradientData, RangeChoiceData, WeirdScaledData, WeirdScaledMapper,
|
||||||
};
|
};
|
||||||
use pumpkin_util::{
|
use pumpkin_util::{
|
||||||
math::clamped_map,
|
math::{clamped_map, vector3::Vector3},
|
||||||
noise::simplex::SimplexNoiseSampler,
|
noise::simplex::SimplexNoiseSampler,
|
||||||
random::{RandomImpl, legacy_rand::LegacyRand},
|
random::{RandomImpl, legacy_rand::LegacyRand},
|
||||||
};
|
};
|
||||||
@ -18,8 +18,7 @@ use crate::generation::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
IndexToNoisePos, NoiseFunctionComponentRange, NoisePos,
|
IndexToNoisePos, NoiseFunctionComponentRange, StaticIndependentChunkNoiseFunctionComponentImpl,
|
||||||
StaticIndependentChunkNoiseFunctionComponentImpl,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@ -80,8 +79,8 @@ impl NoiseFunctionComponentRange for EndIsland {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl StaticIndependentChunkNoiseFunctionComponentImpl for EndIsland {
|
impl StaticIndependentChunkNoiseFunctionComponentImpl for EndIsland {
|
||||||
fn sample(&self, pos: &impl NoisePos) -> f64 {
|
fn sample(&self, pos: &Vector3<i32>) -> f64 {
|
||||||
(Self::sample_2d(&self.sampler, pos.x() / 8, pos.z() / 8) as f64 - 8.0) / 128.0
|
(Self::sample_2d(&self.sampler, pos.x / 8, pos.z / 8) as f64 - 8.0) / 128.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,7 +108,7 @@ impl StaticChunkNoiseFunctionComponentImpl for WeirdScaled {
|
|||||||
fn sample(
|
fn sample(
|
||||||
&self,
|
&self,
|
||||||
component_stack: &mut [ChunkNoiseFunctionComponent],
|
component_stack: &mut [ChunkNoiseFunctionComponent],
|
||||||
pos: &impl NoisePos,
|
pos: &Vector3<i32>,
|
||||||
sample_options: &ChunkNoiseFunctionSampleOptions,
|
sample_options: &ChunkNoiseFunctionSampleOptions,
|
||||||
) -> f64 {
|
) -> f64 {
|
||||||
let input_density = ChunkNoiseFunctionComponent::sample_from_stack(
|
let input_density = ChunkNoiseFunctionComponent::sample_from_stack(
|
||||||
@ -122,9 +121,9 @@ impl StaticChunkNoiseFunctionComponentImpl for WeirdScaled {
|
|||||||
* self
|
* self
|
||||||
.sampler
|
.sampler
|
||||||
.sample(
|
.sample(
|
||||||
pos.x() as f64 / scaled_density,
|
pos.x as f64 / scaled_density,
|
||||||
pos.y() as f64 / scaled_density,
|
pos.y as f64 / scaled_density,
|
||||||
pos.z() as f64 / scaled_density,
|
pos.z as f64 / scaled_density,
|
||||||
)
|
)
|
||||||
.abs()
|
.abs()
|
||||||
}
|
}
|
||||||
@ -150,9 +149,9 @@ impl StaticChunkNoiseFunctionComponentImpl for WeirdScaled {
|
|||||||
* self
|
* self
|
||||||
.sampler
|
.sampler
|
||||||
.sample(
|
.sample(
|
||||||
pos.x() as f64 / scaled_density,
|
pos.x as f64 / scaled_density,
|
||||||
pos.y() as f64 / scaled_density,
|
pos.y as f64 / scaled_density,
|
||||||
pos.z() as f64 / scaled_density,
|
pos.z as f64 / scaled_density,
|
||||||
)
|
)
|
||||||
.abs();
|
.abs();
|
||||||
});
|
});
|
||||||
@ -195,9 +194,9 @@ impl NoiseFunctionComponentRange for ClampedYGradient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl StaticIndependentChunkNoiseFunctionComponentImpl for ClampedYGradient {
|
impl StaticIndependentChunkNoiseFunctionComponentImpl for ClampedYGradient {
|
||||||
fn sample(&self, pos: &impl NoisePos) -> f64 {
|
fn sample(&self, pos: &Vector3<i32>) -> f64 {
|
||||||
clamped_map(
|
clamped_map(
|
||||||
pos.y() as f64,
|
pos.y as f64,
|
||||||
self.data.from_y,
|
self.data.from_y,
|
||||||
self.data.to_y,
|
self.data.to_y,
|
||||||
self.data.from_value,
|
self.data.from_value,
|
||||||
@ -252,7 +251,7 @@ impl StaticChunkNoiseFunctionComponentImpl for RangeChoice {
|
|||||||
fn sample(
|
fn sample(
|
||||||
&self,
|
&self,
|
||||||
component_stack: &mut [ChunkNoiseFunctionComponent],
|
component_stack: &mut [ChunkNoiseFunctionComponent],
|
||||||
pos: &impl NoisePos,
|
pos: &Vector3<i32>,
|
||||||
sample_options: &ChunkNoiseFunctionSampleOptions,
|
sample_options: &ChunkNoiseFunctionSampleOptions,
|
||||||
) -> f64 {
|
) -> f64 {
|
||||||
let input_sample = ChunkNoiseFunctionComponent::sample_from_stack(
|
let input_sample = ChunkNoiseFunctionComponent::sample_from_stack(
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
use enum_dispatch::enum_dispatch;
|
use enum_dispatch::enum_dispatch;
|
||||||
use pumpkin_data::noise_router::WrapperType;
|
use pumpkin_data::noise_router::WrapperType;
|
||||||
|
use pumpkin_util::math::vector3::Vector3;
|
||||||
|
|
||||||
// These are for enum_dispatch
|
// These are for enum_dispatch
|
||||||
use super::chunk_density_function::{
|
use super::chunk_density_function::{
|
||||||
@ -18,48 +19,12 @@ mod test;
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test_deserializer;
|
mod test_deserializer;
|
||||||
|
|
||||||
pub trait NoisePos {
|
|
||||||
fn x(&self) -> i32;
|
|
||||||
fn y(&self) -> i32;
|
|
||||||
fn z(&self) -> i32;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct UnblendedNoisePos {
|
|
||||||
x: i32,
|
|
||||||
y: i32,
|
|
||||||
z: i32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl UnblendedNoisePos {
|
|
||||||
#[must_use]
|
|
||||||
pub const fn new(x: i32, y: i32, z: i32) -> Self {
|
|
||||||
Self { x, y, z }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl NoisePos for UnblendedNoisePos {
|
|
||||||
#[inline]
|
|
||||||
fn x(&self) -> i32 {
|
|
||||||
self.x
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn y(&self) -> i32 {
|
|
||||||
self.y
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn z(&self) -> i32 {
|
|
||||||
self.z
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait IndexToNoisePos {
|
pub trait IndexToNoisePos {
|
||||||
fn at(
|
fn at(
|
||||||
&self,
|
&self,
|
||||||
index: usize,
|
index: usize,
|
||||||
sample_options: Option<&mut ChunkNoiseFunctionSampleOptions>,
|
sample_options: Option<&mut ChunkNoiseFunctionSampleOptions>,
|
||||||
) -> impl NoisePos + 'static;
|
) -> Vector3<i32>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[enum_dispatch]
|
#[enum_dispatch]
|
||||||
@ -70,7 +35,7 @@ pub trait NoiseFunctionComponentRange {
|
|||||||
|
|
||||||
#[enum_dispatch]
|
#[enum_dispatch]
|
||||||
pub trait StaticIndependentChunkNoiseFunctionComponentImpl: NoiseFunctionComponentRange {
|
pub trait StaticIndependentChunkNoiseFunctionComponentImpl: NoiseFunctionComponentRange {
|
||||||
fn sample(&self, pos: &impl NoisePos) -> f64;
|
fn sample(&self, pos: &Vector3<i32>) -> f64;
|
||||||
fn fill(&self, array: &mut [f64], mapper: &impl IndexToNoisePos) {
|
fn fill(&self, array: &mut [f64], mapper: &impl IndexToNoisePos) {
|
||||||
array.iter_mut().enumerate().for_each(|(index, value)| {
|
array.iter_mut().enumerate().for_each(|(index, value)| {
|
||||||
let pos = mapper.at(index, None);
|
let pos = mapper.at(index, None);
|
||||||
|
|||||||
@ -2,7 +2,9 @@ use std::array;
|
|||||||
|
|
||||||
use pumpkin_data::noise_router::{InterpolatedNoiseSamplerData, NoiseData, ShiftedNoiseData};
|
use pumpkin_data::noise_router::{InterpolatedNoiseSamplerData, NoiseData, ShiftedNoiseData};
|
||||||
use pumpkin_util::{
|
use pumpkin_util::{
|
||||||
math::clamped_lerp, noise::perlin::OctavePerlinNoiseSampler, random::RandomGenerator,
|
math::{clamped_lerp, vector3::Vector3},
|
||||||
|
noise::perlin::OctavePerlinNoiseSampler,
|
||||||
|
random::RandomGenerator,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::generation::{
|
use crate::generation::{
|
||||||
@ -13,9 +15,7 @@ use crate::generation::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{NoiseFunctionComponentRange, StaticIndependentChunkNoiseFunctionComponentImpl};
|
||||||
NoiseFunctionComponentRange, NoisePos, StaticIndependentChunkNoiseFunctionComponentImpl,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub struct Noise {
|
pub struct Noise {
|
||||||
sampler: DoublePerlinNoiseSampler,
|
sampler: DoublePerlinNoiseSampler,
|
||||||
@ -41,11 +41,11 @@ impl NoiseFunctionComponentRange for Noise {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl StaticIndependentChunkNoiseFunctionComponentImpl for Noise {
|
impl StaticIndependentChunkNoiseFunctionComponentImpl for Noise {
|
||||||
fn sample(&self, pos: &impl NoisePos) -> f64 {
|
fn sample(&self, pos: &Vector3<i32>) -> f64 {
|
||||||
self.sampler.sample(
|
self.sampler.sample(
|
||||||
pos.x() as f64 * self.data.xz_scale,
|
pos.x as f64 * self.data.xz_scale,
|
||||||
pos.y() as f64 * self.data.y_scale,
|
pos.y as f64 * self.data.y_scale,
|
||||||
pos.z() as f64 * self.data.xz_scale,
|
pos.z as f64 * self.data.xz_scale,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -78,8 +78,8 @@ impl NoiseFunctionComponentRange for ShiftA {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl StaticIndependentChunkNoiseFunctionComponentImpl for ShiftA {
|
impl StaticIndependentChunkNoiseFunctionComponentImpl for ShiftA {
|
||||||
fn sample(&self, pos: &impl NoisePos) -> f64 {
|
fn sample(&self, pos: &Vector3<i32>) -> f64 {
|
||||||
shift_sample_3d(&self.sampler, pos.x() as f64, 0.0, pos.z() as f64)
|
shift_sample_3d(&self.sampler, pos.x as f64, 0.0, pos.z as f64)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,8 +106,8 @@ impl NoiseFunctionComponentRange for ShiftB {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl StaticIndependentChunkNoiseFunctionComponentImpl for ShiftB {
|
impl StaticIndependentChunkNoiseFunctionComponentImpl for ShiftB {
|
||||||
fn sample(&self, pos: &impl NoisePos) -> f64 {
|
fn sample(&self, pos: &Vector3<i32>) -> f64 {
|
||||||
shift_sample_3d(&self.sampler, pos.z() as f64, pos.x() as f64, 0.0)
|
shift_sample_3d(&self.sampler, pos.z as f64, pos.x as f64, 0.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,22 +135,22 @@ impl StaticChunkNoiseFunctionComponentImpl for ShiftedNoise {
|
|||||||
fn sample(
|
fn sample(
|
||||||
&self,
|
&self,
|
||||||
component_stack: &mut [ChunkNoiseFunctionComponent],
|
component_stack: &mut [ChunkNoiseFunctionComponent],
|
||||||
pos: &impl NoisePos,
|
pos: &Vector3<i32>,
|
||||||
sample_options: &ChunkNoiseFunctionSampleOptions,
|
sample_options: &ChunkNoiseFunctionSampleOptions,
|
||||||
) -> f64 {
|
) -> f64 {
|
||||||
let translated_x = pos.x() as f64 * self.data.xz_scale
|
let translated_x = pos.x as f64 * self.data.xz_scale
|
||||||
+ ChunkNoiseFunctionComponent::sample_from_stack(
|
+ ChunkNoiseFunctionComponent::sample_from_stack(
|
||||||
&mut component_stack[..=self.input_x_index],
|
&mut component_stack[..=self.input_x_index],
|
||||||
pos,
|
pos,
|
||||||
sample_options,
|
sample_options,
|
||||||
);
|
);
|
||||||
let translated_y = pos.y() as f64 * self.data.y_scale
|
let translated_y = pos.y as f64 * self.data.y_scale
|
||||||
+ ChunkNoiseFunctionComponent::sample_from_stack(
|
+ ChunkNoiseFunctionComponent::sample_from_stack(
|
||||||
&mut component_stack[..=self.input_y_index],
|
&mut component_stack[..=self.input_y_index],
|
||||||
pos,
|
pos,
|
||||||
sample_options,
|
sample_options,
|
||||||
);
|
);
|
||||||
let translated_z = pos.z() as f64 * self.data.xz_scale
|
let translated_z = pos.z as f64 * self.data.xz_scale
|
||||||
+ ChunkNoiseFunctionComponent::sample_from_stack(
|
+ ChunkNoiseFunctionComponent::sample_from_stack(
|
||||||
&mut component_stack[..=self.input_z_index],
|
&mut component_stack[..=self.input_z_index],
|
||||||
pos,
|
pos,
|
||||||
@ -235,10 +235,10 @@ impl NoiseFunctionComponentRange for InterpolatedNoiseSampler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl StaticIndependentChunkNoiseFunctionComponentImpl for InterpolatedNoiseSampler {
|
impl StaticIndependentChunkNoiseFunctionComponentImpl for InterpolatedNoiseSampler {
|
||||||
fn sample(&self, pos: &impl NoisePos) -> f64 {
|
fn sample(&self, pos: &Vector3<i32>) -> f64 {
|
||||||
let d = pos.x() as f64 * self.data.scaled_xz_scale;
|
let d = pos.x as f64 * self.data.scaled_xz_scale;
|
||||||
let e = pos.y() as f64 * self.data.scaled_y_scale;
|
let e = pos.y as f64 * self.data.scaled_y_scale;
|
||||||
let f = pos.z() as f64 * self.data.scaled_xz_scale;
|
let f = pos.z as f64 * self.data.scaled_xz_scale;
|
||||||
|
|
||||||
let g = d / self.data.xz_factor;
|
let g = d / self.data.xz_factor;
|
||||||
let h = e / self.data.y_factor;
|
let h = e / self.data.y_factor;
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
use pumpkin_util::math::lerp;
|
use pumpkin_util::math::{lerp, vector3::Vector3};
|
||||||
|
|
||||||
use crate::generation::noise::router::{
|
use crate::generation::noise::router::{
|
||||||
chunk_density_function::ChunkNoiseFunctionSampleOptions,
|
chunk_density_function::ChunkNoiseFunctionSampleOptions,
|
||||||
@ -6,7 +6,7 @@ use crate::generation::noise::router::{
|
|||||||
proto_noise_router::ProtoNoiseFunctionComponent,
|
proto_noise_router::ProtoNoiseFunctionComponent,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{NoiseFunctionComponentRange, NoisePos};
|
use super::NoiseFunctionComponentRange;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub enum SplineValue {
|
pub enum SplineValue {
|
||||||
@ -18,7 +18,7 @@ impl SplineValue {
|
|||||||
#[inline]
|
#[inline]
|
||||||
fn sample(
|
fn sample(
|
||||||
&self,
|
&self,
|
||||||
pos: &impl NoisePos,
|
pos: &Vector3<i32>,
|
||||||
component_stack: &mut [ChunkNoiseFunctionComponent],
|
component_stack: &mut [ChunkNoiseFunctionComponent],
|
||||||
sample_options: &ChunkNoiseFunctionSampleOptions,
|
sample_options: &ChunkNoiseFunctionSampleOptions,
|
||||||
) -> f32 {
|
) -> f32 {
|
||||||
@ -151,7 +151,7 @@ impl Spline {
|
|||||||
|
|
||||||
fn sample(
|
fn sample(
|
||||||
&self,
|
&self,
|
||||||
pos: &impl NoisePos,
|
pos: &Vector3<i32>,
|
||||||
component_stack: &mut [ChunkNoiseFunctionComponent],
|
component_stack: &mut [ChunkNoiseFunctionComponent],
|
||||||
sample_options: &ChunkNoiseFunctionSampleOptions,
|
sample_options: &ChunkNoiseFunctionSampleOptions,
|
||||||
) -> f32 {
|
) -> f32 {
|
||||||
@ -224,7 +224,7 @@ impl StaticChunkNoiseFunctionComponentImpl for SplineFunction {
|
|||||||
fn sample(
|
fn sample(
|
||||||
&self,
|
&self,
|
||||||
component_stack: &mut [ChunkNoiseFunctionComponent],
|
component_stack: &mut [ChunkNoiseFunctionComponent],
|
||||||
pos: &impl NoisePos,
|
pos: &Vector3<i32>,
|
||||||
sample_options: &ChunkNoiseFunctionSampleOptions,
|
sample_options: &ChunkNoiseFunctionSampleOptions,
|
||||||
) -> f64 {
|
) -> f64 {
|
||||||
self.spline.sample(pos, component_stack, sample_options) as f64
|
self.spline.sample(pos, component_stack, sample_options) as f64
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
use pumpkin_data::noise_router::OVERWORLD_BASE_NOISE_ROUTER;
|
use pumpkin_data::noise_router::OVERWORLD_BASE_NOISE_ROUTER;
|
||||||
|
use pumpkin_util::math::vector3::Vector3;
|
||||||
use pumpkin_util::{assert_eq_delta, read_data_from_file};
|
use pumpkin_util::{assert_eq_delta, read_data_from_file};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
@ -18,26 +19,7 @@ use crate::generation::noise::router::proto_noise_router::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use super::test_deserializer::DensityFunctionRepr;
|
use super::test_deserializer::DensityFunctionRepr;
|
||||||
use super::{NoiseFunctionComponentRange, NoisePos, PassThrough};
|
use super::{NoiseFunctionComponentRange, PassThrough};
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct TestNoisePos {
|
|
||||||
x: i32,
|
|
||||||
y: i32,
|
|
||||||
z: i32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl NoisePos for TestNoisePos {
|
|
||||||
fn x(&self) -> i32 {
|
|
||||||
self.x
|
|
||||||
}
|
|
||||||
fn y(&self) -> i32 {
|
|
||||||
self.y
|
|
||||||
}
|
|
||||||
fn z(&self) -> i32 {
|
|
||||||
self.z
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is a dummy value because we are not actually building chunk-specific functions
|
// This is a dummy value because we are not actually building chunk-specific functions
|
||||||
static TEST_OPTIONS: ChunkNoiseFunctionBuilderOptions =
|
static TEST_OPTIONS: ChunkNoiseFunctionBuilderOptions =
|
||||||
@ -131,7 +113,7 @@ macro_rules! sample_surface_router_function {
|
|||||||
// This is equivalent to a Java `NoiseRouter` after being passed into `NoiseConfig` but before being
|
// This is equivalent to a Java `NoiseRouter` after being passed into `NoiseConfig` but before being
|
||||||
// passed into `ChunkNoiseGenerator`
|
// passed into `ChunkNoiseGenerator`
|
||||||
fn normal_surface_noisified() {
|
fn normal_surface_noisified() {
|
||||||
let pos = TestNoisePos { x: 0, y: 0, z: 0 };
|
let pos = Vector3 { x: 0, y: 0, z: 0 };
|
||||||
// TODO: Move these values to a file and create an extractor for them
|
// TODO: Move these values to a file and create an extractor for them
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
sample_noise_router_function!(barrier_noise, pos),
|
sample_noise_router_function!(barrier_noise, pos),
|
||||||
@ -307,7 +289,7 @@ fn normal_surface_noisified() {
|
|||||||
((100, 200, 100), 0.0f64),
|
((100, 200, 100), 0.0f64),
|
||||||
];
|
];
|
||||||
for ((x, y, z), value) in values {
|
for ((x, y, z), value) in values {
|
||||||
let pos = TestNoisePos { x, y, z };
|
let pos = Vector3 { x, y, z };
|
||||||
assert_eq!(sample_noise_router_function!(vein_toggle, pos), value);
|
assert_eq!(sample_noise_router_function!(vein_toggle, pos), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -439,7 +421,7 @@ fn normal_surface_noisified() {
|
|||||||
((100, 200, 100), -0.07999999821186066f64),
|
((100, 200, 100), -0.07999999821186066f64),
|
||||||
];
|
];
|
||||||
for ((x, y, z), value) in values {
|
for ((x, y, z), value) in values {
|
||||||
let pos = TestNoisePos { x, y, z };
|
let pos = Vector3 { x, y, z };
|
||||||
assert_eq!(sample_noise_router_function!(vein_ridged, pos), value);
|
assert_eq!(sample_noise_router_function!(vein_ridged, pos), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -571,7 +553,7 @@ fn normal_surface_noisified() {
|
|||||||
((100, 200, 100), 0.3867496985743827f64),
|
((100, 200, 100), 0.3867496985743827f64),
|
||||||
];
|
];
|
||||||
for ((x, y, z), value) in values {
|
for ((x, y, z), value) in values {
|
||||||
let pos = TestNoisePos { x, y, z };
|
let pos = Vector3 { x, y, z };
|
||||||
assert_eq!(sample_noise_router_function!(vein_gap, pos), value);
|
assert_eq!(sample_noise_router_function!(vein_gap, pos), value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -589,7 +571,7 @@ fn config_final_density() {
|
|||||||
|
|
||||||
// This is a lot of data it iter over, one two skip a few done
|
// This is a lot of data it iter over, one two skip a few done
|
||||||
for (x, y, z, sample) in expected_data.into_iter().step_by(5) {
|
for (x, y, z, sample) in expected_data.into_iter().step_by(5) {
|
||||||
let pos = TestNoisePos { x, y, z };
|
let pos = Vector3 { x, y, z };
|
||||||
assert_eq_delta!(
|
assert_eq_delta!(
|
||||||
function.sample(&pos, &TEST_SAMPLE_OPTIONS),
|
function.sample(&pos, &TEST_SAMPLE_OPTIONS),
|
||||||
sample,
|
sample,
|
||||||
@ -659,7 +641,7 @@ fn base_sloped_cheese() {
|
|||||||
let expected_data: Vec<(i32, i32, i32, f64)> =
|
let expected_data: Vec<(i32, i32, i32, f64)> =
|
||||||
read_data_from_file!("../../../../../assets/converted_sloped_cheese_7_4.json");
|
read_data_from_file!("../../../../../assets/converted_sloped_cheese_7_4.json");
|
||||||
for (x, y, z, sample) in expected_data {
|
for (x, y, z, sample) in expected_data {
|
||||||
let pos = TestNoisePos { x, y, z };
|
let pos = Vector3 { x, y, z };
|
||||||
assert_eq_delta!(
|
assert_eq_delta!(
|
||||||
function.sample(&pos, &TEST_SAMPLE_OPTIONS),
|
function.sample(&pos, &TEST_SAMPLE_OPTIONS),
|
||||||
sample,
|
sample,
|
||||||
@ -678,7 +660,7 @@ fn base_factor() {
|
|||||||
let expected_data: Vec<(i32, i32, i32, f64)> =
|
let expected_data: Vec<(i32, i32, i32, f64)> =
|
||||||
read_data_from_file!("../../../../../assets/converted_factor_7_4.json");
|
read_data_from_file!("../../../../../assets/converted_factor_7_4.json");
|
||||||
for (x, y, z, sample) in expected_data {
|
for (x, y, z, sample) in expected_data {
|
||||||
let pos = TestNoisePos { x, y, z };
|
let pos = Vector3 { x, y, z };
|
||||||
assert_eq_delta!(
|
assert_eq_delta!(
|
||||||
function.sample(&pos, &TEST_SAMPLE_OPTIONS),
|
function.sample(&pos, &TEST_SAMPLE_OPTIONS),
|
||||||
sample,
|
sample,
|
||||||
@ -697,7 +679,7 @@ fn base_depth() {
|
|||||||
let expected_data: Vec<(i32, i32, i32, f64)> =
|
let expected_data: Vec<(i32, i32, i32, f64)> =
|
||||||
read_data_from_file!("../../../../../assets/converted_depth_7_4.json");
|
read_data_from_file!("../../../../../assets/converted_depth_7_4.json");
|
||||||
for (x, y, z, sample) in expected_data {
|
for (x, y, z, sample) in expected_data {
|
||||||
let pos = TestNoisePos { x, y, z };
|
let pos = Vector3 { x, y, z };
|
||||||
assert_eq_delta!(
|
assert_eq_delta!(
|
||||||
function.sample(&pos, &TEST_SAMPLE_OPTIONS),
|
function.sample(&pos, &TEST_SAMPLE_OPTIONS),
|
||||||
sample,
|
sample,
|
||||||
@ -716,7 +698,7 @@ fn base_offset() {
|
|||||||
let expected_data: Vec<(i32, i32, i32, f64)> =
|
let expected_data: Vec<(i32, i32, i32, f64)> =
|
||||||
read_data_from_file!("../../../../../assets/converted_offset_7_4.json");
|
read_data_from_file!("../../../../../assets/converted_offset_7_4.json");
|
||||||
for (x, y, z, sample) in expected_data {
|
for (x, y, z, sample) in expected_data {
|
||||||
let pos = TestNoisePos { x, y, z };
|
let pos = Vector3 { x, y, z };
|
||||||
assert_eq_delta!(
|
assert_eq_delta!(
|
||||||
function.sample(&pos, &TEST_SAMPLE_OPTIONS),
|
function.sample(&pos, &TEST_SAMPLE_OPTIONS),
|
||||||
sample,
|
sample,
|
||||||
@ -735,7 +717,7 @@ fn base_cave_entrances() {
|
|||||||
let expected_data: Vec<(i32, i32, i32, f64)> =
|
let expected_data: Vec<(i32, i32, i32, f64)> =
|
||||||
read_data_from_file!("../../../../../assets/converted_cave_entrances_overworld_7_4.json");
|
read_data_from_file!("../../../../../assets/converted_cave_entrances_overworld_7_4.json");
|
||||||
for (x, y, z, sample) in expected_data {
|
for (x, y, z, sample) in expected_data {
|
||||||
let pos = TestNoisePos { x, y, z };
|
let pos = Vector3 { x, y, z };
|
||||||
assert_eq_delta!(
|
assert_eq_delta!(
|
||||||
function.sample(&pos, &TEST_SAMPLE_OPTIONS),
|
function.sample(&pos, &TEST_SAMPLE_OPTIONS),
|
||||||
sample,
|
sample,
|
||||||
@ -754,7 +736,7 @@ fn base_3d_noise() {
|
|||||||
let expected_data: Vec<(i32, i32, i32, f64)> =
|
let expected_data: Vec<(i32, i32, i32, f64)> =
|
||||||
read_data_from_file!("../../../../../assets/converted_3d_overworld_7_4.json");
|
read_data_from_file!("../../../../../assets/converted_3d_overworld_7_4.json");
|
||||||
for (x, y, z, sample) in expected_data {
|
for (x, y, z, sample) in expected_data {
|
||||||
let pos = TestNoisePos { x, y, z };
|
let pos = Vector3 { x, y, z };
|
||||||
assert_eq_delta!(
|
assert_eq_delta!(
|
||||||
function.sample(&pos, &TEST_SAMPLE_OPTIONS),
|
function.sample(&pos, &TEST_SAMPLE_OPTIONS),
|
||||||
sample,
|
sample,
|
||||||
@ -776,7 +758,7 @@ fn base_spahetti_roughness() {
|
|||||||
"../../../../../assets/converted_cave_spaghetti_rough_overworld_7_4.json"
|
"../../../../../assets/converted_cave_spaghetti_rough_overworld_7_4.json"
|
||||||
);
|
);
|
||||||
for (x, y, z, sample) in expected_data {
|
for (x, y, z, sample) in expected_data {
|
||||||
let pos = TestNoisePos { x, y, z };
|
let pos = Vector3 { x, y, z };
|
||||||
assert_eq_delta!(
|
assert_eq_delta!(
|
||||||
function.sample(&pos, &TEST_SAMPLE_OPTIONS),
|
function.sample(&pos, &TEST_SAMPLE_OPTIONS),
|
||||||
sample,
|
sample,
|
||||||
@ -795,7 +777,7 @@ fn base_cave_noodle() {
|
|||||||
let expected_data: Vec<(i32, i32, i32, f64)> =
|
let expected_data: Vec<(i32, i32, i32, f64)> =
|
||||||
read_data_from_file!("../../../../../assets/converted_cave_noodle_7_4.json");
|
read_data_from_file!("../../../../../assets/converted_cave_noodle_7_4.json");
|
||||||
for (x, y, z, sample) in expected_data {
|
for (x, y, z, sample) in expected_data {
|
||||||
let pos = TestNoisePos { x, y, z };
|
let pos = Vector3 { x, y, z };
|
||||||
assert_eq_delta!(
|
assert_eq_delta!(
|
||||||
function.sample(&pos, &TEST_SAMPLE_OPTIONS),
|
function.sample(&pos, &TEST_SAMPLE_OPTIONS),
|
||||||
sample,
|
sample,
|
||||||
@ -814,7 +796,7 @@ fn base_cave_pillars() {
|
|||||||
let expected_data: Vec<(i32, i32, i32, f64)> =
|
let expected_data: Vec<(i32, i32, i32, f64)> =
|
||||||
read_data_from_file!("../../../../../assets/converted_cave_pillar_7_4.json");
|
read_data_from_file!("../../../../../assets/converted_cave_pillar_7_4.json");
|
||||||
for (x, y, z, sample) in expected_data {
|
for (x, y, z, sample) in expected_data {
|
||||||
let pos = TestNoisePos { x, y, z };
|
let pos = Vector3 { x, y, z };
|
||||||
assert_eq_delta!(
|
assert_eq_delta!(
|
||||||
function.sample(&pos, &TEST_SAMPLE_OPTIONS),
|
function.sample(&pos, &TEST_SAMPLE_OPTIONS),
|
||||||
sample,
|
sample,
|
||||||
@ -835,7 +817,7 @@ fn base_spaghetti_2d_thickness() {
|
|||||||
let expected_data: Vec<(i32, i32, i32, f64)> =
|
let expected_data: Vec<(i32, i32, i32, f64)> =
|
||||||
read_data_from_file!("../../../../../assets/converted_cave_spaghetti_2d_thicc_7_4.json");
|
read_data_from_file!("../../../../../assets/converted_cave_spaghetti_2d_thicc_7_4.json");
|
||||||
for (x, y, z, sample) in expected_data {
|
for (x, y, z, sample) in expected_data {
|
||||||
let pos = TestNoisePos { x, y, z };
|
let pos = Vector3 { x, y, z };
|
||||||
assert_eq_delta!(
|
assert_eq_delta!(
|
||||||
function.sample(&pos, &TEST_SAMPLE_OPTIONS),
|
function.sample(&pos, &TEST_SAMPLE_OPTIONS),
|
||||||
sample,
|
sample,
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
use pumpkin_data::noise_router::WrapperType;
|
use pumpkin_data::noise_router::WrapperType;
|
||||||
|
use pumpkin_util::math::vector3::Vector3;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
biome::multi_noise::{NoiseValuePoint, to_long},
|
biome::multi_noise::{NoiseValuePoint, to_long},
|
||||||
@ -11,7 +12,7 @@ use super::{
|
|||||||
SampleAction,
|
SampleAction,
|
||||||
},
|
},
|
||||||
chunk_noise_router::ChunkNoiseFunctionComponent,
|
chunk_noise_router::ChunkNoiseFunctionComponent,
|
||||||
density_function::{NoiseFunctionComponentRange, PassThrough, UnblendedNoisePos},
|
density_function::{NoiseFunctionComponentRange, PassThrough},
|
||||||
proto_noise_router::{ProtoMultiNoiseRouter, ProtoNoiseFunctionComponent},
|
proto_noise_router::{ProtoMultiNoiseRouter, ProtoNoiseFunctionComponent},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -52,7 +53,7 @@ impl<'a> MultiNoiseSampler<'a> {
|
|||||||
let block_y = biome_coords::to_block(biome_y);
|
let block_y = biome_coords::to_block(biome_y);
|
||||||
let block_z = biome_coords::to_block(biome_z);
|
let block_z = biome_coords::to_block(biome_z);
|
||||||
|
|
||||||
let pos = UnblendedNoisePos::new(block_x, block_y, block_z);
|
let pos = Vector3::new(block_x, block_y, block_z);
|
||||||
let sample_options =
|
let sample_options =
|
||||||
ChunkNoiseFunctionSampleOptions::new(false, SampleAction::SkipCellCaches, 0, 0, 0);
|
ChunkNoiseFunctionSampleOptions::new(false, SampleAction::SkipCellCaches, 0, 0, 0);
|
||||||
|
|
||||||
@ -103,7 +104,7 @@ impl<'a> MultiNoiseSampler<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn sample_erosion(&mut self, block_x: i32, block_y: i32, block_z: i32) -> f64 {
|
pub fn sample_erosion(&mut self, block_x: i32, block_y: i32, block_z: i32) -> f64 {
|
||||||
let pos = UnblendedNoisePos::new(block_x, block_y, block_z);
|
let pos = Vector3::new(block_x, block_y, block_z);
|
||||||
let sample_options =
|
let sample_options =
|
||||||
ChunkNoiseFunctionSampleOptions::new(false, SampleAction::SkipCellCaches, 0, 0, 0);
|
ChunkNoiseFunctionSampleOptions::new(false, SampleAction::SkipCellCaches, 0, 0, 0);
|
||||||
|
|
||||||
@ -178,11 +179,7 @@ impl<'a> MultiNoiseSampler<'a> {
|
|||||||
let block_z_position =
|
let block_z_position =
|
||||||
biome_coords::to_block(absolute_biome_z_position);
|
biome_coords::to_block(absolute_biome_z_position);
|
||||||
|
|
||||||
let pos = UnblendedNoisePos::new(
|
let pos = Vector3::new(block_x_position, 0, block_z_position);
|
||||||
block_x_position,
|
|
||||||
0,
|
|
||||||
block_z_position,
|
|
||||||
);
|
|
||||||
|
|
||||||
//NOTE: Due to our stack invariant, what is on the stack is a
|
//NOTE: Due to our stack invariant, what is on the stack is a
|
||||||
// valid density function
|
// valid density function
|
||||||
|
|||||||
@ -14,7 +14,7 @@ use super::{
|
|||||||
chunk_density_function::ChunkNoiseFunctionSampleOptions,
|
chunk_density_function::ChunkNoiseFunctionSampleOptions,
|
||||||
chunk_noise_router::{ChunkNoiseFunctionComponent, StaticChunkNoiseFunctionComponentImpl},
|
chunk_noise_router::{ChunkNoiseFunctionComponent, StaticChunkNoiseFunctionComponentImpl},
|
||||||
density_function::{
|
density_function::{
|
||||||
IndexToNoisePos, NoiseFunctionComponentRange, NoisePos, PassThrough,
|
IndexToNoisePos, NoiseFunctionComponentRange, PassThrough,
|
||||||
StaticIndependentChunkNoiseFunctionComponentImpl, Wrapper,
|
StaticIndependentChunkNoiseFunctionComponentImpl, Wrapper,
|
||||||
math::{Binary, Clamp, Constant, Linear, Unary},
|
math::{Binary, Clamp, Constant, Linear, Unary},
|
||||||
misc::{ClampedYGradient, EndIsland, RangeChoice, WeirdScaled},
|
misc::{ClampedYGradient, EndIsland, RangeChoice, WeirdScaled},
|
||||||
@ -22,6 +22,7 @@ use super::{
|
|||||||
spline::{Spline, SplineFunction, SplinePoint, SplineValue},
|
spline::{Spline, SplineFunction, SplinePoint, SplineValue},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
use pumpkin_util::math::vector3::Vector3;
|
||||||
|
|
||||||
#[enum_dispatch(
|
#[enum_dispatch(
|
||||||
StaticIndependentChunkNoiseFunctionComponentImpl,
|
StaticIndependentChunkNoiseFunctionComponentImpl,
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
use pumpkin_data::noise_router::WrapperType;
|
use pumpkin_data::noise_router::WrapperType;
|
||||||
|
use pumpkin_util::math::vector3::Vector3;
|
||||||
|
use rustc_hash::FxHashMap;
|
||||||
|
|
||||||
use crate::generation::{biome_coords, positions::chunk_pos};
|
use crate::generation::{biome_coords, positions::chunk_pos};
|
||||||
|
|
||||||
@ -10,7 +10,7 @@ use super::{
|
|||||||
SampleAction,
|
SampleAction,
|
||||||
},
|
},
|
||||||
chunk_noise_router::ChunkNoiseFunctionComponent,
|
chunk_noise_router::ChunkNoiseFunctionComponent,
|
||||||
density_function::{NoiseFunctionComponentRange, PassThrough, UnblendedNoisePos},
|
density_function::{NoiseFunctionComponentRange, PassThrough},
|
||||||
proto_noise_router::{ProtoNoiseFunctionComponent, ProtoSurfaceEstimator},
|
proto_noise_router::{ProtoNoiseFunctionComponent, ProtoSurfaceEstimator},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -58,7 +58,7 @@ pub struct SurfaceHeightEstimateSampler<'a> {
|
|||||||
component_stack: Box<[ChunkNoiseFunctionComponent<'a>]>,
|
component_stack: Box<[ChunkNoiseFunctionComponent<'a>]>,
|
||||||
|
|
||||||
// TODO: Can this be a flat map? I think the aquifer sampler samples outside of the chunk
|
// TODO: Can this be a flat map? I think the aquifer sampler samples outside of the chunk
|
||||||
cache: HashMap<u64, i32>,
|
cache: FxHashMap<u64, i32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> SurfaceHeightEstimateSampler<'a> {
|
impl<'a> SurfaceHeightEstimateSampler<'a> {
|
||||||
@ -90,7 +90,7 @@ impl<'a> SurfaceHeightEstimateSampler<'a> {
|
|||||||
let mid = low + ((high - low) / 2);
|
let mid = low + ((high - low) / 2);
|
||||||
let stepped_mid = mid - (mid % self.y_level_step_count as i32);
|
let stepped_mid = mid - (mid % self.y_level_step_count as i32);
|
||||||
|
|
||||||
let pos = UnblendedNoisePos::new(aligned_x, stepped_mid, aligned_z);
|
let pos = Vector3::new(aligned_x, stepped_mid, aligned_z);
|
||||||
let density = ChunkNoiseFunctionComponent::sample_from_stack(
|
let density = ChunkNoiseFunctionComponent::sample_from_stack(
|
||||||
&mut self.component_stack,
|
&mut self.component_stack,
|
||||||
&pos,
|
&pos,
|
||||||
@ -172,11 +172,7 @@ impl<'a> SurfaceHeightEstimateSampler<'a> {
|
|||||||
let block_z_position =
|
let block_z_position =
|
||||||
biome_coords::to_block(absolute_biome_z_position);
|
biome_coords::to_block(absolute_biome_z_position);
|
||||||
|
|
||||||
let pos = UnblendedNoisePos::new(
|
let pos = Vector3::new(block_x_position, 0, block_z_position);
|
||||||
block_x_position,
|
|
||||||
0,
|
|
||||||
block_z_position,
|
|
||||||
);
|
|
||||||
|
|
||||||
//NOTE: Due to our stack invariant, what is on the stack is a
|
//NOTE: Due to our stack invariant, what is on the stack is a
|
||||||
// valid density function
|
// valid density function
|
||||||
@ -216,7 +212,7 @@ impl<'a> SurfaceHeightEstimateSampler<'a> {
|
|||||||
minimum_y: build_options.minimum_y,
|
minimum_y: build_options.minimum_y,
|
||||||
y_level_step_count: build_options.y_level_step_count,
|
y_level_step_count: build_options.y_level_step_count,
|
||||||
|
|
||||||
cache: HashMap::new(),
|
cache: FxHashMap::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
use std::collections::HashMap;
|
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use pumpkin_data::block_properties::is_air;
|
use pumpkin_data::block_properties::is_air;
|
||||||
|
use pumpkin_data::chunk_gen_settings::GenerationSettings;
|
||||||
use pumpkin_data::dimension::Dimension;
|
use pumpkin_data::dimension::Dimension;
|
||||||
use pumpkin_data::fluid::{Fluid, FluidState};
|
use pumpkin_data::fluid::{Fluid, FluidState};
|
||||||
use pumpkin_data::tag;
|
use pumpkin_data::tag;
|
||||||
@ -13,6 +13,7 @@ use pumpkin_util::{
|
|||||||
math::{position::BlockPos, vector3::Vector3},
|
math::{position::BlockPos, vector3::Vector3},
|
||||||
random::{RandomGenerator, get_decorator_seed, xoroshiro128::Xoroshiro},
|
random::{RandomGenerator, get_decorator_seed, xoroshiro128::Xoroshiro},
|
||||||
};
|
};
|
||||||
|
use rustc_hash::FxHashMap;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
GlobalRandomConfig, biome_coords,
|
GlobalRandomConfig, biome_coords,
|
||||||
@ -23,7 +24,6 @@ use super::{
|
|||||||
},
|
},
|
||||||
positions::chunk_pos::{start_block_x, start_block_z},
|
positions::chunk_pos::{start_block_x, start_block_z},
|
||||||
section_coords,
|
section_coords,
|
||||||
settings::GenerationSettings,
|
|
||||||
surface::{MaterialRuleContext, estimate_surface_height, terrain::SurfaceTerrainBuilder},
|
surface::{MaterialRuleContext, estimate_surface_height, terrain::SurfaceTerrainBuilder},
|
||||||
};
|
};
|
||||||
use crate::chunk::{ChunkData, ChunkHeightmapType};
|
use crate::chunk::{ChunkData, ChunkHeightmapType};
|
||||||
@ -38,6 +38,7 @@ use crate::generation::noise::{CHUNK_DIM, ChunkNoiseGenerator, LAVA_BLOCK, WATER
|
|||||||
use crate::generation::structure::placement::StructurePlacementCalculator;
|
use crate::generation::structure::placement::StructurePlacementCalculator;
|
||||||
use crate::generation::structure::structures::StructureInstance;
|
use crate::generation::structure::structures::StructureInstance;
|
||||||
use crate::generation::structure::{STRUCTURE_SETS, STRUCTURES, StructureKeys, WeightedEntry};
|
use crate::generation::structure::{STRUCTURE_SETS, STRUCTURES, StructureKeys, WeightedEntry};
|
||||||
|
use crate::generation::surface::rule::try_apply_material_rule;
|
||||||
use crate::{
|
use crate::{
|
||||||
BlockStateId, ProtoNoiseRouters,
|
BlockStateId, ProtoNoiseRouters,
|
||||||
biome::{BiomeSupplier, MultiNoiseBiomeSupplier, end::TheEndBiomeSupplier},
|
biome::{BiomeSupplier, MultiNoiseBiomeSupplier, end::TheEndBiomeSupplier},
|
||||||
@ -142,7 +143,7 @@ pub struct ProtoChunk {
|
|||||||
flat_ocean_floor_height_map: Box<[i16]>,
|
flat_ocean_floor_height_map: Box<[i16]>,
|
||||||
pub flat_motion_blocking_height_map: Box<[i16]>,
|
pub flat_motion_blocking_height_map: Box<[i16]>,
|
||||||
pub flat_motion_blocking_no_leaves_height_map: Box<[i16]>,
|
pub flat_motion_blocking_no_leaves_height_map: Box<[i16]>,
|
||||||
structure_starts: HashMap<StructureKeys, StructureInstance>,
|
structure_starts: FxHashMap<StructureKeys, StructureInstance>,
|
||||||
|
|
||||||
// Height of the chunk for indexing
|
// Height of the chunk for indexing
|
||||||
height: u16,
|
height: u16,
|
||||||
@ -201,7 +202,7 @@ impl ProtoChunk {
|
|||||||
flat_ocean_floor_height_map: default_heightmap.clone(),
|
flat_ocean_floor_height_map: default_heightmap.clone(),
|
||||||
flat_motion_blocking_height_map: default_heightmap.clone(),
|
flat_motion_blocking_height_map: default_heightmap.clone(),
|
||||||
flat_motion_blocking_no_leaves_height_map: default_heightmap,
|
flat_motion_blocking_no_leaves_height_map: default_heightmap,
|
||||||
structure_starts: HashMap::new(),
|
structure_starts: FxHashMap::default(),
|
||||||
height,
|
height,
|
||||||
bottom_y: dimension.min_y as i8,
|
bottom_y: dimension.min_y as i8,
|
||||||
stage: StagedChunkEnum::Empty,
|
stage: StagedChunkEnum::Empty,
|
||||||
@ -313,45 +314,24 @@ impl ProtoChunk {
|
|||||||
self.bottom_y
|
self.bottom_y
|
||||||
}
|
}
|
||||||
|
|
||||||
fn maybe_update_surface_height_map(&mut self, local_x: i32, y: i32, local_z: i32) {
|
fn maybe_update_surface_height_map(&mut self, index: usize, y: i16) {
|
||||||
let index = Self::local_position_to_height_map_index(local_x, local_z);
|
|
||||||
let current_height = self.flat_surface_height_map[index];
|
let current_height = self.flat_surface_height_map[index];
|
||||||
|
self.flat_surface_height_map[index] = current_height.max(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, local_x: i32, y: i32, local_z: i32) {
|
fn maybe_update_ocean_floor_height_map(&mut self, index: usize, y: i16) {
|
||||||
let index = Self::local_position_to_height_map_index(local_x, local_z);
|
|
||||||
let current_height = self.flat_ocean_floor_height_map[index];
|
let current_height = self.flat_ocean_floor_height_map[index];
|
||||||
|
self.flat_ocean_floor_height_map[index] = current_height.max(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, local_x: i32, y: i32, local_z: i32) {
|
fn maybe_update_motion_blocking_height_map(&mut self, index: usize, y: i16) {
|
||||||
let index = Self::local_position_to_height_map_index(local_x, local_z);
|
|
||||||
let current_height = self.flat_motion_blocking_height_map[index];
|
let current_height = self.flat_motion_blocking_height_map[index];
|
||||||
|
self.flat_motion_blocking_height_map[index] = current_height.max(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(
|
fn maybe_update_motion_blocking_no_leaves_height_map(&mut self, index: usize, y: i16) {
|
||||||
&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];
|
let current_height = self.flat_motion_blocking_no_leaves_height_map[index];
|
||||||
|
self.flat_motion_blocking_no_leaves_height_map[index] = current_height.max(y) as _;
|
||||||
if y > current_height as i32 {
|
|
||||||
self.flat_motion_blocking_no_leaves_height_map[index] = y as _;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
@ -407,13 +387,10 @@ impl ProtoChunk {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn local_pos_to_block_index(&self, x: i32, y: i32, z: i32) -> usize {
|
fn local_pos_to_block_index(&self, x: i32, y: i32, z: i32) -> usize {
|
||||||
#[cfg(debug_assertions)]
|
debug_assert!((0..16).contains(&x), "x out of bounds: {}", x);
|
||||||
{
|
debug_assert!((0..16).contains(&z), "z out of bounds: {}", z);
|
||||||
assert!((0..=15).contains(&x));
|
debug_assert!(y >= 0 && y < self.height() as i32, "y out of bounds: {}", y);
|
||||||
assert!(y < self.height() as i32);
|
|
||||||
assert!(y >= 0);
|
|
||||||
assert!((0..=15).contains(&z));
|
|
||||||
};
|
|
||||||
self.height() as usize * CHUNK_DIM as usize * x as usize
|
self.height() as usize * CHUNK_DIM as usize * x as usize
|
||||||
+ CHUNK_DIM as usize * y as usize
|
+ CHUNK_DIM as usize * y as usize
|
||||||
+ z as usize
|
+ z as usize
|
||||||
@ -422,22 +399,17 @@ impl ProtoChunk {
|
|||||||
#[inline]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn local_biome_pos_to_biome_index(&self, x: i32, y: i32, z: i32) -> usize {
|
pub fn local_biome_pos_to_biome_index(&self, x: i32, y: i32, z: i32) -> usize {
|
||||||
#[cfg(debug_assertions)]
|
let biome_height = self.height() as usize >> 2;
|
||||||
{
|
|
||||||
assert!((0..=3).contains(&x));
|
debug_assert!((0..4).contains(&x), "Biome X out of bounds: {}", x);
|
||||||
assert!(
|
debug_assert!((0..4).contains(&z), "Biome Z out of bounds: {}", z);
|
||||||
y < biome_coords::from_chunk(self.height() as i32) && y >= 0,
|
debug_assert!(
|
||||||
"{} - {} vs {}",
|
y >= 0 && y < biome_height as i32,
|
||||||
0,
|
"Biome Y out of bounds: {}",
|
||||||
biome_coords::from_chunk(self.height() as i32),
|
|
||||||
y
|
y
|
||||||
);
|
);
|
||||||
assert!((0..=3).contains(&z));
|
|
||||||
};
|
|
||||||
|
|
||||||
biome_coords::from_block(self.height() as usize)
|
biome_height * biome_coords::from_block(CHUNK_DIM as usize) * x as usize
|
||||||
* biome_coords::from_block(CHUNK_DIM as usize)
|
|
||||||
* x as usize
|
|
||||||
+ biome_coords::from_block(CHUNK_DIM as usize) * y as usize
|
+ biome_coords::from_block(CHUNK_DIM as usize) * y as usize
|
||||||
+ z as usize
|
+ z as usize
|
||||||
}
|
}
|
||||||
@ -474,18 +446,20 @@ impl ProtoChunk {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if !block_state.is_air() {
|
if !block_state.is_air() {
|
||||||
self.maybe_update_surface_height_map(local_x, y, local_z);
|
let index = Self::local_position_to_height_map_index(local_x, local_z);
|
||||||
|
let y = y as i16;
|
||||||
|
self.maybe_update_surface_height_map(index, y);
|
||||||
let block = Block::get_raw_id_from_state_id(block_state.id);
|
let block = Block::get_raw_id_from_state_id(block_state.id);
|
||||||
|
|
||||||
let blocks_movement = blocks_movement(block_state, block);
|
let blocks_movement = blocks_movement(block_state, block);
|
||||||
if blocks_movement {
|
if blocks_movement {
|
||||||
self.maybe_update_ocean_floor_height_map(local_x, y, local_z);
|
self.maybe_update_ocean_floor_height_map(index, y);
|
||||||
}
|
}
|
||||||
if blocks_movement || block_state.is_liquid() {
|
if blocks_movement || block_state.is_liquid() {
|
||||||
self.maybe_update_motion_blocking_height_map(local_x, y, local_z);
|
self.maybe_update_motion_blocking_height_map(index, y);
|
||||||
if !tag::Block::MINECRAFT_LEAVES.1.contains(&block) {
|
if !tag::Block::MINECRAFT_LEAVES.1.contains(&block) {
|
||||||
{
|
{
|
||||||
self.maybe_update_motion_blocking_no_leaves_height_map(local_x, y, local_z);
|
self.maybe_update_motion_blocking_no_leaves_height_map(index, y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -542,7 +516,10 @@ impl ProtoChunk {
|
|||||||
let start_z = start_block_z(self.z);
|
let start_z = start_block_z(self.z);
|
||||||
|
|
||||||
let sampler = FluidLevelSampler::Chunk(StandardChunkFluidLevelSampler::new(
|
let sampler = FluidLevelSampler::Chunk(StandardChunkFluidLevelSampler::new(
|
||||||
FluidLevel::new(settings.sea_level, settings.default_fluid.name),
|
FluidLevel::new(
|
||||||
|
settings.sea_level,
|
||||||
|
Block::from_registry_key(settings.default_fluid.name).unwrap(),
|
||||||
|
),
|
||||||
FluidLevel::new(-54, &Block::LAVA),
|
FluidLevel::new(-54, &Block::LAVA),
|
||||||
));
|
));
|
||||||
|
|
||||||
@ -873,7 +850,8 @@ impl ProtoChunk {
|
|||||||
context.block_pos_y,
|
context.block_pos_y,
|
||||||
context.block_pos_z,
|
context.block_pos_z,
|
||||||
);
|
);
|
||||||
let new_state = settings.surface_rule.try_apply(
|
let new_state = try_apply_material_rule(
|
||||||
|
&settings.surface_rule,
|
||||||
self,
|
self,
|
||||||
&mut context,
|
&mut context,
|
||||||
surface_height_estimate_sampler,
|
surface_height_estimate_sampler,
|
||||||
|
|||||||
@ -1,104 +1,104 @@
|
|||||||
use std::{collections::HashMap, sync::LazyLock};
|
// use std::{collections::HashMap, sync::LazyLock};
|
||||||
|
|
||||||
use pumpkin_data::dimension::Dimension;
|
// use pumpkin_data::dimension::Dimension;
|
||||||
use pumpkin_util::include_json_static;
|
// use pumpkin_util::include_json_static;
|
||||||
use serde::Deserialize;
|
// use serde::Deserialize;
|
||||||
|
|
||||||
use crate::block::BlockStateCodec;
|
// use crate::block::BlockStateCodec;
|
||||||
|
|
||||||
use super::{biome_coords::to_block, height_limit::HeightLimitView, surface::rule::MaterialRule};
|
// use super::{biome_coords::to_block, height_limit::HeightLimitView, surface::rule::MaterialRule};
|
||||||
|
|
||||||
pub static GENERATION_SETTINGS: LazyLock<HashMap<GeneratorSetting, GenerationSettings>> =
|
// pub static GENERATION_SETTINGS: LazyLock<HashMap<GeneratorSetting, GenerationSettings>> =
|
||||||
LazyLock::new(
|
// LazyLock::new(
|
||||||
|| include_json_static!("../../../assets/chunk_gen_settings.json", HashMap<GeneratorSetting, GenerationSettings>),
|
// || include_json_static!("../../../assets/chunk_gen_settings.json", HashMap<GeneratorSetting, GenerationSettings>),
|
||||||
);
|
// );
|
||||||
|
|
||||||
pub fn gen_settings_from_dimension(dimension: &Dimension) -> &GenerationSettings {
|
// pub fn gen_settings_from_dimension(dimension: &Dimension) -> &GenerationSettings {
|
||||||
let setting = if dimension == &Dimension::OVERWORLD {
|
// let setting = if dimension == &Dimension::OVERWORLD {
|
||||||
GeneratorSetting::Overworld
|
// GeneratorSetting::Overworld
|
||||||
} else if dimension == &Dimension::THE_NETHER {
|
// } else if dimension == &Dimension::THE_NETHER {
|
||||||
GeneratorSetting::Nether
|
// GeneratorSetting::Nether
|
||||||
} else {
|
// } else {
|
||||||
GeneratorSetting::End
|
// GeneratorSetting::End
|
||||||
};
|
// };
|
||||||
GENERATION_SETTINGS.get(&setting).unwrap()
|
// GENERATION_SETTINGS.get(&setting).unwrap()
|
||||||
}
|
// }
|
||||||
|
|
||||||
#[derive(Deserialize, Hash, PartialEq, Eq)]
|
// #[derive(Deserialize, Hash, PartialEq, Eq)]
|
||||||
#[serde(rename_all = "snake_case")]
|
// #[serde(rename_all = "snake_case")]
|
||||||
pub enum GeneratorSetting {
|
// pub enum GeneratorSetting {
|
||||||
Overworld,
|
// Overworld,
|
||||||
LargeBiomes,
|
// LargeBiomes,
|
||||||
Amplified,
|
// Amplified,
|
||||||
Nether,
|
// Nether,
|
||||||
End,
|
// End,
|
||||||
Caves,
|
// Caves,
|
||||||
FloatingIslands,
|
// FloatingIslands,
|
||||||
}
|
// }
|
||||||
#[derive(Deserialize)]
|
// #[derive(Deserialize)]
|
||||||
pub struct GenerationSettings {
|
// pub struct GenerationSettings {
|
||||||
pub aquifers_enabled: bool,
|
// pub aquifers_enabled: bool,
|
||||||
pub ore_veins_enabled: bool,
|
// pub ore_veins_enabled: bool,
|
||||||
pub legacy_random_source: bool,
|
// pub legacy_random_source: bool,
|
||||||
pub sea_level: i32,
|
// pub sea_level: i32,
|
||||||
pub default_fluid: BlockStateCodec,
|
// pub default_fluid: BlockStateCodec,
|
||||||
#[serde(rename = "noise")]
|
// #[serde(rename = "noise")]
|
||||||
pub shape: GenerationShapeConfig,
|
// pub shape: GenerationShapeConfig,
|
||||||
pub surface_rule: MaterialRule,
|
// pub surface_rule: MaterialRule,
|
||||||
pub default_block: BlockStateCodec,
|
// pub default_block: BlockStateCodec,
|
||||||
}
|
// }
|
||||||
#[derive(Deserialize)]
|
// #[derive(Deserialize)]
|
||||||
pub struct GenerationShapeConfig {
|
// pub struct GenerationShapeConfig {
|
||||||
pub min_y: i8,
|
// pub min_y: i8,
|
||||||
pub height: u16,
|
// pub height: u16,
|
||||||
size_horizontal: u8,
|
// size_horizontal: u8,
|
||||||
size_vertical: u8,
|
// size_vertical: u8,
|
||||||
}
|
// }
|
||||||
|
|
||||||
impl GenerationShapeConfig {
|
// impl GenerationShapeConfig {
|
||||||
#[inline]
|
// #[inline]
|
||||||
#[must_use]
|
// #[must_use]
|
||||||
pub fn vertical_cell_block_count(&self) -> u8 {
|
// pub fn vertical_cell_block_count(&self) -> u8 {
|
||||||
to_block(self.size_vertical)
|
// to_block(self.size_vertical)
|
||||||
}
|
// }
|
||||||
|
|
||||||
#[inline]
|
// #[inline]
|
||||||
#[must_use]
|
// #[must_use]
|
||||||
pub fn horizontal_cell_block_count(&self) -> u8 {
|
// pub fn horizontal_cell_block_count(&self) -> u8 {
|
||||||
to_block(self.size_horizontal)
|
// to_block(self.size_horizontal)
|
||||||
}
|
// }
|
||||||
|
|
||||||
#[must_use]
|
// #[must_use]
|
||||||
pub const fn max_y(&self) -> u16 {
|
// pub const fn max_y(&self) -> u16 {
|
||||||
if self.min_y >= 0 {
|
// if self.min_y >= 0 {
|
||||||
self.height + self.min_y as u16
|
// self.height + self.min_y as u16
|
||||||
} else {
|
// } else {
|
||||||
(self.height as i32 + self.min_y as i32) as u16
|
// (self.height as i32 + self.min_y as i32) as u16
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
pub fn trim_height(&self, limit: &dyn HeightLimitView) -> Self {
|
// pub fn trim_height(&self, limit: &dyn HeightLimitView) -> Self {
|
||||||
let new_min = self.min_y.max(limit.bottom_y());
|
// let new_min = self.min_y.max(limit.bottom_y());
|
||||||
|
|
||||||
let this_top = if self.min_y >= 0 {
|
// let this_top = if self.min_y >= 0 {
|
||||||
self.height + self.min_y as u16
|
// self.height + self.min_y as u16
|
||||||
} else {
|
// } else {
|
||||||
self.height - self.min_y.unsigned_abs() as u16
|
// self.height - self.min_y.unsigned_abs() as u16
|
||||||
};
|
// };
|
||||||
|
|
||||||
let new_top = this_top.min(limit.top_y());
|
// let new_top = this_top.min(limit.top_y());
|
||||||
|
|
||||||
let new_height = if new_min >= 0 {
|
// let new_height = if new_min >= 0 {
|
||||||
new_top - new_min as u16
|
// new_top - new_min as u16
|
||||||
} else {
|
// } else {
|
||||||
new_top + new_min.unsigned_abs() as u16
|
// new_top + new_min.unsigned_abs() as u16
|
||||||
};
|
// };
|
||||||
|
|
||||||
Self {
|
// Self {
|
||||||
min_y: new_min,
|
// min_y: new_min,
|
||||||
height: new_height,
|
// height: new_height,
|
||||||
size_horizontal: self.size_horizontal,
|
// size_horizontal: self.size_horizontal,
|
||||||
size_vertical: self.size_vertical,
|
// size_vertical: self.size_vertical,
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|||||||
@ -321,7 +321,7 @@ impl StructurePiece {
|
|||||||
let block_pos = self.offset_pos(x, y, z);
|
let block_pos = self.offset_pos(x, y, z);
|
||||||
|
|
||||||
if !box_limit.contains_pos(&block_pos) {
|
if !box_limit.contains_pos(&block_pos) {
|
||||||
log::warn!("Structure out of bounds");
|
log::debug!("Structure out of bounds");
|
||||||
return Block::AIR.default_state;
|
return Block::AIR.default_state;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -341,7 +341,7 @@ impl StructurePiece {
|
|||||||
|
|
||||||
// Bounds and logic checks
|
// Bounds and logic checks
|
||||||
if !box_limit.contains_pos(&block_pos) {
|
if !box_limit.contains_pos(&block_pos) {
|
||||||
log::warn!("Structure out of bounds");
|
log::debug!("Structure out of bounds");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,11 @@
|
|||||||
use std::{cell::RefCell, num::NonZeroUsize};
|
use pumpkin_data::{
|
||||||
|
chunk::Biome,
|
||||||
use lru::LruCache;
|
chunk_gen_settings::{
|
||||||
use pumpkin_data::chunk::Biome;
|
AboveYMaterialCondition, MaterialCondition, NoiseThresholdMaterialCondition,
|
||||||
|
NotMaterialCondition, StoneDepthMaterialCondition, VerticalGradientMaterialCondition,
|
||||||
|
WaterMaterialCondition,
|
||||||
|
},
|
||||||
|
};
|
||||||
use pumpkin_util::{
|
use pumpkin_util::{
|
||||||
math::{lerp2, vertical_surface_type::VerticalSurfaceType},
|
math::{lerp2, vertical_surface_type::VerticalSurfaceType},
|
||||||
random::{RandomDeriver, RandomDeriverImpl, RandomImpl},
|
random::{RandomDeriver, RandomDeriverImpl, RandomImpl},
|
||||||
@ -9,7 +13,6 @@ use pumpkin_util::{
|
|||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
use terrain::SurfaceTerrainBuilder;
|
use terrain::SurfaceTerrainBuilder;
|
||||||
use thread_local::ThreadLocal;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ProtoChunk,
|
ProtoChunk,
|
||||||
@ -22,7 +25,6 @@ use super::{
|
|||||||
proto_noise_router::DoublePerlinNoiseBuilder,
|
proto_noise_router::DoublePerlinNoiseBuilder,
|
||||||
surface_height_sampler::SurfaceHeightEstimateSampler,
|
surface_height_sampler::SurfaceHeightEstimateSampler,
|
||||||
},
|
},
|
||||||
y_offset::YOffset,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub mod rule;
|
pub mod rule;
|
||||||
@ -138,49 +140,24 @@ impl<'a> MaterialRuleContext<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
#[serde(tag = "type")]
|
|
||||||
#[serde(rename_all = "snake_case")]
|
|
||||||
pub enum MaterialCondition {
|
|
||||||
#[serde(rename = "minecraft:biome")]
|
|
||||||
Biome(BiomeMaterialCondition),
|
|
||||||
#[serde(rename = "minecraft:noise_threshold")]
|
|
||||||
NoiseThreshold(NoiseThresholdMaterialCondition),
|
|
||||||
#[serde(rename = "minecraft:vertical_gradient")]
|
|
||||||
VerticalGradient(Box<VerticalGradientMaterialCondition>),
|
|
||||||
#[serde(rename = "minecraft:y_above")]
|
|
||||||
YAbove(AboveYMaterialCondition),
|
|
||||||
#[serde(rename = "minecraft:water")]
|
|
||||||
Water(WaterMaterialCondition),
|
|
||||||
#[serde(rename = "minecraft:temperature")]
|
|
||||||
Temperature,
|
|
||||||
#[serde(rename = "minecraft:steep")]
|
|
||||||
Steep,
|
|
||||||
#[serde(rename = "minecraft:not")]
|
|
||||||
Not(NotMaterialCondition),
|
|
||||||
#[serde(rename = "minecraft:hole")]
|
|
||||||
Hole(HoleMaterialCondition),
|
|
||||||
#[serde(rename = "minecraft:above_preliminary_surface")]
|
|
||||||
AbovePreliminarySurface(SurfaceMaterialCondition),
|
|
||||||
#[serde(rename = "minecraft:stone_depth")]
|
|
||||||
StoneDepth(StoneDepthMaterialCondition),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MaterialCondition {
|
|
||||||
#[expect(clippy::similar_names)]
|
#[expect(clippy::similar_names)]
|
||||||
pub fn test(
|
pub fn test_condition(
|
||||||
&self,
|
condition: &MaterialCondition,
|
||||||
chunk: &mut ProtoChunk,
|
chunk: &mut ProtoChunk,
|
||||||
context: &mut MaterialRuleContext,
|
context: &mut MaterialRuleContext,
|
||||||
surface_height_estimate_sampler: &mut SurfaceHeightEstimateSampler,
|
surface_height_estimate_sampler: &mut SurfaceHeightEstimateSampler,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
match self {
|
match condition {
|
||||||
Self::Biome(biome) => biome.test(context),
|
MaterialCondition::Biome(biome) => BiomeMaterialCondition::test(biome.biome_is, context),
|
||||||
Self::NoiseThreshold(noise_threshold) => noise_threshold.test(context),
|
MaterialCondition::NoiseThreshold(noise_threshold) => {
|
||||||
Self::VerticalGradient(vertical_gradient) => vertical_gradient.test(context),
|
test_noise_threshold(noise_threshold, context)
|
||||||
Self::YAbove(above_y) => above_y.test(context),
|
}
|
||||||
Self::Water(water) => water.test(context),
|
MaterialCondition::VerticalGradient(vertical_gradient) => {
|
||||||
Self::Temperature => {
|
test_vertical_gradient(vertical_gradient, context)
|
||||||
|
}
|
||||||
|
MaterialCondition::YAbove(above_y) => test_above_y_material(above_y, context),
|
||||||
|
MaterialCondition::Water(water) => test_water_material(water, context),
|
||||||
|
MaterialCondition::Temperature => {
|
||||||
let temperature = context.biome.weather.compute_temperature(
|
let temperature = context.biome.weather.compute_temperature(
|
||||||
context.block_pos_x as f64,
|
context.block_pos_x as f64,
|
||||||
context.block_pos_y,
|
context.block_pos_y,
|
||||||
@ -189,7 +166,7 @@ impl MaterialCondition {
|
|||||||
);
|
);
|
||||||
temperature < 0.15f32
|
temperature < 0.15f32
|
||||||
}
|
}
|
||||||
Self::Steep => {
|
MaterialCondition::Steep => {
|
||||||
let local_x = context.block_pos_x & 15;
|
let local_x = context.block_pos_x & 15;
|
||||||
let local_z = context.block_pos_z & 15;
|
let local_z = context.block_pos_z & 15;
|
||||||
|
|
||||||
@ -211,13 +188,14 @@ impl MaterialCondition {
|
|||||||
sub_height >= add_height + 4
|
sub_height >= add_height + 4
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Self::Not(not) => not.test(chunk, context, surface_height_estimate_sampler),
|
MaterialCondition::Not(not) => {
|
||||||
Self::Hole(_hole) => HoleMaterialCondition::test(context),
|
test_not_material(not, chunk, context, surface_height_estimate_sampler)
|
||||||
Self::AbovePreliminarySurface(_above) => {
|
}
|
||||||
|
MaterialCondition::Hole(_hole) => HoleMaterialCondition::test(context),
|
||||||
|
MaterialCondition::AbovePreliminarySurface(_above) => {
|
||||||
SurfaceMaterialCondition::test(context, surface_height_estimate_sampler)
|
SurfaceMaterialCondition::test(context, surface_height_estimate_sampler)
|
||||||
}
|
}
|
||||||
Self::StoneDepth(stone_depth) => stone_depth.test(context),
|
MaterialCondition::StoneDepth(stone_depth) => test_stone_depth(stone_depth, context),
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -230,42 +208,32 @@ impl HoleMaterialCondition {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
pub const fn test_above_y_material(
|
||||||
pub struct AboveYMaterialCondition {
|
condition: &AboveYMaterialCondition,
|
||||||
anchor: YOffset,
|
context: &MaterialRuleContext,
|
||||||
surface_depth_multiplier: i32,
|
) -> bool {
|
||||||
add_stone_depth: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AboveYMaterialCondition {
|
|
||||||
pub const fn test(&self, context: &MaterialRuleContext) -> bool {
|
|
||||||
context.block_pos_y
|
context.block_pos_y
|
||||||
+ if self.add_stone_depth {
|
+ if condition.add_stone_depth {
|
||||||
context.stone_depth_above
|
context.stone_depth_above
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
>= self.anchor.get_y(context.min_y as i16, context.height)
|
>= condition.anchor.get_y(context.min_y as i16, context.height)
|
||||||
+ context.run_depth * self.surface_depth_multiplier
|
+ context.run_depth * condition.surface_depth_multiplier
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
pub fn test_not_material(
|
||||||
pub struct NotMaterialCondition {
|
condition: &NotMaterialCondition,
|
||||||
invert: Box<MaterialCondition>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl NotMaterialCondition {
|
|
||||||
pub fn test(
|
|
||||||
&self,
|
|
||||||
chunk: &mut ProtoChunk,
|
chunk: &mut ProtoChunk,
|
||||||
context: &mut MaterialRuleContext,
|
context: &mut MaterialRuleContext,
|
||||||
surface_height_estimate_sampler: &mut SurfaceHeightEstimateSampler,
|
surface_height_estimate_sampler: &mut SurfaceHeightEstimateSampler,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
!self
|
!test_condition(
|
||||||
.invert
|
condition.invert,
|
||||||
.test(chunk, context, surface_height_estimate_sampler)
|
chunk,
|
||||||
}
|
context,
|
||||||
|
surface_height_estimate_sampler,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
@ -324,54 +292,40 @@ pub fn estimate_surface_height(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct BiomeMaterialCondition {
|
pub struct BiomeMaterialCondition;
|
||||||
biome_is: Box<[&'static Biome]>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BiomeMaterialCondition {
|
impl BiomeMaterialCondition {
|
||||||
pub fn test(&self, context: &MaterialRuleContext) -> bool {
|
pub fn test(biome_is: &[&'static Biome], context: &MaterialRuleContext) -> bool {
|
||||||
self.biome_is.contains(&context.biome)
|
biome_is.contains(&context.biome)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
pub fn test_noise_threshold(
|
||||||
pub struct NoiseThresholdMaterialCondition {
|
condition: &NoiseThresholdMaterialCondition,
|
||||||
noise: String,
|
context: &mut MaterialRuleContext,
|
||||||
min_threshold: f64,
|
) -> bool {
|
||||||
max_threshold: f64,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl NoiseThresholdMaterialCondition {
|
|
||||||
pub fn test(&self, context: &mut MaterialRuleContext) -> bool {
|
|
||||||
// TODO: we want to cache these
|
// TODO: we want to cache these
|
||||||
let sampler = context
|
let sampler = context
|
||||||
.noise_builder
|
.noise_builder
|
||||||
.get_noise_sampler_for_id(self.noise.strip_prefix("minecraft:").unwrap());
|
.get_noise_sampler_for_id(condition.noise.strip_prefix("minecraft:").unwrap());
|
||||||
let value = sampler.sample(context.block_pos_x as f64, 0.0, context.block_pos_z as f64);
|
let value = sampler.sample(context.block_pos_x as f64, 0.0, context.block_pos_z as f64);
|
||||||
value >= self.min_threshold && value <= self.max_threshold
|
value >= condition.min_threshold && value <= condition.max_threshold
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
pub fn test_stone_depth(
|
||||||
pub struct StoneDepthMaterialCondition {
|
condition: &StoneDepthMaterialCondition,
|
||||||
offset: i32,
|
context: &mut MaterialRuleContext,
|
||||||
add_surface_depth: bool,
|
) -> bool {
|
||||||
secondary_depth_range: i32,
|
let stone_depth = match &condition.surface_type {
|
||||||
surface_type: VerticalSurfaceType,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl StoneDepthMaterialCondition {
|
|
||||||
pub fn test(&self, context: &mut MaterialRuleContext) -> bool {
|
|
||||||
let stone_depth = match &self.surface_type {
|
|
||||||
VerticalSurfaceType::Ceiling => context.stone_depth_below,
|
VerticalSurfaceType::Ceiling => context.stone_depth_below,
|
||||||
VerticalSurfaceType::Floor => context.stone_depth_above,
|
VerticalSurfaceType::Floor => context.stone_depth_above,
|
||||||
};
|
};
|
||||||
let depth = if self.add_surface_depth {
|
let depth = if condition.add_surface_depth {
|
||||||
context.run_depth
|
context.run_depth
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
};
|
};
|
||||||
let depth_range = if self.secondary_depth_range == 0 {
|
let depth_range = if condition.secondary_depth_range == 0 {
|
||||||
0
|
0
|
||||||
} else {
|
} else {
|
||||||
pumpkin_util::math::map(
|
pumpkin_util::math::map(
|
||||||
@ -379,71 +333,45 @@ impl StoneDepthMaterialCondition {
|
|||||||
-1.0,
|
-1.0,
|
||||||
1.0,
|
1.0,
|
||||||
0.0,
|
0.0,
|
||||||
self.secondary_depth_range as f64,
|
condition.secondary_depth_range as f64,
|
||||||
) as i32
|
) as i32
|
||||||
};
|
};
|
||||||
stone_depth <= 1 + self.offset + depth + depth_range
|
stone_depth <= 1 + condition.offset + depth + depth_range
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
pub const fn test_water_material(
|
||||||
pub struct WaterMaterialCondition {
|
condition: &WaterMaterialCondition,
|
||||||
offset: i32,
|
context: &MaterialRuleContext,
|
||||||
surface_depth_multiplier: i32,
|
) -> bool {
|
||||||
add_stone_depth: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WaterMaterialCondition {
|
|
||||||
pub const fn test(&self, context: &MaterialRuleContext) -> bool {
|
|
||||||
context.fluid_height == i32::MIN
|
context.fluid_height == i32::MIN
|
||||||
|| context.block_pos_y
|
|| context.block_pos_y
|
||||||
+ (if self.add_stone_depth {
|
+ (if condition.add_stone_depth {
|
||||||
context.stone_depth_above
|
context.stone_depth_above
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
})
|
})
|
||||||
>= context.fluid_height
|
>= context.fluid_height
|
||||||
+ self.offset
|
+ condition.offset
|
||||||
+ context.run_depth * self.surface_depth_multiplier
|
+ context.run_depth * condition.surface_depth_multiplier
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
// random_deriver: ThreadLocal<RefCell<LruCache<usize, RandomDeriver>>>,
|
||||||
pub struct VerticalGradientMaterialCondition {
|
|
||||||
random_name: String,
|
|
||||||
true_at_and_below: YOffset,
|
|
||||||
false_at_and_above: YOffset,
|
|
||||||
#[serde(skip)]
|
|
||||||
random_deriver: ThreadLocal<RefCell<LruCache<usize, RandomDeriver>>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl VerticalGradientMaterialCondition {
|
pub fn test_vertical_gradient(
|
||||||
pub fn test(&self, context: &MaterialRuleContext) -> bool {
|
condition: &VerticalGradientMaterialCondition,
|
||||||
let true_at = self
|
context: &MaterialRuleContext,
|
||||||
|
) -> bool {
|
||||||
|
let true_at = condition
|
||||||
.true_at_and_below
|
.true_at_and_below
|
||||||
.get_y(context.min_y as i16, context.height);
|
.get_y(context.min_y as i16, context.height);
|
||||||
let false_at = self
|
let false_at = condition
|
||||||
.false_at_and_above
|
.false_at_and_above
|
||||||
.get_y(context.min_y as i16, context.height);
|
.get_y(context.min_y as i16, context.height);
|
||||||
|
|
||||||
let context_pointer: *const RandomDeriver = context.random_deriver;
|
let splitter = context
|
||||||
let key = context_pointer.addr();
|
|
||||||
|
|
||||||
let mut cache = self
|
|
||||||
.random_deriver
|
.random_deriver
|
||||||
.get_or(|| {
|
.split_string(condition.random_name)
|
||||||
let cache_size = NonZeroUsize::new(128).unwrap();
|
.next_splitter();
|
||||||
let cache = LruCache::new(cache_size);
|
|
||||||
RefCell::new(cache)
|
|
||||||
})
|
|
||||||
.borrow_mut();
|
|
||||||
|
|
||||||
let splitter = cache.get_or_insert(key, || {
|
|
||||||
context
|
|
||||||
.random_deriver
|
|
||||||
.split_string(&self.random_name)
|
|
||||||
.next_splitter()
|
|
||||||
});
|
|
||||||
|
|
||||||
let block_y = context.block_pos_y;
|
let block_y = context.block_pos_y;
|
||||||
if block_y <= true_at {
|
if block_y <= true_at {
|
||||||
@ -452,9 +380,7 @@ impl VerticalGradientMaterialCondition {
|
|||||||
if block_y >= false_at {
|
if block_y >= false_at {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
let mapped =
|
let mapped = pumpkin_util::math::map(block_y as f32, true_at as f32, false_at as f32, 1.0, 0.0);
|
||||||
pumpkin_util::math::map(block_y as f32, true_at as f32, false_at as f32, 1.0, 0.0);
|
|
||||||
let mut random = splitter.split_pos(context.block_pos_x, block_y, context.block_pos_z);
|
let mut random = splitter.split_pos(context.block_pos_x, block_y, context.block_pos_z);
|
||||||
random.next_f32() < mapped
|
random.next_f32() < mapped
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|||||||
@ -1,42 +1,37 @@
|
|||||||
use pumpkin_data::BlockState;
|
use pumpkin_data::{
|
||||||
|
BlockState,
|
||||||
|
chunk_gen_settings::{
|
||||||
|
BlockBlueprint, ConditionMaterialRule, MaterialRule, SequenceMaterialRule,
|
||||||
|
},
|
||||||
|
};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
use super::{MaterialCondition, MaterialRuleContext};
|
use super::MaterialRuleContext;
|
||||||
use crate::{
|
use crate::{
|
||||||
ProtoChunk, block::BlockStateCodec,
|
ProtoChunk,
|
||||||
generation::noise::router::surface_height_sampler::SurfaceHeightEstimateSampler,
|
block::to_state_from_blueprint,
|
||||||
|
generation::{
|
||||||
|
noise::router::surface_height_sampler::SurfaceHeightEstimateSampler,
|
||||||
|
surface::test_condition,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
pub fn try_apply_material_rule(
|
||||||
#[serde(tag = "type")]
|
rule: &MaterialRule,
|
||||||
pub enum MaterialRule {
|
|
||||||
#[serde(rename = "minecraft:bandlands")]
|
|
||||||
Badlands(BadLandsMaterialRule),
|
|
||||||
#[serde(rename = "minecraft:block")]
|
|
||||||
Block(BlockMaterialRule),
|
|
||||||
#[serde(rename = "minecraft:sequence")]
|
|
||||||
Sequence(SequenceMaterialRule),
|
|
||||||
#[serde(rename = "minecraft:condition")]
|
|
||||||
Condition(ConditionMaterialRule),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MaterialRule {
|
|
||||||
pub fn try_apply(
|
|
||||||
&self,
|
|
||||||
chunk: &mut ProtoChunk,
|
chunk: &mut ProtoChunk,
|
||||||
context: &mut MaterialRuleContext,
|
context: &mut MaterialRuleContext,
|
||||||
surface_height_estimate_sampler: &mut SurfaceHeightEstimateSampler,
|
surface_height_estimate_sampler: &mut SurfaceHeightEstimateSampler,
|
||||||
) -> Option<&'static BlockState> {
|
) -> Option<&'static BlockState> {
|
||||||
match self {
|
match rule {
|
||||||
Self::Badlands(_badlands) => Some(BadLandsMaterialRule::try_apply(context)),
|
MaterialRule::Badlands(_badlands) => Some(BadLandsMaterialRule::try_apply(context)),
|
||||||
Self::Block(block) => Some(block.try_apply()),
|
MaterialRule::Block(block) => Some(BlockMaterialRule::try_apply(&block.result_state)),
|
||||||
Self::Sequence(sequence) => {
|
MaterialRule::Sequence(sequence) => {
|
||||||
sequence.try_apply(chunk, context, surface_height_estimate_sampler)
|
try_apply_sequence(sequence, chunk, context, surface_height_estimate_sampler)
|
||||||
}
|
|
||||||
Self::Condition(condition) => {
|
|
||||||
condition.try_apply(chunk, context, surface_height_estimate_sampler)
|
|
||||||
}
|
}
|
||||||
|
MaterialRule::Condition(condition) => {
|
||||||
|
try_apply_condition(condition, chunk, context, surface_height_estimate_sampler)
|
||||||
}
|
}
|
||||||
|
MaterialRule::Unsupported => todo!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,58 +49,48 @@ impl BadLandsMaterialRule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct BlockMaterialRule {
|
pub struct BlockMaterialRule;
|
||||||
result_state: BlockStateCodec,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BlockMaterialRule {
|
impl BlockMaterialRule {
|
||||||
pub fn try_apply(&self) -> &'static BlockState {
|
pub fn try_apply(blueprint: &BlockBlueprint) -> &'static BlockState {
|
||||||
self.result_state.get_state()
|
to_state_from_blueprint(blueprint)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
pub fn try_apply_sequence(
|
||||||
pub struct SequenceMaterialRule {
|
rule: &SequenceMaterialRule,
|
||||||
sequence: Vec<MaterialRule>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SequenceMaterialRule {
|
|
||||||
pub fn try_apply(
|
|
||||||
&self,
|
|
||||||
chunk: &mut ProtoChunk,
|
chunk: &mut ProtoChunk,
|
||||||
context: &mut MaterialRuleContext,
|
context: &mut MaterialRuleContext,
|
||||||
surface_height_estimate_sampler: &mut SurfaceHeightEstimateSampler,
|
surface_height_estimate_sampler: &mut SurfaceHeightEstimateSampler,
|
||||||
) -> Option<&'static BlockState> {
|
) -> Option<&'static BlockState> {
|
||||||
for seq in &self.sequence {
|
for seq in rule.sequence {
|
||||||
if let Some(state) = seq.try_apply(chunk, context, surface_height_estimate_sampler) {
|
if let Some(state) =
|
||||||
|
try_apply_material_rule(seq, chunk, context, surface_height_estimate_sampler)
|
||||||
|
{
|
||||||
return Some(state);
|
return Some(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
pub fn try_apply_condition(
|
||||||
pub struct ConditionMaterialRule {
|
rule: &ConditionMaterialRule,
|
||||||
if_true: MaterialCondition,
|
|
||||||
then_run: Box<MaterialRule>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ConditionMaterialRule {
|
|
||||||
pub fn try_apply(
|
|
||||||
&self,
|
|
||||||
chunk: &mut ProtoChunk,
|
chunk: &mut ProtoChunk,
|
||||||
context: &mut MaterialRuleContext,
|
context: &mut MaterialRuleContext,
|
||||||
surface_height_estimate_sampler: &mut SurfaceHeightEstimateSampler,
|
surface_height_estimate_sampler: &mut SurfaceHeightEstimateSampler,
|
||||||
) -> Option<&'static BlockState> {
|
) -> Option<&'static BlockState> {
|
||||||
if self
|
if test_condition(
|
||||||
.if_true
|
&rule.if_true,
|
||||||
.test(chunk, context, surface_height_estimate_sampler)
|
chunk,
|
||||||
{
|
context,
|
||||||
return self
|
surface_height_estimate_sampler,
|
||||||
.then_run
|
) {
|
||||||
.try_apply(chunk, context, surface_height_estimate_sampler);
|
return try_apply_material_rule(
|
||||||
|
rule.then_run,
|
||||||
|
chunk,
|
||||||
|
context,
|
||||||
|
surface_height_estimate_sampler,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|||||||
@ -153,7 +153,7 @@ impl SurfaceTerrainBuilder {
|
|||||||
for y in (chunk.bottom_y() as i32..=elevation_y).rev() {
|
for y in (chunk.bottom_y() as i32..=elevation_y).rev() {
|
||||||
let pos = Vector3::new(global_x, y, global_z);
|
let pos = Vector3::new(global_x, y, global_z);
|
||||||
let block_id = chunk.get_block_state(&pos).to_block_id();
|
let block_id = chunk.get_block_state(&pos).to_block_id();
|
||||||
if block_id == Block::get_raw_id_from_state_id(chunk.default_block.id) {
|
if block_id == chunk.default_block.id {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -22,14 +22,13 @@ use pumpkin_data::dimension::Dimension;
|
|||||||
use pumpkin_data::{Block, block_properties::has_random_ticks, fluid::Fluid};
|
use pumpkin_data::{Block, block_properties::has_random_ticks, fluid::Fluid};
|
||||||
use pumpkin_util::math::{position::BlockPos, vector2::Vector2};
|
use pumpkin_util::math::{position::BlockPos, vector2::Vector2};
|
||||||
use pumpkin_util::world_seed::Seed;
|
use pumpkin_util::world_seed::Seed;
|
||||||
use rand::{RngExt, SeedableRng, rngs::SmallRng};
|
use rustc_hash::FxHashMap;
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use tokio::time::timeout;
|
use tokio::time::timeout;
|
||||||
use tokio_util::sync::CancellationToken;
|
use tokio_util::sync::CancellationToken;
|
||||||
// use std::time::Duration;
|
// use std::time::Duration;
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
sync::{
|
sync::{
|
||||||
Arc,
|
Arc,
|
||||||
@ -232,7 +231,7 @@ impl Level {
|
|||||||
let arc_chunk = Arc::new(RwLock::new(ChunkEntityData {
|
let arc_chunk = Arc::new(RwLock::new(ChunkEntityData {
|
||||||
x: pos.x,
|
x: pos.x,
|
||||||
z: pos.y,
|
z: pos.y,
|
||||||
data: HashMap::new(),
|
data: FxHashMap::default(),
|
||||||
dirty: true,
|
dirty: true,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -341,11 +340,6 @@ impl Level {
|
|||||||
self.loaded_chunks.len()
|
self.loaded_chunks.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn clean_up_log(&self) {
|
|
||||||
self.chunk_saver.clean_up_log().await;
|
|
||||||
self.entity_saver.clean_up_log().await;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn list_cached(&self) {
|
pub fn list_cached(&self) {
|
||||||
for entry in self.loaded_chunks.iter() {
|
for entry in self.loaded_chunks.iter() {
|
||||||
log::debug!("In map: {:?}", entry.key());
|
log::debug!("In map: {:?}", entry.key());
|
||||||
@ -404,51 +398,37 @@ impl Level {
|
|||||||
!self.mark_chunks_as_not_watched(&[chunk]).await.is_empty()
|
!self.mark_chunks_as_not_watched(&[chunk]).await.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// In Level::clean_entity_chunks()
|
||||||
pub fn clean_entity_chunks(self: &Arc<Self>, chunks: &[Vector2<i32>]) {
|
pub fn clean_entity_chunks(self: &Arc<Self>, chunks: &[Vector2<i32>]) {
|
||||||
// Care needs to be take here because of interweaving case:
|
let chunks_to_process: Vec<_> = chunks
|
||||||
// 1) Remove chunk from cache
|
|
||||||
// 2) Another player wants same chunk
|
|
||||||
// 3) Load (old) chunk from serializer
|
|
||||||
// 4) Write (new) chunk from serializer
|
|
||||||
// Now outdated chunk data is cached and will be written later
|
|
||||||
|
|
||||||
let chunks_with_no_watchers = chunks
|
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|pos| {
|
.filter_map(|pos| {
|
||||||
// Only chunks that have no entry in the watcher map or have 0 watchers
|
// Only include chunks with no watchers
|
||||||
if self
|
let has_watchers = self
|
||||||
.chunk_watchers
|
.chunk_watchers
|
||||||
.get(pos)
|
.get(pos)
|
||||||
.is_none_or(|count| count.is_zero())
|
.is_some_and(|count| !count.is_zero());
|
||||||
{
|
|
||||||
self.loaded_entity_chunks
|
if has_watchers {
|
||||||
.get(pos)
|
return None;
|
||||||
.map(|chunk| (*pos, chunk.value().clone()))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove immediately to prevent race conditions
|
||||||
|
self.loaded_entity_chunks.remove(pos)
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect();
|
||||||
|
|
||||||
|
if chunks_to_process.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let level = self.clone();
|
let level = self.clone();
|
||||||
self.spawn_task(async move {
|
self.spawn_task(async move {
|
||||||
let chunks_to_remove = chunks_with_no_watchers.clone();
|
log::debug!("Writing {} entity chunks to disk", chunks_to_process.len());
|
||||||
level.write_entity_chunks(chunks_with_no_watchers).await;
|
level.write_entity_chunks(chunks_to_process).await;
|
||||||
// Only after we have written the chunks to the serializer do we remove them from the
|
|
||||||
// cache
|
|
||||||
for (pos, _) in chunks_to_remove {
|
|
||||||
let _ = level.loaded_entity_chunks.remove_if(&pos, |_, _| {
|
|
||||||
// Recheck that there is no one watching
|
|
||||||
level
|
|
||||||
.chunk_watchers
|
|
||||||
.get(&pos)
|
|
||||||
.is_none_or(|count| count.is_zero())
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gets random ticks, block ticks and fluid ticks
|
|
||||||
pub async fn get_tick_data(&self) -> TickData {
|
pub async fn get_tick_data(&self) -> TickData {
|
||||||
let mut ticks = TickData {
|
let mut ticks = TickData {
|
||||||
block_ticks: Vec::new(),
|
block_ticks: Vec::new(),
|
||||||
@ -457,75 +437,52 @@ impl Level {
|
|||||||
block_entities: Vec::new(),
|
block_entities: Vec::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut rng = SmallRng::from_rng(&mut rand::rng());
|
let r = rand::random::<u32>();
|
||||||
|
|
||||||
for chunk_sync in self.loaded_chunks.iter() {
|
for chunk_sync in self.loaded_chunks.iter() {
|
||||||
// Try to get a READ lock first.
|
let mut chunk = chunk_sync.write().await;
|
||||||
// Most chunks won't have pending ticks, so this is very fast.
|
|
||||||
let chunk = chunk_sync.read().await;
|
|
||||||
let chunk_x_base = chunk.x * 16;
|
let chunk_x_base = chunk.x * 16;
|
||||||
let chunk_z_base = chunk.z * 16;
|
let chunk_z_base = chunk.z * 16;
|
||||||
|
let section_count = chunk.section.sections.len();
|
||||||
let mut section_blocks = Vec::new();
|
|
||||||
for i in 0..chunk.section.sections.len() {
|
|
||||||
let mut section_block_data = Vec::new();
|
|
||||||
|
|
||||||
//TODO use game rules to determine how many random ticks to perform
|
|
||||||
for _ in 0..3 {
|
|
||||||
let r = rng.random::<u32>();
|
|
||||||
let x_offset = (r & 0xF) as i32;
|
|
||||||
let y_offset = ((r >> 4) & 0xF) as i32 - 32;
|
|
||||||
let z_offset = (r >> 8 & 0xF) as i32;
|
|
||||||
|
|
||||||
let random_pos = BlockPos::new(
|
|
||||||
chunk_x_base + x_offset,
|
|
||||||
i as i32 * 16 + y_offset,
|
|
||||||
chunk_z_base + z_offset,
|
|
||||||
);
|
|
||||||
|
|
||||||
let block_state_id = chunk
|
|
||||||
.section
|
|
||||||
.get_block_absolute_y(x_offset as usize, random_pos.0.y, z_offset as usize)
|
|
||||||
.unwrap_or(Block::AIR.default_state.id);
|
|
||||||
|
|
||||||
section_block_data.push((random_pos, block_state_id));
|
|
||||||
}
|
|
||||||
section_blocks.push(section_block_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
for section_data in section_blocks {
|
|
||||||
ticks
|
|
||||||
.random_ticks
|
|
||||||
.extend(
|
|
||||||
section_data
|
|
||||||
.into_iter()
|
|
||||||
.filter_map(|(random_pos, block_state_id)| {
|
|
||||||
has_random_ticks(block_state_id).then_some(ScheduledTick {
|
|
||||||
position: random_pos,
|
|
||||||
delay: 0,
|
|
||||||
priority: TickPriority::Normal,
|
|
||||||
value: (),
|
|
||||||
})
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
ticks
|
ticks
|
||||||
.block_entities
|
.block_entities
|
||||||
.extend(chunk.block_entities.values().cloned());
|
.extend(chunk.block_entities.values().cloned());
|
||||||
|
|
||||||
drop(chunk);
|
for i in 0..section_count {
|
||||||
let mut chunk_write = chunk_sync.write().await;
|
let y_base = i as i32 * 16;
|
||||||
ticks
|
for _ in 0..3 {
|
||||||
.block_ticks
|
let x_offset = (r & 0xF) as usize;
|
||||||
.append(&mut chunk_write.block_ticks.step_tick());
|
let z_offset = (r >> 8 & 0xF) as usize;
|
||||||
ticks
|
let y_in_section = ((r >> 4) & 0xF) as i32;
|
||||||
.fluid_ticks
|
let absolute_y = y_base + y_in_section;
|
||||||
.append(&mut chunk_write.fluid_ticks.step_tick());
|
|
||||||
|
if let Some(block_state_id) = chunk
|
||||||
|
.section
|
||||||
|
.get_block_absolute_y(x_offset, absolute_y, z_offset)
|
||||||
|
&& has_random_ticks(block_state_id)
|
||||||
|
{
|
||||||
|
ticks.random_ticks.push(ScheduledTick {
|
||||||
|
position: BlockPos::new(
|
||||||
|
chunk_x_base + x_offset as i32,
|
||||||
|
absolute_y,
|
||||||
|
chunk_z_base + z_offset as i32,
|
||||||
|
),
|
||||||
|
delay: 0,
|
||||||
|
priority: TickPriority::Normal,
|
||||||
|
value: (),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ticks.block_ticks.append(&mut chunk.block_ticks.step_tick());
|
||||||
|
ticks.fluid_ticks.append(&mut chunk.fluid_ticks.step_tick());
|
||||||
}
|
}
|
||||||
|
|
||||||
ticks.block_ticks.sort_unstable();
|
ticks.block_ticks.sort_unstable();
|
||||||
ticks.fluid_ticks.sort_unstable();
|
ticks.fluid_ticks.sort_unstable();
|
||||||
|
|
||||||
ticks
|
ticks
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -573,12 +530,20 @@ impl Level {
|
|||||||
lock.send_change();
|
lock.send_change();
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(chunk) = self.loaded_chunks.get(&pos) {
|
let chunk = if let Some(chunk) = self.loaded_chunks.get(&pos) {
|
||||||
chunk.clone()
|
chunk.clone()
|
||||||
} else {
|
} else {
|
||||||
recv.await
|
recv.await
|
||||||
.expect("Chunk listener dropped without sending chunk")
|
.expect("Chunk listener dropped without sending chunk")
|
||||||
|
};
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut lock = self.chunk_loading.lock().unwrap();
|
||||||
|
lock.remove_ticket(pos, 31);
|
||||||
|
lock.send_change();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
chunk
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn load_single_entity_chunk(
|
async fn load_single_entity_chunk(
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
use generation::settings::GenerationSettings;
|
use pumpkin_data::{
|
||||||
use pumpkin_data::{BlockState, dimension::Dimension};
|
Block, BlockState, chunk_gen_settings::GenerationSettings, dimension::Dimension,
|
||||||
|
};
|
||||||
use pumpkin_util::math::vector2::Vector2;
|
use pumpkin_util::math::vector2::Vector2;
|
||||||
|
|
||||||
pub mod biome;
|
pub mod biome;
|
||||||
@ -45,7 +46,7 @@ macro_rules! global_path {
|
|||||||
// TODO: is there a way to do in-file benches?
|
// TODO: is there a way to do in-file benches?
|
||||||
pub use generation::{
|
pub use generation::{
|
||||||
GlobalRandomConfig, noise::router::proto_noise_router::ProtoNoiseRouters,
|
GlobalRandomConfig, noise::router::proto_noise_router::ProtoNoiseRouters,
|
||||||
proto_chunk::ProtoChunk, settings::GENERATION_SETTINGS, settings::GeneratorSetting,
|
proto_chunk::ProtoChunk,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::generation::{
|
use crate::generation::{
|
||||||
@ -78,7 +79,10 @@ pub fn bench_create_and_populate_noise(
|
|||||||
let generation_shape = &settings.shape;
|
let generation_shape = &settings.shape;
|
||||||
let horizontal_cell_count = CHUNK_DIM / generation_shape.horizontal_cell_block_count();
|
let horizontal_cell_count = CHUNK_DIM / generation_shape.horizontal_cell_block_count();
|
||||||
let sampler = FluidLevelSampler::Chunk(StandardChunkFluidLevelSampler::new(
|
let sampler = FluidLevelSampler::Chunk(StandardChunkFluidLevelSampler::new(
|
||||||
FluidLevel::new(settings.sea_level, settings.default_fluid.name),
|
FluidLevel::new(
|
||||||
|
settings.sea_level,
|
||||||
|
Block::from_registry_key(settings.default_fluid.name).unwrap(),
|
||||||
|
),
|
||||||
FluidLevel::new(-54, &pumpkin_data::Block::LAVA),
|
FluidLevel::new(-54, &pumpkin_data::Block::LAVA),
|
||||||
));
|
));
|
||||||
|
|
||||||
@ -205,7 +209,10 @@ pub fn bench_create_and_populate_noise_with_surface(
|
|||||||
|
|
||||||
// Noise sampler
|
// Noise sampler
|
||||||
let sampler = FluidLevelSampler::Chunk(StandardChunkFluidLevelSampler::new(
|
let sampler = FluidLevelSampler::Chunk(StandardChunkFluidLevelSampler::new(
|
||||||
FluidLevel::new(settings.sea_level, settings.default_fluid.name),
|
FluidLevel::new(
|
||||||
|
settings.sea_level,
|
||||||
|
Block::from_registry_key(settings.default_fluid.name).unwrap(),
|
||||||
|
),
|
||||||
FluidLevel::new(-54, &pumpkin_data::Block::LAVA),
|
FluidLevel::new(-54, &pumpkin_data::Block::LAVA),
|
||||||
));
|
));
|
||||||
|
|
||||||
|
|||||||
@ -121,7 +121,7 @@ where
|
|||||||
nbt.put_int("z", self.position.0.z);
|
nbt.put_int("z", self.position.0.z);
|
||||||
nbt.put_int("t", self.delay as i32);
|
nbt.put_int("t", self.delay as i32);
|
||||||
nbt.put_int("p", self.priority as i32);
|
nbt.put_int("p", self.priority as i32);
|
||||||
nbt.put_string("i", self.value.to_resource_location().to_string());
|
nbt.put_string("i", self.value.to_resource_location());
|
||||||
nbt.serialize(serializer)
|
nbt.serialize(serializer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,13 +1,12 @@
|
|||||||
use std::collections::HashSet;
|
|
||||||
|
|
||||||
use pumpkin_util::math::position::BlockPos;
|
use pumpkin_util::math::position::BlockPos;
|
||||||
|
use rustc_hash::FxHashSet;
|
||||||
|
|
||||||
use crate::tick::{MAX_TICK_DELAY, OrderedTick, ScheduledTick};
|
use crate::tick::{MAX_TICK_DELAY, OrderedTick, ScheduledTick};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct ChunkTickScheduler<T> {
|
pub struct ChunkTickScheduler<T> {
|
||||||
tick_queue: [Vec<OrderedTick<T>>; MAX_TICK_DELAY],
|
tick_queue: [Vec<OrderedTick<T>>; MAX_TICK_DELAY],
|
||||||
queued_ticks: HashSet<(BlockPos, T)>,
|
queued_ticks: FxHashSet<(BlockPos, T)>,
|
||||||
offset: usize,
|
offset: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,7 +78,7 @@ impl<T> Default for ChunkTickScheduler<T> {
|
|||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
tick_queue: std::array::from_fn(|_| Vec::new()),
|
tick_queue: std::array::from_fn(|_| Vec::new()),
|
||||||
queued_ticks: HashSet::new(),
|
queued_ticks: FxHashSet::default(),
|
||||||
offset: 0,
|
offset: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
use std::{
|
use std::{
|
||||||
fs::OpenOptions,
|
fs::File,
|
||||||
io::{Cursor, Read},
|
io::{Cursor, Read},
|
||||||
path::Path,
|
path::Path,
|
||||||
time::{SystemTime, UNIX_EPOCH},
|
time::{SystemTime, UNIX_EPOCH},
|
||||||
@ -82,10 +82,9 @@ impl WorldInfoReader for AnvilLevelInfo {
|
|||||||
fn read_world_info(&self, level_folder: &Path) -> Result<LevelData, WorldInfoError> {
|
fn read_world_info(&self, level_folder: &Path) -> Result<LevelData, WorldInfoError> {
|
||||||
let path = level_folder.join(LEVEL_DAT_FILE_NAME);
|
let path = level_folder.join(LEVEL_DAT_FILE_NAME);
|
||||||
|
|
||||||
let world_info_file = OpenOptions::new().read(true).open(path)?;
|
let world_info_file = File::open(path)?;
|
||||||
let mut compression_reader = GzDecoder::new(world_info_file);
|
|
||||||
let mut buf = Vec::new();
|
let mut buf = Vec::new();
|
||||||
let _ = compression_reader.read_to_end(&mut buf)?;
|
GzDecoder::new(world_info_file).read_to_end(&mut buf)?;
|
||||||
|
|
||||||
check_file_data_version(&buf)?;
|
check_file_data_version(&buf)?;
|
||||||
check_file_level_version(&buf)?;
|
check_file_level_version(&buf)?;
|
||||||
@ -114,11 +113,7 @@ impl WorldInfoWriter for AnvilLevelInfo {
|
|||||||
|
|
||||||
// open file
|
// open file
|
||||||
let path = level_folder.join(LEVEL_DAT_FILE_NAME);
|
let path = level_folder.join(LEVEL_DAT_FILE_NAME);
|
||||||
let world_info_file = OpenOptions::new()
|
let world_info_file = File::create(path)?;
|
||||||
.truncate(true)
|
|
||||||
.create(true)
|
|
||||||
.write(true)
|
|
||||||
.open(path)?;
|
|
||||||
|
|
||||||
// write compressed data into file
|
// write compressed data into file
|
||||||
let compression_writer = GzEncoder::new(world_info_file, Compression::best());
|
let compression_writer = GzEncoder::new(world_info_file, Compression::best());
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
use std::{collections::HashMap, sync::Arc};
|
use std::sync::Arc;
|
||||||
|
|
||||||
use pumpkin_data::{
|
use pumpkin_data::{
|
||||||
Block, BlockDirection, BlockState, FacingExt,
|
Block, BlockDirection, BlockState, FacingExt,
|
||||||
@ -15,6 +15,7 @@ use pumpkin_world::{
|
|||||||
world::BlockFlags,
|
world::BlockFlags,
|
||||||
};
|
};
|
||||||
use rand::RngExt;
|
use rand::RngExt;
|
||||||
|
use rustc_hash::FxHashMap;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
block::{
|
block::{
|
||||||
@ -377,7 +378,7 @@ async fn move_piston(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut moved_blocks_map: HashMap<BlockPos, &BlockState> = HashMap::new();
|
let mut moved_blocks_map: FxHashMap<BlockPos, &BlockState> = FxHashMap::default();
|
||||||
let moved_blocks: Vec<BlockPos> = handler.moved_blocks;
|
let moved_blocks: Vec<BlockPos> = handler.moved_blocks;
|
||||||
|
|
||||||
let mut moved_block_states: Vec<&BlockState> = Vec::new();
|
let mut moved_block_states: Vec<&BlockState> = Vec::new();
|
||||||
|
|||||||
@ -97,7 +97,7 @@ use pumpkin_util::math::position::BlockPos;
|
|||||||
use pumpkin_world::BlockStateId;
|
use pumpkin_world::BlockStateId;
|
||||||
use pumpkin_world::item::ItemStack;
|
use pumpkin_world::item::ItemStack;
|
||||||
use pumpkin_world::world::{BlockAccessor, BlockFlags, BlockRegistryExt};
|
use pumpkin_world::world::{BlockAccessor, BlockFlags, BlockRegistryExt};
|
||||||
use std::collections::HashMap;
|
use rustc_hash::FxHashMap;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
@ -310,8 +310,8 @@ impl BlockActionResult {
|
|||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct BlockRegistry {
|
pub struct BlockRegistry {
|
||||||
blocks: HashMap<u16, Arc<dyn BlockBehaviour>>,
|
blocks: FxHashMap<u16, Arc<dyn BlockBehaviour>>,
|
||||||
fluids: HashMap<u16, Arc<dyn FluidBehaviour>>,
|
fluids: FxHashMap<u16, Arc<dyn FluidBehaviour>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BlockRegistryExt for BlockRegistry {
|
impl BlockRegistryExt for BlockRegistry {
|
||||||
|
|||||||
@ -30,7 +30,7 @@ impl CommandExecutor for Executor {
|
|||||||
[
|
[
|
||||||
TextComponent::text(players.len().to_string()),
|
TextComponent::text(players.len().to_string()),
|
||||||
TextComponent::text(server.basic_config.max_players.to_string()),
|
TextComponent::text(server.basic_config.max_players.to_string()),
|
||||||
TextComponent::text(get_player_names(players)),
|
TextComponent::text(get_player_names(&players)),
|
||||||
],
|
],
|
||||||
))
|
))
|
||||||
.await;
|
.await;
|
||||||
@ -39,7 +39,7 @@ impl CommandExecutor for Executor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_player_names(players: Vec<Arc<Player>>) -> String {
|
fn get_player_names(players: &[Arc<Player>]) -> String {
|
||||||
let mut names = String::new();
|
let mut names = String::new();
|
||||||
for player in players {
|
for player in players {
|
||||||
if !names.is_empty() {
|
if !names.is_empty() {
|
||||||
|
|||||||
@ -6,7 +6,6 @@ use crate::command::{
|
|||||||
},
|
},
|
||||||
tree::{CommandTree, builder::argument},
|
tree::{CommandTree, builder::argument},
|
||||||
};
|
};
|
||||||
use pumpkin_util::resource_location::ResourceLocation;
|
|
||||||
use pumpkin_util::text::TextComponent;
|
use pumpkin_util::text::TextComponent;
|
||||||
|
|
||||||
const NAMES: [&str; 1] = ["stopsound"];
|
const NAMES: [&str; 1] = ["stopsound"];
|
||||||
@ -37,7 +36,7 @@ impl CommandExecutor for Executor {
|
|||||||
sound
|
sound
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.cloned()
|
.cloned()
|
||||||
.map(|s| ResourceLocation::vanilla(s.to_name()))
|
.map(|s| format!("minecraft:{}", s.to_name()))
|
||||||
.ok(),
|
.ok(),
|
||||||
category.as_ref().map(|s| **s).ok(),
|
category.as_ref().map(|s| **s).ok(),
|
||||||
)
|
)
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
use pumpkin_protocol::java::client::play::CommandSuggestion;
|
use pumpkin_protocol::java::client::play::CommandSuggestion;
|
||||||
use pumpkin_util::text::TextComponent;
|
use pumpkin_util::text::TextComponent;
|
||||||
|
use rustc_hash::FxHashMap;
|
||||||
|
|
||||||
use super::args::ConsumedArgs;
|
use super::args::ConsumedArgs;
|
||||||
|
|
||||||
@ -56,8 +57,8 @@ impl CommandError {
|
|||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct CommandDispatcher {
|
pub struct CommandDispatcher {
|
||||||
pub commands: HashMap<String, Command>,
|
pub commands: FxHashMap<String, Command>,
|
||||||
pub permissions: HashMap<String, String>,
|
pub permissions: FxHashMap<String, String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Stores registered [`CommandTree`]s and dispatches commands to them.
|
/// Stores registered [`CommandTree`]s and dispatches commands to them.
|
||||||
|
|||||||
@ -2,7 +2,7 @@ use core::f32;
|
|||||||
use std::sync::{
|
use std::sync::{
|
||||||
Arc,
|
Arc,
|
||||||
atomic::{
|
atomic::{
|
||||||
AtomicBool, AtomicU32,
|
AtomicBool, AtomicU8, AtomicU32,
|
||||||
Ordering::{self},
|
Ordering::{self},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -27,7 +27,7 @@ pub struct ItemEntity {
|
|||||||
// These cannot be atomic values because we mutate their state based on what they are; we run
|
// These cannot be atomic values because we mutate their state based on what they are; we run
|
||||||
// into the ABA problem
|
// into the ABA problem
|
||||||
item_stack: Mutex<ItemStack>,
|
item_stack: Mutex<ItemStack>,
|
||||||
pickup_delay: Mutex<u8>,
|
pickup_delay: AtomicU8,
|
||||||
health: AtomicCell<f32>,
|
health: AtomicCell<f32>,
|
||||||
never_despawn: AtomicBool,
|
never_despawn: AtomicBool,
|
||||||
never_pickup: AtomicBool,
|
never_pickup: AtomicBool,
|
||||||
@ -47,7 +47,7 @@ impl ItemEntity {
|
|||||||
entity,
|
entity,
|
||||||
item_stack: Mutex::new(item_stack),
|
item_stack: Mutex::new(item_stack),
|
||||||
item_age: AtomicU32::new(0),
|
item_age: AtomicU32::new(0),
|
||||||
pickup_delay: Mutex::new(10), // Vanilla pickup delay is 10 ticks
|
pickup_delay: AtomicU8::new(10), // Vanilla pickup delay is 10 ticks
|
||||||
health: AtomicCell::new(5.0),
|
health: AtomicCell::new(5.0),
|
||||||
never_despawn: AtomicBool::new(false),
|
never_despawn: AtomicBool::new(false),
|
||||||
never_pickup: AtomicBool::new(false),
|
never_pickup: AtomicBool::new(false),
|
||||||
@ -66,7 +66,7 @@ impl ItemEntity {
|
|||||||
entity,
|
entity,
|
||||||
item_stack: Mutex::new(item_stack),
|
item_stack: Mutex::new(item_stack),
|
||||||
item_age: AtomicU32::new(0),
|
item_age: AtomicU32::new(0),
|
||||||
pickup_delay: Mutex::new(pickup_delay), // Vanilla pickup delay is 10 ticks
|
pickup_delay: AtomicU8::new(pickup_delay), // Vanilla pickup delay is 10 ticks
|
||||||
health: AtomicCell::new(5.0),
|
health: AtomicCell::new(5.0),
|
||||||
never_despawn: AtomicBool::new(false),
|
never_despawn: AtomicBool::new(false),
|
||||||
never_pickup: AtomicBool::new(false),
|
never_pickup: AtomicBool::new(false),
|
||||||
@ -109,8 +109,6 @@ impl ItemEntity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn try_merge_with(&self, other: &Self) {
|
async fn try_merge_with(&self, other: &Self) {
|
||||||
// Check if merge is possible
|
|
||||||
|
|
||||||
let self_stack = self.item_stack.lock().await;
|
let self_stack = self.item_stack.lock().await;
|
||||||
|
|
||||||
let other_stack = other.item_stack.lock().await;
|
let other_stack = other.item_stack.lock().await;
|
||||||
@ -164,11 +162,10 @@ impl ItemEntity {
|
|||||||
target.never_pickup.store(never_pickup, Ordering::Relaxed);
|
target.never_pickup.store(never_pickup, Ordering::Relaxed);
|
||||||
|
|
||||||
if !never_pickup {
|
if !never_pickup {
|
||||||
let mut target_delay = target.pickup_delay.lock().await;
|
let source_delay = source.pickup_delay.load(Ordering::Relaxed);
|
||||||
|
target
|
||||||
let delay = (*target_delay).max(*source.pickup_delay.lock().await);
|
.pickup_delay
|
||||||
|
.fetch_max(source_delay, Ordering::Relaxed);
|
||||||
*target_delay = delay;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if empty1 {
|
if empty1 {
|
||||||
@ -195,11 +192,11 @@ impl EntityBase for ItemEntity {
|
|||||||
) -> EntityBaseFuture<'a, ()> {
|
) -> EntityBaseFuture<'a, ()> {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let entity = &self.entity;
|
let entity = &self.entity;
|
||||||
entity.tick(caller.clone(), server).await;
|
self.pickup_delay
|
||||||
{
|
.fetch_update(Ordering::Relaxed, Ordering::Relaxed, |val| {
|
||||||
let mut delay = self.pickup_delay.lock().await;
|
Some(val.saturating_sub(1))
|
||||||
*delay = delay.saturating_sub(1);
|
})
|
||||||
};
|
.ok();
|
||||||
|
|
||||||
let original_velo = entity.velocity.load();
|
let original_velo = entity.velocity.load();
|
||||||
|
|
||||||
@ -321,7 +318,7 @@ impl EntityBase for ItemEntity {
|
|||||||
let velocity_dirty = entity.velocity_dirty.swap(false, Ordering::SeqCst)
|
let velocity_dirty = entity.velocity_dirty.swap(false, Ordering::SeqCst)
|
||||||
|| entity.touching_water.load(Ordering::SeqCst)
|
|| entity.touching_water.load(Ordering::SeqCst)
|
||||||
|| entity.touching_lava.load(Ordering::SeqCst)
|
|| entity.touching_lava.load(Ordering::SeqCst)
|
||||||
|| entity.velocity.load().sub(&original_velo).length_squared() > 0.01;
|
|| entity.velocity.load().sub(&original_velo).length_squared() > 0.1;
|
||||||
|
|
||||||
if velocity_dirty {
|
if velocity_dirty {
|
||||||
entity.send_pos_rot().await;
|
entity.send_pos_rot().await;
|
||||||
@ -373,18 +370,17 @@ impl EntityBase for ItemEntity {
|
|||||||
|
|
||||||
fn on_player_collision<'a>(&'a self, player: &'a Arc<Player>) -> EntityBaseFuture<'a, ()> {
|
fn on_player_collision<'a>(&'a self, player: &'a Arc<Player>) -> EntityBaseFuture<'a, ()> {
|
||||||
Box::pin(async {
|
Box::pin(async {
|
||||||
let can_pickup = {
|
if self.pickup_delay.load(Ordering::Relaxed) > 0
|
||||||
let delay = self.pickup_delay.lock().await;
|
|| player.living_entity.health.load() <= 0.0
|
||||||
*delay == 0
|
{
|
||||||
};
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if can_pickup
|
if player
|
||||||
&& player.living_entity.health.load() > 0.0
|
|
||||||
&& (player
|
|
||||||
.inventory
|
.inventory
|
||||||
.insert_stack_anywhere(&mut *self.item_stack.lock().await)
|
.insert_stack_anywhere(&mut *self.item_stack.lock().await)
|
||||||
.await
|
.await
|
||||||
|| player.is_creative())
|
|| player.is_creative()
|
||||||
{
|
{
|
||||||
player
|
player
|
||||||
.client
|
.client
|
||||||
@ -402,7 +398,6 @@ impl EntityBase for ItemEntity {
|
|||||||
.await
|
.await
|
||||||
.send_content_updates()
|
.send_content_updates()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
if self.item_stack.lock().await.is_empty() {
|
if self.item_stack.lock().await.is_empty() {
|
||||||
self.entity.remove().await;
|
self.entity.remove().await;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -203,16 +203,15 @@ impl ChunkManager {
|
|||||||
|
|
||||||
{
|
{
|
||||||
let mut lock = level.chunk_loading.lock().unwrap();
|
let mut lock = level.chunk_loading.lock().unwrap();
|
||||||
lock.add_ticket(
|
let new_level = ChunkLoading::get_level_from_view_distance(view_distance);
|
||||||
center,
|
lock.add_ticket(center, new_level);
|
||||||
ChunkLoading::get_level_from_view_distance(view_distance),
|
|
||||||
);
|
|
||||||
|
|
||||||
if old_center != center || old_view_distance != view_distance {
|
if old_center != center || old_view_distance != view_distance {
|
||||||
lock.remove_ticket(
|
let old_level = ChunkLoading::get_level_from_view_distance(old_view_distance);
|
||||||
old_center,
|
// Don't remove if it would be the same ticket
|
||||||
ChunkLoading::get_level_from_view_distance(old_view_distance),
|
if old_center != center || old_level != new_level {
|
||||||
);
|
lock.remove_ticket(old_center, old_level);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
lock.send_change();
|
lock.send_change();
|
||||||
};
|
};
|
||||||
@ -604,8 +603,6 @@ impl Player {
|
|||||||
level.loaded_chunk_count(),
|
level.loaded_chunk_count(),
|
||||||
);
|
);
|
||||||
|
|
||||||
level.clean_up_log().await;
|
|
||||||
|
|
||||||
//self.world().level.list_cached();
|
//self.world().level.list_cached();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1743,7 +1740,7 @@ impl Player {
|
|||||||
self.client
|
self.client
|
||||||
.send_packet_now(&CRespawn::new(
|
.send_packet_now(&CRespawn::new(
|
||||||
(new_world.dimension.id).into(),
|
(new_world.dimension.id).into(),
|
||||||
ResourceLocation::from(new_world.dimension.minecraft_name),
|
new_world.dimension.minecraft_name.to_string(),
|
||||||
biome::hash_seed(new_world.level.seed.0), // seed
|
biome::hash_seed(new_world.level.seed.0), // seed
|
||||||
self.gamemode.load() as u8,
|
self.gamemode.load() as u8,
|
||||||
self.gamemode.load() as i8,
|
self.gamemode.load() as i8,
|
||||||
@ -2666,7 +2663,7 @@ impl NBTStorage for Player {
|
|||||||
|
|
||||||
nbt.put_string(
|
nbt.put_string(
|
||||||
"Dimension",
|
"Dimension",
|
||||||
ResourceLocation::from(self.world().dimension.minecraft_name).to_string(),
|
self.world().dimension.minecraft_name.to_string(),
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,14 +7,14 @@ use pumpkin_data::item::Item;
|
|||||||
use pumpkin_util::math::position::BlockPos;
|
use pumpkin_util::math::position::BlockPos;
|
||||||
use pumpkin_util::math::vector3::Vector3;
|
use pumpkin_util::math::vector3::Vector3;
|
||||||
use pumpkin_world::item::ItemStack;
|
use pumpkin_world::item::ItemStack;
|
||||||
use std::collections::HashMap;
|
use rustc_hash::FxHashMap;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use super::{ItemBehaviour, ItemMetadata};
|
use super::{ItemBehaviour, ItemMetadata};
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct ItemRegistry {
|
pub struct ItemRegistry {
|
||||||
items: HashMap<u16, Arc<dyn ItemBehaviour>>,
|
items: FxHashMap<u16, Arc<dyn ItemBehaviour>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ItemRegistry {
|
impl ItemRegistry {
|
||||||
|
|||||||
@ -402,7 +402,7 @@ impl BedrockClient {
|
|||||||
Self::handle_ack(&Ack::read(reader)?);
|
Self::handle_ack(&Ack::read(reader)?);
|
||||||
}
|
}
|
||||||
RAKNET_NACK => {
|
RAKNET_NACK => {
|
||||||
dbg!("received nack, client is missing packets");
|
log::debug!("received nack, client is missing packets");
|
||||||
}
|
}
|
||||||
0x80..0x8d => {
|
0x80..0x8d => {
|
||||||
self.handle_frame_set(server, FrameSet::read(reader)?).await;
|
self.handle_frame_set(server, FrameSet::read(reader)?).await;
|
||||||
|
|||||||
@ -22,6 +22,8 @@ use pumpkin_protocol::{
|
|||||||
};
|
};
|
||||||
use pumpkin_util::{Hand, text::TextComponent, version::MinecraftVersion};
|
use pumpkin_util::{Hand, text::TextComponent, version::MinecraftVersion};
|
||||||
|
|
||||||
|
const BRAND_CHANNEL_PREFIX: &str = "minecraft:brand";
|
||||||
|
|
||||||
impl JavaClient {
|
impl JavaClient {
|
||||||
pub async fn handle_client_information_config(
|
pub async fn handle_client_information_config(
|
||||||
&self,
|
&self,
|
||||||
@ -59,11 +61,7 @@ impl JavaClient {
|
|||||||
|
|
||||||
pub async fn handle_plugin_message(&self, plugin_message: SPluginMessage) {
|
pub async fn handle_plugin_message(&self, plugin_message: SPluginMessage) {
|
||||||
log::debug!("Handling plugin message");
|
log::debug!("Handling plugin message");
|
||||||
if plugin_message
|
if plugin_message.channel.starts_with(BRAND_CHANNEL_PREFIX) {
|
||||||
.channel
|
|
||||||
.to_string()
|
|
||||||
.starts_with("minecraft:brand")
|
|
||||||
{
|
|
||||||
log::debug!("Got a client brand");
|
log::debug!("Got a client brand");
|
||||||
match str::from_utf8(&plugin_message.data) {
|
match str::from_utf8(&plugin_message.data) {
|
||||||
Ok(brand) => *self.brand.lock().await = Some(brand.to_string()),
|
Ok(brand) => *self.brand.lock().await = Some(brand.to_string()),
|
||||||
|
|||||||
@ -57,7 +57,6 @@ pub mod config;
|
|||||||
pub mod handshake;
|
pub mod handshake;
|
||||||
pub mod login;
|
pub mod login;
|
||||||
pub mod play;
|
pub mod play;
|
||||||
pub mod remapper;
|
|
||||||
pub mod status;
|
pub mod status;
|
||||||
|
|
||||||
use crate::entity::player::Player;
|
use crate::entity::player::Player;
|
||||||
|
|||||||
@ -1 +0,0 @@
|
|||||||
pub mod registry;
|
|
||||||
@ -1 +0,0 @@
|
|||||||
|
|
||||||
@ -9,14 +9,15 @@ use pumpkin_protocol::{
|
|||||||
java::client::{config::CPluginMessage, status::CStatusResponse},
|
java::client::{config::CPluginMessage, status::CStatusResponse},
|
||||||
};
|
};
|
||||||
use pumpkin_world::CURRENT_MC_VERSION;
|
use pumpkin_world::CURRENT_MC_VERSION;
|
||||||
use std::{fs::File, io::Read, path::Path};
|
use std::{
|
||||||
|
fs::{self},
|
||||||
|
path::Path,
|
||||||
|
};
|
||||||
|
|
||||||
const DEFAULT_ICON: &[u8] = include_bytes!("../../../assets/default_icon.png");
|
const DEFAULT_ICON: &[u8] = include_bytes!("../../../assets/default_icon.png");
|
||||||
|
|
||||||
fn load_icon_from_file<P: AsRef<Path>>(path: P) -> Result<String, Box<dyn error::Error>> {
|
fn load_icon_from_file<P: AsRef<Path>>(path: P) -> Result<String, Box<dyn error::Error>> {
|
||||||
let mut icon_file = File::open(path)?;
|
let buf = fs::read(path)?;
|
||||||
let mut buf = Vec::new();
|
|
||||||
icon_file.read_to_end(&mut buf)?;
|
|
||||||
Ok(load_icon_from_bytes(&buf))
|
Ok(load_icon_from_bytes(&buf))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -38,10 +38,8 @@ impl KeyStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn generate_private_key() -> RsaPrivateKey {
|
fn generate_private_key() -> RsaPrivateKey {
|
||||||
// Found out that OsRng is faster than rand::thread_rng here
|
|
||||||
let mut rng = rand::rng();
|
let mut rng = rand::rng();
|
||||||
|
|
||||||
// let pub_key = RsaPublicKey::from(&priv_key);
|
|
||||||
RsaPrivateKey::new(&mut rng, 1024).expect("Failed to generate a key")
|
RsaPrivateKey::new(&mut rng, 1024).expect("Failed to generate a key")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -585,6 +585,20 @@ impl Server {
|
|||||||
players
|
players
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn for_each_player<F>(&self, mut f: F)
|
||||||
|
where
|
||||||
|
F: FnMut(&Arc<Player>),
|
||||||
|
{
|
||||||
|
let worlds = self.worlds.load();
|
||||||
|
|
||||||
|
for world in worlds.iter() {
|
||||||
|
let players = world.players.load();
|
||||||
|
for player in players.iter() {
|
||||||
|
f(player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns a random player from any of the worlds, or `None` if all worlds are empty.
|
/// Returns a random player from any of the worlds, or `None` if all worlds are empty.
|
||||||
pub fn get_random_player(&self) -> Option<Arc<Player>> {
|
pub fn get_random_player(&self) -> Option<Arc<Player>> {
|
||||||
let players = self.get_all_players();
|
let players = self.get_all_players();
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
use std::collections::HashMap;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use pumpkin_data::{Block, BlockState};
|
use pumpkin_data::{Block, BlockState};
|
||||||
use pumpkin_util::math::{position::BlockPos, vector3::Vector3};
|
use pumpkin_util::math::{position::BlockPos, vector3::Vector3};
|
||||||
|
use rustc_hash::FxHashMap;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
block::{ExplodeArgs, drop_loot},
|
block::{ExplodeArgs, drop_loot},
|
||||||
@ -23,13 +23,14 @@ impl Explosion {
|
|||||||
async fn get_blocks_to_destroy(
|
async fn get_blocks_to_destroy(
|
||||||
&self,
|
&self,
|
||||||
world: &World,
|
world: &World,
|
||||||
) -> HashMap<BlockPos, (&'static Block, &'static BlockState)> {
|
) -> FxHashMap<BlockPos, (&'static Block, &'static BlockState)> {
|
||||||
// The hashmap will prevent position duplicates.
|
// Somethings are not vanilla here but make it way faster
|
||||||
let mut map = HashMap::new();
|
let mut map = FxHashMap::default();
|
||||||
|
let random_val = rand::random::<f32>();
|
||||||
for x in 0..16 {
|
for x in 0..16 {
|
||||||
for y in 0..16 {
|
for y in 0..16 {
|
||||||
'block2: for z in 0..16 {
|
'block2: for z in 0..16 {
|
||||||
if x != 0 && x != 15 && z != 0 && z != 15 && y != 0 && y != 15 {
|
if x > 0 && x < 15 && y > 0 && y < 15 && z > 0 && z < 15 {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,7 +47,7 @@ impl Explosion {
|
|||||||
let mut pos_y = self.pos.y + 0.0625;
|
let mut pos_y = self.pos.y + 0.0625;
|
||||||
let mut pos_z = self.pos.z;
|
let mut pos_z = self.pos.z;
|
||||||
|
|
||||||
let mut h = self.power * rand::random::<f32>().mul_add(0.6, 0.7);
|
let mut h = self.power * random_val.mul_add(0.6, 0.7);
|
||||||
while h > 0.0 {
|
while h > 0.0 {
|
||||||
let block_pos = BlockPos::floored(pos_x, pos_y, pos_z);
|
let block_pos = BlockPos::floored(pos_x, pos_y, pos_z);
|
||||||
let (block, state) = world.get_block_and_state(&block_pos).await;
|
let (block, state) = world.get_block_and_state(&block_pos).await;
|
||||||
@ -61,11 +62,10 @@ impl Explosion {
|
|||||||
let resistance =
|
let resistance =
|
||||||
fluid_state.blast_resistance.max(block.blast_resistance);
|
fluid_state.blast_resistance.max(block.blast_resistance);
|
||||||
h -= resistance * 0.3;
|
h -= resistance * 0.3;
|
||||||
}
|
|
||||||
|
|
||||||
if h > 0.0 {
|
if h > 0.0 {
|
||||||
map.insert(block_pos, (block, state));
|
map.insert(block_pos, (block, state));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
pos_x += x * 0.3;
|
pos_x += x * 0.3;
|
||||||
pos_y += y * 0.3;
|
pos_y += y * 0.3;
|
||||||
pos_z += z * 0.3;
|
pos_z += z * 0.3;
|
||||||
@ -82,13 +82,10 @@ impl Explosion {
|
|||||||
let blocks = self.get_blocks_to_destroy(world).await;
|
let blocks = self.get_blocks_to_destroy(world).await;
|
||||||
// TODO: Entity damage, fire
|
// TODO: Entity damage, fire
|
||||||
for (pos, (block, state)) in &blocks {
|
for (pos, (block, state)) in &blocks {
|
||||||
if state.is_air() {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
let pumpkin_block = world.block_registry.get_pumpkin_block(block.id);
|
|
||||||
|
|
||||||
world.set_block_state(pos, 0, BlockFlags::NOTIFY_ALL).await;
|
world.set_block_state(pos, 0, BlockFlags::NOTIFY_ALL).await;
|
||||||
|
|
||||||
|
let pumpkin_block = world.block_registry.get_pumpkin_block(block.id);
|
||||||
|
|
||||||
if pumpkin_block.is_none_or(|s| s.should_drop_items_on_explosion()) {
|
if pumpkin_block.is_none_or(|s| s.should_drop_items_on_explosion()) {
|
||||||
let params = LootContextParameters {
|
let params = LootContextParameters {
|
||||||
block_state: Some(state),
|
block_state: Some(state),
|
||||||
|
|||||||
@ -35,6 +35,7 @@ use crossbeam::queue::SegQueue;
|
|||||||
use explosion::Explosion;
|
use explosion::Explosion;
|
||||||
use pumpkin_config::BasicConfiguration;
|
use pumpkin_config::BasicConfiguration;
|
||||||
use pumpkin_data::block_properties::is_air;
|
use pumpkin_data::block_properties::is_air;
|
||||||
|
use pumpkin_data::chunk_gen_settings::GenerationSettings;
|
||||||
use pumpkin_data::data_component_impl::EquipmentSlot;
|
use pumpkin_data::data_component_impl::EquipmentSlot;
|
||||||
use pumpkin_data::dimension::Dimension;
|
use pumpkin_data::dimension::Dimension;
|
||||||
use pumpkin_data::entity::MobCategory;
|
use pumpkin_data::entity::MobCategory;
|
||||||
@ -135,7 +136,6 @@ pub mod weather;
|
|||||||
use crate::world::natural_spawner::{SpawnState, spawn_for_chunk};
|
use crate::world::natural_spawner::{SpawnState, spawn_for_chunk};
|
||||||
use pumpkin_data::effect::StatusEffect;
|
use pumpkin_data::effect::StatusEffect;
|
||||||
use pumpkin_world::chunk::ChunkHeightmapType::MotionBlocking;
|
use pumpkin_world::chunk::ChunkHeightmapType::MotionBlocking;
|
||||||
use pumpkin_world::generation::settings::gen_settings_from_dimension;
|
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
use weather::Weather;
|
use weather::Weather;
|
||||||
|
|
||||||
@ -217,7 +217,7 @@ impl World {
|
|||||||
server: Weak<Server>,
|
server: Weak<Server>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
// TODO
|
// TODO
|
||||||
let generation_settings = gen_settings_from_dimension(&dimension);
|
let generation_settings = GenerationSettings::from_dimension(&dimension);
|
||||||
|
|
||||||
// Load portal POI from disk (PoiStorage::new automatically loads from disk if files exist)
|
// Load portal POI from disk (PoiStorage::new automatically loads from disk if files exist)
|
||||||
let portal_poi = portal::PortalPoiStorage::new(&level.level_folder.root_folder);
|
let portal_poi = portal::PortalPoiStorage::new(&level.level_folder.root_folder);
|
||||||
@ -768,11 +768,8 @@ impl World {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut spawning_chunks: Vec<(Vector2<i32>, Arc<RwLock<ChunkData>>)> =
|
|
||||||
spawning_chunks_map.into_iter().collect();
|
|
||||||
|
|
||||||
let mut spawn_state =
|
let mut spawn_state =
|
||||||
SpawnState::new(spawning_chunks.len() as i32, &self.entities, self).await; // TODO store it
|
SpawnState::new(spawning_chunks_map.len() as i32, &self.entities, self).await; // TODO store it
|
||||||
|
|
||||||
// TODO gamerule this.spawnEnemies || this.spawnFriendlies
|
// TODO gamerule this.spawnEnemies || this.spawnFriendlies
|
||||||
let spawn_passives = self.level_time.lock().await.time_of_day % 400 == 0;
|
let spawn_passives = self.level_time.lock().await.time_of_day % 400 == 0;
|
||||||
@ -785,7 +782,8 @@ impl World {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// log::debug!("spawning list size {}", spawn_list.len());
|
// log::debug!("spawning list size {}", spawn_list.len());
|
||||||
|
let mut spawning_chunks: Vec<(Vector2<i32>, Arc<RwLock<ChunkData>>)> =
|
||||||
|
spawning_chunks_map.into_iter().collect();
|
||||||
spawning_chunks.shuffle(&mut rng());
|
spawning_chunks.shuffle(&mut rng());
|
||||||
|
|
||||||
// TODO i think it can be multithread
|
// TODO i think it can be multithread
|
||||||
@ -794,9 +792,10 @@ impl World {
|
|||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
for block_entity in tick_data.block_entities {
|
|
||||||
let world: Arc<dyn SimpleWorld> = self.clone();
|
let world: Arc<dyn SimpleWorld> = self.clone();
|
||||||
block_entity.tick(world).await;
|
|
||||||
|
for block_entity in tick_data.block_entities {
|
||||||
|
block_entity.tick(&world).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3001,13 +3000,16 @@ impl World {
|
|||||||
|
|
||||||
pub async fn drop_stack(self: &Arc<Self>, pos: &BlockPos, stack: ItemStack) {
|
pub async fn drop_stack(self: &Arc<Self>, pos: &BlockPos, stack: ItemStack) {
|
||||||
let height = EntityType::ITEM.dimension[1] / 2.0;
|
let height = EntityType::ITEM.dimension[1] / 2.0;
|
||||||
let pos = Vector3::new(
|
let spawn_pos = {
|
||||||
f64::from(pos.0.x) + 0.5 + rand::rng().random_range(-0.25..0.25),
|
let mut r = rand::rng();
|
||||||
f64::from(pos.0.y) + 0.5 + rand::rng().random_range(-0.25..0.25) - f64::from(height),
|
Vector3::new(
|
||||||
f64::from(pos.0.z) + 0.5 + rand::rng().random_range(-0.25..0.25),
|
f64::from(pos.0.x) + 0.5 + r.random_range(-0.25..0.25),
|
||||||
);
|
f64::from(pos.0.y) + 0.5 + r.random_range(-0.25..0.25) - f64::from(height),
|
||||||
|
f64::from(pos.0.z) + 0.5 + r.random_range(-0.25..0.25),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
let entity = Entity::new(self.clone(), pos, &EntityType::ITEM);
|
let entity = Entity::new(self.clone(), spawn_pos, &EntityType::ITEM);
|
||||||
let item_entity = Arc::new(ItemEntity::new(entity, stack).await);
|
let item_entity = Arc::new(ItemEntity::new(entity, stack).await);
|
||||||
self.spawn_entity(item_entity).await;
|
self.spawn_entity(item_entity).await;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user