#![doc = include_str!("../README.md")] // The contents of the macros below are generated in // codegen/lib/code/registry.py, though the rest of the file isn't // auto-generated (so you can add doc comments to the registry enums if you // want). pub mod builtin; pub mod data; pub mod identifier; pub mod tags; use std::{ fmt::{self, Debug}, hash::Hash, io::{self, Cursor, Write}, }; use azalea_buf::{AzBuf, AzBufVar, BufReadError}; #[cfg(feature = "serde")] use serde::Serialize; use simdnbt::{FromNbtTag, borrow::NbtTag}; use crate::identifier::Identifier; // TODO: remove this next update macro_rules! define_deprecated_builtin { ($($r:ident) *) => { $( #[doc(hidden)] #[deprecated = concat!("moved to `azalea_registry::builtin::", stringify!($r), "`")] pub type $r = builtin::$r; )* }; } define_deprecated_builtin!(Activity Attribute BlockEntityKind BlockPredicateKind ChunkStatus CommandArgumentKind CustomStat EntityKind FloatProviderKind Fluid GameEvent HeightProviderKind IntProviderKind LootConditionKind LootFunctionKind LootNbtProviderKind LootNumberProviderKind LootPoolEntryKind LootScoreProviderKind MemoryModuleKind MobEffect ParticleKind PointOfInterestKind PosRuleTest PositionSourceKind Potion RecipeSerializer RecipeKind RuleTest SensorKind SoundEvent StatKind VillagerProfession VillagerKind WorldgenBiomeSource WorldgenBlockStateProviderKind WorldgenCarver WorldgenChunkGenerator WorldgenDensityFunctionKind WorldgenFeature WorldgenFeatureSizeKind WorldgenFoliagePlacerKind WorldgenMaterialCondition WorldgenMaterialRule WorldgenPlacementModifierKind WorldgenRootPlacerKind WorldgenStructurePiece WorldgenStructurePlacement WorldgenStructurePoolElement WorldgenStructureProcessor WorldgenStructureKind WorldgenTreeDecoratorKind WorldgenTrunkPlacerKind RuleBlockEntityModifier CreativeModeTab MenuKind WorldgenPoolAliasBinding TriggerKind NumberFormatKind DataComponentKind EntitySubPredicateKind MapDecorationKind EnchantmentEffectComponentKind EnchantmentEntityEffectKind EnchantmentLevelBasedValueKind EnchantmentLocationBasedEffectKind EnchantmentProviderKind EnchantmentValueEffectKind DecoratedPotPattern ConsumeEffectKind RecipeBookCategory RecipeDisplay SlotDisplay TicketKind TestEnvironmentDefinitionKind TestFunction TestInstanceKind DataComponentPredicateKind SpawnConditionKind DialogBodyKind DialogKind InputControlKind DialogActionKind DebugSubscription IncomingRpcMethods OutgoingRpcMethods AttributeKind EnvironmentAttribute GameRule PermissionCheckKind PermissionKind SlotSourceKind); macro_rules! define_deprecated_data { ($($r:ident) *) => { $( #[doc(hidden)] #[deprecated = concat!("moved to `azalea_registry::data::", stringify!($r), "`")] pub type $r = data::$r; )* }; } define_deprecated_data!(Enchantment DamageKind Dialog WolfSoundVariant CowVariant ChickenVariant FrogVariant CatVariant PigVariant PaintingVariant WolfVariant ZombieNautilusVariant Biome); #[doc(hidden)] #[deprecated = "renamed to `azalea_registry::builtin::ItemKind`"] pub type Item = builtin::ItemKind; #[doc(hidden)] #[deprecated = "renamed to `azalea_registry::builtin::BlockKind`"] pub type Block = builtin::BlockKind; #[doc(hidden)] #[deprecated = "renamed to `azalea_registry::data::DimensionKind`"] pub type DimensionType = data::DimensionKind; pub trait Registry: AzBuf + PartialEq + PartialOrd + Ord + Copy + Hash where Self: Sized, { fn from_u32(value: u32) -> Option; fn to_u32(&self) -> u32; } /// A registry that might not be present. /// /// This is transmitted as a single varint in the protocol. #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub struct OptionalRegistry(pub Option); impl AzBuf for OptionalRegistry { fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result { Ok(OptionalRegistry(match u32::azalea_read_var(buf)? { 0 => None, value => Some( T::from_u32(value - 1) .ok_or(BufReadError::UnexpectedEnumVariant { id: value as i32 })?, ), })) } fn azalea_write(&self, buf: &mut impl Write) -> io::Result<()> { match &self.0 { None => 0u32.azalea_write_var(buf), Some(value) => (value.to_u32() + 1).azalea_write_var(buf), } } } /// A registry that will either take an ID or a resource location. #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub enum CustomRegistry { Direct(D), Custom(C), } impl AzBuf for CustomRegistry { fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result { let direct_registry = OptionalRegistry::::azalea_read(buf)?; if let Some(direct_registry) = direct_registry.0 { return Ok(CustomRegistry::Direct(direct_registry)); } Ok(CustomRegistry::Custom(C::azalea_read(buf)?)) } fn azalea_write(&self, buf: &mut impl Write) -> io::Result<()> { match self { CustomRegistry::Direct(direct_registry) => { // write the id + 1 (direct_registry.to_u32() + 1).azalea_write_var(buf) } CustomRegistry::Custom(custom_registry) => { // write 0, then the custom registry 0u32.azalea_write_var(buf)?; custom_registry.azalea_write(buf) } } } } #[derive(Clone, PartialEq)] pub enum HolderSet { Direct { contents: Vec, }, Named { key: Identifier, contents: Vec, }, } impl AzBuf for HolderSet { fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result { let size = i32::azalea_read_var(buf)?.wrapping_sub(1); if size == -1 { let key = Identifier::azalea_read(buf)?; Ok(Self::Named { key, contents: Vec::new(), }) } else { let mut contents = Vec::new(); for _ in 0..size { contents.push(D::azalea_read(buf)?); } Ok(Self::Direct { contents }) } } fn azalea_write(&self, buf: &mut impl Write) -> io::Result<()> { match self { Self::Direct { contents } => { (contents.len() as i32 + 1).azalea_write_var(buf)?; for item in contents { item.azalea_write(buf)?; } } Self::Named { key, contents: _ } => { 0i32.azalea_write_var(buf)?; key.azalea_write(buf)?; } } Ok(()) } } impl Debug for HolderSet { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::Direct { contents } => f.debug_list().entries(contents).finish(), Self::Named { key, contents } => f .debug_struct("Named") .field("key", key) .field("contents", contents) .finish(), } } } impl From> for HolderSet { fn from(contents: Vec) -> Self { Self::Direct { contents } } } #[cfg(feature = "serde")] impl Serialize for HolderSet { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, { match self { Self::Direct { contents } => { if contents.len() == 1 { contents[0].serialize(serializer) } else { contents.serialize(serializer) } } Self::Named { key, contents: _ } => key.serialize(serializer), } } } impl Default for HolderSet { fn default() -> Self { Self::Direct { contents: Vec::new(), } } } impl + PartialEq> HolderSet { pub fn contains(&self, value: D) -> bool { match self { HolderSet::Direct { contents } => contents.contains(&value), HolderSet::Named { key: _, contents } => contents.contains(&Identifier::from(value)), } } } /// A reference to either a registry or a custom value (usually something with /// an `Identifier`). pub enum Holder { Reference(R), Direct(Direct), } impl AzBuf for Holder { fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result { let id = u32::azalea_read_var(buf)?; if id == 0 { Ok(Self::Direct(Direct::azalea_read(buf)?)) } else { let id = id - 1; let Some(value) = R::from_u32(id) else { return Err(BufReadError::UnexpectedEnumVariant { id: id as i32 }); }; Ok(Self::Reference(value)) } } fn azalea_write(&self, buf: &mut impl Write) -> io::Result<()> { match self { Self::Reference(value) => (value.to_u32() + 1).azalea_write_var(buf), Self::Direct(value) => { 0u32.azalea_write_var(buf)?; value.azalea_write(buf) } } } } impl Debug for Holder { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::Reference(value) => f.debug_tuple("Reference").field(value).finish(), Self::Direct(value) => f.debug_tuple("Direct").field(value).finish(), } } } impl Clone for Holder { fn clone(&self) -> Self { match self { Self::Reference(value) => Self::Reference(*value), Self::Direct(value) => Self::Direct(value.clone()), } } } impl PartialEq for Holder { fn eq(&self, other: &Self) -> bool { match (self, other) { (Self::Reference(a), Self::Reference(b)) => a == b, (Self::Direct(a), Self::Direct(b)) => a == b, _ => false, } } } impl Default for Holder { fn default() -> Self { Self::Reference(R::default()) } } #[cfg(feature = "serde")] impl Serialize for Holder { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, { match self { Self::Reference(value) => value.serialize(serializer), Self::Direct(value) => value.serialize(serializer), } } } impl FromNbtTag for Holder { fn from_nbt_tag(tag: NbtTag) -> Option { if let Some(reference) = R::from_nbt_tag(tag) { return Some(Self::Reference(reference)); }; Direct::from_nbt_tag(tag).map(Self::Direct) } } /// A registry which has its values decided by the server in the /// `ClientboundRegistryData` packet. /// /// These can be resolved into their actual values with /// `ResolvableDataRegistry` from azalea-core. pub trait DataRegistry: AzBuf + PartialEq + PartialOrd + Ord + Copy + Hash { const NAME: &'static str; type Key: DataRegistryKey; fn protocol_id(&self) -> u32; fn new_raw(id: u32) -> Self; } pub trait DataRegistryKey { type Borrow<'a>: DataRegistryKeyRef<'a>; fn from_ident(ident: Identifier) -> Self; fn into_ident(self) -> Identifier; } pub trait DataRegistryKeyRef<'a> { type Owned: DataRegistryKey; fn to_owned(self) -> Self::Owned; fn from_ident(ident: &'a Identifier) -> Self; fn into_ident(self) -> Identifier; } impl Registry for T { fn from_u32(value: u32) -> Option { Some(Self::new_raw(value)) } fn to_u32(&self) -> u32 { self.protocol_id() } }