mirror of
https://github.com/mat-1/azalea.git
synced 2025-08-02 14:26:04 +00:00
* Update simdnbt dep * Fix not compiling (rust analyzer is still yapping, i trust you cargo check) * Update simdnbt to 0.5.2 * finally everything works :prayge:
336 lines
10 KiB
Rust
336 lines
10 KiB
Rust
//! The data sent to the client in the `ClientboundRegistryDataPacket`.
|
|
//!
|
|
//! This module contains the structures used to represent the registry
|
|
//! sent to the client upon login. This contains a lot of information about
|
|
//! the game, including the types of chat messages, dimensions, and
|
|
//! biomes.
|
|
|
|
use simdnbt::{
|
|
owned::{NbtCompound, NbtTag},
|
|
Deserialize, FromNbtTag, Serialize, ToNbtTag,
|
|
};
|
|
use std::{collections::HashMap, io::Cursor};
|
|
use tracing::error;
|
|
|
|
use crate::resource_location::ResourceLocation;
|
|
|
|
/// The base of the registry.
|
|
///
|
|
/// This is the registry that is sent to the client upon login.
|
|
#[derive(Default, Debug, Clone)]
|
|
pub struct RegistryHolder {
|
|
pub map: HashMap<ResourceLocation, HashMap<ResourceLocation, NbtCompound>>,
|
|
}
|
|
|
|
impl RegistryHolder {
|
|
pub fn append(
|
|
&mut self,
|
|
id: ResourceLocation,
|
|
entries: HashMap<ResourceLocation, Option<NbtCompound>>,
|
|
) {
|
|
let map = self.map.entry(id).or_default();
|
|
for (key, value) in entries {
|
|
if let Some(value) = value {
|
|
map.insert(key, value);
|
|
} else {
|
|
map.remove(&key);
|
|
}
|
|
}
|
|
}
|
|
|
|
fn get<T: Deserialize>(
|
|
&self,
|
|
name: &ResourceLocation,
|
|
) -> Option<Result<RegistryType<T>, simdnbt::DeserializeError>> {
|
|
// this is suboptimal, ideally simdnbt should just have a way to get the
|
|
// owned::NbtCompound as a borrow::NbtCompound
|
|
|
|
let mut map = HashMap::new();
|
|
|
|
for (key, value) in self.map.get(name)? {
|
|
// convert the value to T
|
|
let mut nbt_bytes = Vec::new();
|
|
value.write(&mut nbt_bytes);
|
|
let nbt_borrow_compound =
|
|
simdnbt::borrow::read_compound(&mut Cursor::new(&nbt_bytes)).ok()?;
|
|
let value = match T::from_compound(&nbt_borrow_compound) {
|
|
Ok(value) => value,
|
|
Err(err) => {
|
|
return Some(Err(err));
|
|
}
|
|
};
|
|
|
|
map.insert(key.clone(), value);
|
|
}
|
|
|
|
Some(Ok(RegistryType { map }))
|
|
}
|
|
|
|
/// Get the dimension type registry, or `None` if it doesn't exist. You
|
|
/// should do some type of error handling if this returns `None`.
|
|
pub fn dimension_type(&self) -> Option<RegistryType<DimensionTypeElement>> {
|
|
let name = ResourceLocation::new("minecraft:dimension_type");
|
|
match self.get(&name) {
|
|
Some(Ok(registry)) => Some(registry),
|
|
Some(Err(err)) => {
|
|
error!(
|
|
"Error deserializing dimension type registry: {err:?}\n{:?}",
|
|
self.map.get(&name)
|
|
);
|
|
None
|
|
}
|
|
None => None,
|
|
}
|
|
}
|
|
}
|
|
|
|
/// A collection of values for a certain type of registry data.
|
|
#[derive(Debug, Clone)]
|
|
pub struct RegistryType<T> {
|
|
pub map: HashMap<ResourceLocation, T>,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[cfg_attr(feature = "strict_registry", simdnbt(deny_unknown_fields))]
|
|
pub struct TrimMaterialElement {
|
|
pub asset_name: String,
|
|
pub ingredient: ResourceLocation,
|
|
pub item_model_index: f32,
|
|
pub override_armor_materials: HashMap<String, String>,
|
|
pub description: Option<String>,
|
|
}
|
|
|
|
/// Data about a kind of chat message
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[cfg_attr(feature = "strict_registry", simdnbt(deny_unknown_fields))]
|
|
pub struct ChatTypeElement {
|
|
pub chat: ChatTypeData,
|
|
pub narration: ChatTypeData,
|
|
}
|
|
|
|
/// Data about a chat message.
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[cfg_attr(feature = "strict_registry", simdnbt(deny_unknown_fields))]
|
|
pub struct ChatTypeData {
|
|
pub translation_key: String,
|
|
pub parameters: Vec<String>,
|
|
pub style: Option<ChatTypeStyle>,
|
|
}
|
|
|
|
/// The style of a chat message.
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[cfg_attr(feature = "strict_registry", simdnbt(deny_unknown_fields))]
|
|
pub struct ChatTypeStyle {
|
|
pub color: Option<String>,
|
|
pub bold: Option<bool>,
|
|
pub italic: Option<bool>,
|
|
pub underlined: Option<bool>,
|
|
pub strikethrough: Option<bool>,
|
|
pub obfuscated: Option<bool>,
|
|
}
|
|
|
|
/// Dimension attributes.
|
|
#[cfg(feature = "strict_registry")]
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[simdnbt(deny_unknown_fields)]
|
|
pub struct DimensionTypeElement {
|
|
pub ambient_light: f32,
|
|
pub bed_works: bool,
|
|
pub coordinate_scale: f32,
|
|
pub effects: ResourceLocation,
|
|
pub fixed_time: Option<u32>,
|
|
pub has_ceiling: bool,
|
|
pub has_raids: bool,
|
|
pub has_skylight: bool,
|
|
pub height: u32,
|
|
pub infiniburn: ResourceLocation,
|
|
pub logical_height: u32,
|
|
pub min_y: i32,
|
|
pub monster_spawn_block_light_limit: u32,
|
|
pub monster_spawn_light_level: MonsterSpawnLightLevel,
|
|
pub natural: bool,
|
|
pub piglin_safe: bool,
|
|
pub respawn_anchor_works: bool,
|
|
pub ultrawarm: bool,
|
|
}
|
|
|
|
/// Dimension attributes.
|
|
#[cfg(not(feature = "strict_registry"))]
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct DimensionTypeElement {
|
|
pub height: u32,
|
|
pub min_y: i32,
|
|
#[simdnbt(flatten)]
|
|
pub _extra: HashMap<String, NbtTag>,
|
|
}
|
|
|
|
/// The light level at which monsters can spawn.
|
|
///
|
|
/// This can be either a single minimum value, or a formula with a min and
|
|
/// max.
|
|
#[derive(Debug, Clone)]
|
|
// #[serde(untagged)]
|
|
pub enum MonsterSpawnLightLevel {
|
|
/// A simple minimum value.
|
|
Simple(u32),
|
|
/// A complex value with a type, minimum, and maximum.
|
|
/// Vanilla minecraft only uses one type, "minecraft:uniform".
|
|
Complex {
|
|
kind: ResourceLocation,
|
|
value: MonsterSpawnLightLevelValues,
|
|
},
|
|
}
|
|
|
|
impl FromNbtTag for MonsterSpawnLightLevel {
|
|
fn from_nbt_tag(tag: &simdnbt::borrow::NbtTag) -> Option<Self> {
|
|
if let Some(value) = tag.int() {
|
|
Some(Self::Simple(value as u32))
|
|
} else if let Some(value) = tag.compound() {
|
|
let kind = ResourceLocation::from_nbt_tag(value.get("type")?)?;
|
|
let value = MonsterSpawnLightLevelValues::from_nbt_tag(value.get("value")?)?;
|
|
Some(Self::Complex { kind, value })
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
}
|
|
|
|
impl ToNbtTag for MonsterSpawnLightLevel {
|
|
fn to_nbt_tag(self) -> simdnbt::owned::NbtTag {
|
|
match self {
|
|
Self::Simple(value) => value.to_nbt_tag(),
|
|
Self::Complex { kind, value } => {
|
|
let mut compound = NbtCompound::new();
|
|
compound.insert("type", kind.to_nbt_tag());
|
|
compound.insert("value", value.to_nbt_tag());
|
|
simdnbt::owned::NbtTag::Compound(compound)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// The min and max light levels at which monsters can spawn.
|
|
///
|
|
/// Values are inclusive.
|
|
#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
|
|
#[cfg_attr(feature = "strict_registry", simdnbt(deny_unknown_fields))]
|
|
pub struct MonsterSpawnLightLevelValues {
|
|
#[simdnbt(rename = "min_inclusive")]
|
|
pub min: u32,
|
|
#[simdnbt(rename = "max_inclusive")]
|
|
pub max: u32,
|
|
}
|
|
|
|
/// Biome attributes.
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[cfg_attr(feature = "strict_registry", simdnbt(deny_unknown_fields))]
|
|
pub struct WorldTypeElement {
|
|
pub has_precipitation: bool,
|
|
pub temperature: f32,
|
|
pub temperature_modifier: Option<String>,
|
|
pub downfall: f32,
|
|
pub effects: BiomeEffects,
|
|
}
|
|
|
|
/// The precipitation of a biome.
|
|
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
|
pub enum BiomePrecipitation {
|
|
None,
|
|
Rain,
|
|
Snow,
|
|
}
|
|
impl FromNbtTag for BiomePrecipitation {
|
|
fn from_nbt_tag(tag: &simdnbt::borrow::NbtTag) -> Option<Self> {
|
|
match tag.string()?.to_str().as_ref() {
|
|
"none" => Some(Self::None),
|
|
"rain" => Some(Self::Rain),
|
|
"snow" => Some(Self::Snow),
|
|
_ => None,
|
|
}
|
|
}
|
|
}
|
|
impl ToNbtTag for BiomePrecipitation {
|
|
fn to_nbt_tag(self) -> NbtTag {
|
|
match self {
|
|
Self::None => NbtTag::String("none".into()),
|
|
Self::Rain => NbtTag::String("rain".into()),
|
|
Self::Snow => NbtTag::String("snow".into()),
|
|
}
|
|
}
|
|
}
|
|
|
|
/// The effects of a biome.
|
|
///
|
|
/// This includes the sky, fog, water, and grass color,
|
|
/// as well as music and other sound effects.
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[cfg_attr(feature = "strict_registry", simdnbt(deny_unknown_fields))]
|
|
pub struct BiomeEffects {
|
|
pub sky_color: u32,
|
|
pub fog_color: u32,
|
|
pub water_color: u32,
|
|
pub water_fog_color: u32,
|
|
pub foliage_color: Option<u32>,
|
|
pub grass_color: Option<u32>,
|
|
pub grass_color_modifier: Option<String>,
|
|
pub music: Option<BiomeMusic>,
|
|
pub mood_sound: BiomeMoodSound,
|
|
pub additions_sound: Option<AdditionsSound>,
|
|
pub ambient_sound: Option<ResourceLocation>,
|
|
pub particle: Option<BiomeParticle>,
|
|
}
|
|
|
|
/// The music of the biome.
|
|
///
|
|
/// Some biomes have unique music that only play when inside them.
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[cfg_attr(feature = "strict_registry", simdnbt(deny_unknown_fields))]
|
|
pub struct BiomeMusic {
|
|
pub replace_current_music: bool,
|
|
pub max_delay: u32,
|
|
pub min_delay: u32,
|
|
pub sound: azalea_registry::SoundEvent,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[cfg_attr(feature = "strict_registry", simdnbt(deny_unknown_fields))]
|
|
pub struct BiomeMoodSound {
|
|
pub tick_delay: u32,
|
|
pub block_search_extent: u32,
|
|
pub offset: f32,
|
|
pub sound: azalea_registry::SoundEvent,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[cfg_attr(feature = "strict_registry", simdnbt(deny_unknown_fields))]
|
|
pub struct AdditionsSound {
|
|
pub tick_chance: f32,
|
|
pub sound: azalea_registry::SoundEvent,
|
|
}
|
|
|
|
/// Biome particles.
|
|
///
|
|
/// Some biomes have particles that spawn in the air.
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[cfg_attr(feature = "strict_registry", simdnbt(deny_unknown_fields))]
|
|
pub struct BiomeParticle {
|
|
pub probability: f32,
|
|
pub options: HashMap<String, String>,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[cfg_attr(feature = "strict_registry", simdnbt(deny_unknown_fields))]
|
|
pub struct TrimPatternElement {
|
|
#[simdnbt(flatten)]
|
|
pub pattern: HashMap<String, String>,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[cfg_attr(feature = "strict_registry", simdnbt(deny_unknown_fields))]
|
|
pub struct DamageTypeElement {
|
|
pub message_id: String,
|
|
pub scaling: String,
|
|
pub exhaustion: f32,
|
|
pub effects: Option<String>,
|
|
pub death_message_type: Option<String>,
|
|
}
|