azalea_registry/
lib.rs

1#![doc = include_str!("../README.md")]
2
3// The contents of the macros below are generated in
4// codegen/lib/code/registry.py, though the rest of the file isn't
5// auto-generated (so you can add doc comments to the registry enums if you
6// want).
7
8pub mod builtin;
9pub mod data;
10pub mod identifier;
11pub mod tags;
12
13use std::{
14    fmt::{self, Debug},
15    hash::Hash,
16    io::{self, Cursor, Write},
17};
18
19use azalea_buf::{AzaleaRead, AzaleaReadVar, AzaleaWrite, AzaleaWriteVar, BufReadError};
20#[cfg(feature = "serde")]
21use serde::Serialize;
22use simdnbt::{FromNbtTag, borrow::NbtTag};
23
24use crate::identifier::Identifier;
25
26// TODO: remove this next update
27macro_rules! define_deprecated_builtin {
28    ($($r:ident) *) => {
29        $(
30            #[doc(hidden)]
31            #[deprecated = concat!("moved to `azalea_registry::builtin::", stringify!($r), "`")]
32            pub type $r = builtin::$r;
33        )*
34    };
35}
36define_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);
37macro_rules! define_deprecated_data {
38    ($($r:ident) *) => {
39        $(
40            #[doc(hidden)]
41            #[deprecated = concat!("moved to `azalea_registry::data::", stringify!($r), "`")]
42            pub type $r = data::$r;
43        )*
44    };
45}
46define_deprecated_data!(Enchantment DamageKind Dialog WolfSoundVariant CowVariant ChickenVariant FrogVariant CatVariant PigVariant PaintingVariant WolfVariant ZombieNautilusVariant Biome);
47
48#[doc(hidden)]
49#[deprecated = "renamed to `azalea_registry::builtin::ItemKind`"]
50pub type Item = builtin::ItemKind;
51#[doc(hidden)]
52#[deprecated = "renamed to `azalea_registry::builtin::BlockKind`"]
53pub type Block = builtin::BlockKind;
54#[doc(hidden)]
55#[deprecated = "renamed to `azalea_registry::data::DimensionKind`"]
56pub type DimensionType = data::DimensionKind;
57
58pub trait Registry: AzaleaRead + AzaleaWrite + PartialEq + PartialOrd + Ord + Copy + Hash
59where
60    Self: Sized,
61{
62    fn from_u32(value: u32) -> Option<Self>;
63    fn to_u32(&self) -> u32;
64}
65
66/// A registry that might not be present.
67///
68/// This is transmitted as a single varint in the protocol.
69#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
70pub struct OptionalRegistry<T: Registry>(pub Option<T>);
71
72impl<T: Registry> AzaleaRead for OptionalRegistry<T> {
73    fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
74        Ok(OptionalRegistry(match u32::azalea_read_var(buf)? {
75            0 => None,
76            value => Some(
77                T::from_u32(value - 1)
78                    .ok_or(BufReadError::UnexpectedEnumVariant { id: value as i32 })?,
79            ),
80        }))
81    }
82}
83impl<T: Registry> AzaleaWrite for OptionalRegistry<T> {
84    fn azalea_write(&self, buf: &mut impl Write) -> io::Result<()> {
85        match &self.0 {
86            None => 0u32.azalea_write_var(buf),
87            Some(value) => (value.to_u32() + 1).azalea_write_var(buf),
88        }
89    }
90}
91
92/// A registry that will either take an ID or a resource location.
93#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
94pub enum CustomRegistry<D: Registry, C: AzaleaRead + AzaleaWrite> {
95    Direct(D),
96    Custom(C),
97}
98
99impl<D: Registry, C: AzaleaRead + AzaleaWrite> AzaleaRead for CustomRegistry<D, C> {
100    fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
101        let direct_registry = OptionalRegistry::<D>::azalea_read(buf)?;
102        if let Some(direct_registry) = direct_registry.0 {
103            return Ok(CustomRegistry::Direct(direct_registry));
104        }
105        Ok(CustomRegistry::Custom(C::azalea_read(buf)?))
106    }
107}
108impl<D: Registry, C: AzaleaRead + AzaleaWrite> AzaleaWrite for CustomRegistry<D, C> {
109    fn azalea_write(&self, buf: &mut impl Write) -> io::Result<()> {
110        match self {
111            CustomRegistry::Direct(direct_registry) => {
112                // write the id + 1
113                (direct_registry.to_u32() + 1).azalea_write_var(buf)
114            }
115            CustomRegistry::Custom(custom_registry) => {
116                // write 0, then the custom registry
117                0u32.azalea_write_var(buf)?;
118                custom_registry.azalea_write(buf)
119            }
120        }
121    }
122}
123
124#[derive(Clone, PartialEq)]
125pub enum HolderSet<D: Registry, Identifier: AzaleaRead + AzaleaWrite> {
126    Direct {
127        contents: Vec<D>,
128    },
129    Named {
130        key: Identifier,
131        contents: Vec<Identifier>,
132    },
133}
134impl<D: Registry, Identifier: AzaleaRead + AzaleaWrite> AzaleaRead for HolderSet<D, Identifier> {
135    fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
136        let size = i32::azalea_read_var(buf)? - 1;
137        if size == -1 {
138            let key = Identifier::azalea_read(buf)?;
139            Ok(Self::Named {
140                key,
141                contents: Vec::new(),
142            })
143        } else {
144            let mut contents = Vec::new();
145            for _ in 0..size {
146                contents.push(D::azalea_read(buf)?);
147            }
148            Ok(Self::Direct { contents })
149        }
150    }
151}
152impl<D: Registry, Identifier: AzaleaRead + AzaleaWrite> AzaleaWrite for HolderSet<D, Identifier> {
153    fn azalea_write(&self, buf: &mut impl Write) -> io::Result<()> {
154        match self {
155            Self::Direct { contents } => {
156                (contents.len() as i32 + 1).azalea_write_var(buf)?;
157                for item in contents {
158                    item.azalea_write(buf)?;
159                }
160            }
161            Self::Named { key, contents: _ } => {
162                0i32.azalea_write_var(buf)?;
163                key.azalea_write(buf)?;
164            }
165        }
166        Ok(())
167    }
168}
169impl<D: Registry + Debug, Identifier: AzaleaRead + AzaleaWrite + Debug> Debug
170    for HolderSet<D, Identifier>
171{
172    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
173        match self {
174            Self::Direct { contents } => f.debug_list().entries(contents).finish(),
175            Self::Named { key, contents } => f
176                .debug_struct("Named")
177                .field("key", key)
178                .field("contents", contents)
179                .finish(),
180        }
181    }
182}
183impl<D: Registry, Identifier: AzaleaRead + AzaleaWrite> From<Vec<D>> for HolderSet<D, Identifier> {
184    fn from(contents: Vec<D>) -> Self {
185        Self::Direct { contents }
186    }
187}
188#[cfg(feature = "serde")]
189impl<D: Registry + Serialize, Identifier: AzaleaRead + AzaleaWrite + Serialize> Serialize
190    for HolderSet<D, Identifier>
191{
192    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
193    where
194        S: serde::Serializer,
195    {
196        match self {
197            Self::Direct { contents } => {
198                if contents.len() == 1 {
199                    contents[0].serialize(serializer)
200                } else {
201                    contents.serialize(serializer)
202                }
203            }
204            Self::Named { key, contents: _ } => key.serialize(serializer),
205        }
206    }
207}
208impl<D: Registry, Identifier: AzaleaRead + AzaleaWrite> Default for HolderSet<D, Identifier> {
209    fn default() -> Self {
210        Self::Direct {
211            contents: Vec::new(),
212        }
213    }
214}
215
216/// A reference to either a registry or a custom value (usually something with
217/// an `Identifier`).
218pub enum Holder<R: Registry, Direct: AzaleaRead + AzaleaWrite> {
219    Reference(R),
220    Direct(Direct),
221}
222impl<R: Registry, Direct: AzaleaRead + AzaleaWrite> AzaleaRead for Holder<R, Direct> {
223    fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
224        let id = u32::azalea_read_var(buf)?;
225        if id == 0 {
226            Ok(Self::Direct(Direct::azalea_read(buf)?))
227        } else {
228            let id = id - 1;
229            let Some(value) = R::from_u32(id) else {
230                return Err(BufReadError::UnexpectedEnumVariant { id: id as i32 });
231            };
232            Ok(Self::Reference(value))
233        }
234    }
235}
236impl<R: Registry, Direct: AzaleaRead + AzaleaWrite> AzaleaWrite for Holder<R, Direct> {
237    fn azalea_write(&self, buf: &mut impl Write) -> io::Result<()> {
238        match self {
239            Self::Reference(value) => (value.to_u32() + 1).azalea_write_var(buf),
240            Self::Direct(value) => {
241                0u32.azalea_write_var(buf)?;
242                value.azalea_write(buf)
243            }
244        }
245    }
246}
247impl<R: Registry + Debug, Direct: AzaleaRead + AzaleaWrite + Debug> Debug for Holder<R, Direct> {
248    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
249        match self {
250            Self::Reference(value) => f.debug_tuple("Reference").field(value).finish(),
251            Self::Direct(value) => f.debug_tuple("Direct").field(value).finish(),
252        }
253    }
254}
255impl<R: Registry + Clone, Direct: AzaleaRead + AzaleaWrite + Clone> Clone for Holder<R, Direct> {
256    fn clone(&self) -> Self {
257        match self {
258            Self::Reference(value) => Self::Reference(*value),
259            Self::Direct(value) => Self::Direct(value.clone()),
260        }
261    }
262}
263impl<R: Registry + PartialEq, Direct: AzaleaRead + AzaleaWrite + PartialEq> PartialEq
264    for Holder<R, Direct>
265{
266    fn eq(&self, other: &Self) -> bool {
267        match (self, other) {
268            (Self::Reference(a), Self::Reference(b)) => a == b,
269            (Self::Direct(a), Self::Direct(b)) => a == b,
270            _ => false,
271        }
272    }
273}
274impl<R: Registry + Default, Direct: AzaleaRead + AzaleaWrite> Default for Holder<R, Direct> {
275    fn default() -> Self {
276        Self::Reference(R::default())
277    }
278}
279#[cfg(feature = "serde")]
280impl<R: Registry + Serialize, Direct: AzaleaRead + AzaleaWrite + Serialize> Serialize
281    for Holder<R, Direct>
282{
283    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
284    where
285        S: serde::Serializer,
286    {
287        match self {
288            Self::Reference(value) => value.serialize(serializer),
289            Self::Direct(value) => value.serialize(serializer),
290        }
291    }
292}
293
294impl<
295    R: Registry + Serialize + FromNbtTag,
296    Direct: AzaleaRead + AzaleaWrite + Serialize + FromNbtTag,
297> FromNbtTag for Holder<R, Direct>
298{
299    fn from_nbt_tag(tag: NbtTag) -> Option<Self> {
300        if let Some(reference) = R::from_nbt_tag(tag) {
301            return Some(Self::Reference(reference));
302        };
303        Direct::from_nbt_tag(tag).map(Self::Direct)
304    }
305}
306
307/// A registry which has its values decided by the server in the
308/// `ClientboundRegistryData` packet.
309///
310/// These can be resolved into their actual values with
311/// `ResolvableDataRegistry` from azalea-core.
312pub trait DataRegistry:
313    AzaleaRead + AzaleaWrite + PartialEq + PartialOrd + Ord + Copy + Hash
314{
315    const NAME: &'static str;
316    type Key: DataRegistryKey;
317
318    fn protocol_id(&self) -> u32;
319    fn new_raw(id: u32) -> Self;
320}
321pub trait DataRegistryKey {
322    type Borrow<'a>: DataRegistryKeyRef<'a>;
323
324    fn into_ident(self) -> Identifier;
325}
326pub trait DataRegistryKeyRef<'a> {
327    type Owned: DataRegistryKey;
328
329    fn to_owned(self) -> Self::Owned;
330    fn from_ident(ident: &'a Identifier) -> Self;
331    fn into_ident(self) -> Identifier;
332}
333impl<T: DataRegistry> Registry for T {
334    fn from_u32(value: u32) -> Option<Self> {
335        Some(Self::new_raw(value))
336    }
337
338    fn to_u32(&self) -> u32 {
339        self.protocol_id()
340    }
341}