mirror of
https://github.com/italicsjenga/valence.git
synced 2025-02-05 18:16:34 +11:00
228 lines
6.8 KiB
Rust
228 lines
6.8 KiB
Rust
//! Biome configuration and identification.
|
|
|
|
use std::collections::HashSet;
|
|
|
|
use anyhow::ensure;
|
|
use valence_nbt::{compound, Compound};
|
|
|
|
use crate::ident;
|
|
use crate::ident::Ident;
|
|
|
|
/// Identifies a particular [`Biome`] on the server.
|
|
///
|
|
/// The default biome ID refers to the first biome added in the server's
|
|
/// [configuration](crate::config::Config).
|
|
///
|
|
/// To obtain biome IDs for other biomes, call
|
|
/// [`biomes`](crate::server::SharedServer::biomes).
|
|
#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
|
|
pub struct BiomeId(pub(crate) u16);
|
|
|
|
/// Contains the configuration for a biome.
|
|
///
|
|
/// Biomes are registered once at startup through
|
|
/// [`biomes`](crate::config::Config::biomes).
|
|
#[derive(Clone, Debug)]
|
|
pub struct Biome {
|
|
/// The unique name for this biome. The name can be
|
|
/// seen in the F3 debug menu.
|
|
pub name: Ident,
|
|
pub precipitation: BiomePrecipitation,
|
|
pub sky_color: u32,
|
|
pub water_fog_color: u32,
|
|
pub fog_color: u32,
|
|
pub water_color: u32,
|
|
pub foliage_color: Option<u32>,
|
|
pub grass_color: Option<u32>,
|
|
pub grass_color_modifier: BiomeGrassColorModifier,
|
|
pub music: Option<BiomeMusic>,
|
|
pub ambient_sound: Option<Ident>,
|
|
pub additions_sound: Option<BiomeAdditionsSound>,
|
|
pub mood_sound: Option<BiomeMoodSound>,
|
|
pub particle: Option<BiomeParticle>,
|
|
// TODO: The following fields should be added if they can affect the appearance of the biome to
|
|
// clients.
|
|
// * depth: f32
|
|
// * temperature: f32
|
|
// * scale: f32
|
|
// * downfall: f32
|
|
// * category
|
|
// * temperature_modifier
|
|
}
|
|
|
|
impl Biome {
|
|
pub(crate) fn to_biome_registry_item(&self, id: i32) -> Compound {
|
|
let mut reg = compound! {
|
|
"name" => self.name.clone(),
|
|
"id" => id,
|
|
"element" => compound! {
|
|
"precipitation" => match self.precipitation {
|
|
BiomePrecipitation::Rain => "rain",
|
|
BiomePrecipitation::Snow => "snow",
|
|
BiomePrecipitation::None => "none",
|
|
},
|
|
"depth" => 0.125_f32,
|
|
"temperature" => 0.8_f32,
|
|
"scale" => 0.05_f32,
|
|
"downfall" => 0.4_f32,
|
|
"category" => "none",
|
|
// "temperature_modifier" =>
|
|
"effects" => {
|
|
let mut eff = compound! {
|
|
"sky_color" => self.sky_color as i32,
|
|
"water_fog_color" => self.water_fog_color as i32,
|
|
"fog_color" => self.fog_color as i32,
|
|
"water_color" => self.water_color as i32,
|
|
};
|
|
|
|
if let Some(color) = self.foliage_color {
|
|
eff.insert("foliage_color", color as i32);
|
|
}
|
|
|
|
if let Some(color) = self.grass_color {
|
|
eff.insert("grass_color", color as i32);
|
|
}
|
|
|
|
match self.grass_color_modifier {
|
|
BiomeGrassColorModifier::Swamp => eff.insert("grass_color_modifier", "swamp"),
|
|
BiomeGrassColorModifier::DarkForest => eff.insert("grass_color_modifier", "dark_forest"),
|
|
BiomeGrassColorModifier::None => None
|
|
};
|
|
|
|
if let Some(music) = &self.music {
|
|
eff.insert("music", compound! {
|
|
"replace_current_music" => music.replace_current_music,
|
|
"sound" => music.sound.clone(),
|
|
"max_delay" => music.max_delay,
|
|
"min_delay" => music.min_delay,
|
|
});
|
|
}
|
|
|
|
if let Some(s) = &self.ambient_sound {
|
|
eff.insert("ambient_sound", s.clone());
|
|
}
|
|
|
|
if let Some(a) = &self.additions_sound {
|
|
eff.insert("additions_sound", compound! {
|
|
"sound" => a.sound.clone(),
|
|
"tick_chance" => a.tick_chance,
|
|
});
|
|
}
|
|
|
|
if let Some(m) = &self.mood_sound {
|
|
eff.insert("mood_sound", compound! {
|
|
"sound" => m.sound.clone(),
|
|
"tick_delay" => m.tick_delay,
|
|
"offset" => m.offset,
|
|
"block_search_extent" => m.block_search_extent,
|
|
});
|
|
}
|
|
|
|
eff
|
|
},
|
|
}
|
|
};
|
|
|
|
if let Some(p) = &self.particle {
|
|
reg.insert(
|
|
"particle",
|
|
compound! {
|
|
"probability" => p.probability,
|
|
"options" => compound! {
|
|
"type" => p.kind.clone(),
|
|
}
|
|
},
|
|
);
|
|
}
|
|
|
|
reg
|
|
}
|
|
}
|
|
|
|
pub(crate) fn validate_biomes(biomes: &[Biome]) -> anyhow::Result<()> {
|
|
ensure!(!biomes.is_empty(), "at least one biome must be present");
|
|
|
|
ensure!(
|
|
biomes.len() <= u16::MAX as _,
|
|
"more than u16::MAX biomes present"
|
|
);
|
|
|
|
let mut names = HashSet::new();
|
|
|
|
for biome in biomes {
|
|
ensure!(
|
|
names.insert(biome.name.clone()),
|
|
"biome \"{}\" already exists",
|
|
biome.name
|
|
);
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
impl Default for Biome {
|
|
fn default() -> Self {
|
|
Self {
|
|
name: ident!("plains"),
|
|
precipitation: BiomePrecipitation::default(),
|
|
sky_color: 7907327,
|
|
water_fog_color: 329011,
|
|
fog_color: 12638463,
|
|
water_color: 4159204,
|
|
foliage_color: None,
|
|
grass_color: None,
|
|
grass_color_modifier: BiomeGrassColorModifier::default(),
|
|
music: None,
|
|
ambient_sound: None,
|
|
additions_sound: None,
|
|
mood_sound: None,
|
|
particle: None,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Copy, PartialEq, Eq, Default, Debug)]
|
|
pub enum BiomePrecipitation {
|
|
#[default]
|
|
Rain,
|
|
Snow,
|
|
None,
|
|
}
|
|
|
|
/// Minecraft handles grass colors for swamps and dark oak forests in a special
|
|
/// way.
|
|
#[derive(Clone, Copy, PartialEq, Eq, Default, Debug)]
|
|
pub enum BiomeGrassColorModifier {
|
|
Swamp,
|
|
DarkForest,
|
|
#[default]
|
|
None,
|
|
}
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub struct BiomeMusic {
|
|
pub replace_current_music: bool,
|
|
pub sound: Ident,
|
|
pub min_delay: i32,
|
|
pub max_delay: i32,
|
|
}
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub struct BiomeAdditionsSound {
|
|
pub sound: Ident,
|
|
pub tick_chance: f64,
|
|
}
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub struct BiomeMoodSound {
|
|
pub sound: Ident,
|
|
pub tick_delay: i32,
|
|
pub offset: f64,
|
|
pub block_search_extent: i32,
|
|
}
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub struct BiomeParticle {
|
|
pub probability: f32,
|
|
pub kind: Ident,
|
|
}
|