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<R: Registry + FromNbtTag, Direct: AzaleaRead + AzaleaWrite + FromNbtTag> FromNbtTag
295    for Holder<R, Direct>
296{
297    fn from_nbt_tag(tag: NbtTag) -> Option<Self> {
298        if let Some(reference) = R::from_nbt_tag(tag) {
299            return Some(Self::Reference(reference));
300        };
301        Direct::from_nbt_tag(tag).map(Self::Direct)
302    }
303}
304
305/// A registry which has its values decided by the server in the
306/// `ClientboundRegistryData` packet.
307///
308/// These can be resolved into their actual values with
309/// `ResolvableDataRegistry` from azalea-core.
310pub trait DataRegistry:
311    AzaleaRead + AzaleaWrite + PartialEq + PartialOrd + Ord + Copy + Hash
312{
313    const NAME: &'static str;
314    type Key: DataRegistryKey;
315
316    fn protocol_id(&self) -> u32;
317    fn new_raw(id: u32) -> Self;
318}
319pub trait DataRegistryKey {
320    type Borrow<'a>: DataRegistryKeyRef<'a>;
321
322    fn from_ident(ident: Identifier) -> Self;
323    fn into_ident(self) -> Identifier;
324}
325pub trait DataRegistryKeyRef<'a> {
326    type Owned: DataRegistryKey;
327
328    fn to_owned(self) -> Self::Owned;
329    fn from_ident(ident: &'a Identifier) -> Self;
330    fn into_ident(self) -> Identifier;
331}
332impl<T: DataRegistry> Registry for T {
333    fn from_u32(value: u32) -> Option<Self> {
334        Some(Self::new_raw(value))
335    }
336
337    fn to_u32(&self) -> u32 {
338        self.protocol_id()
339    }
340}