Skip to main content

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::{AzBuf, AzBufVar, 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: AzBuf + 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> AzBuf 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    fn azalea_write(&self, buf: &mut impl Write) -> io::Result<()> {
83        match &self.0 {
84            None => 0u32.azalea_write_var(buf),
85            Some(value) => (value.to_u32() + 1).azalea_write_var(buf),
86        }
87    }
88}
89
90/// A registry that will either take an ID or a resource location.
91#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
92pub enum CustomRegistry<D: Registry, C: AzBuf> {
93    Direct(D),
94    Custom(C),
95}
96
97impl<D: Registry, C: AzBuf> AzBuf for CustomRegistry<D, C> {
98    fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
99        let direct_registry = OptionalRegistry::<D>::azalea_read(buf)?;
100        if let Some(direct_registry) = direct_registry.0 {
101            return Ok(CustomRegistry::Direct(direct_registry));
102        }
103        Ok(CustomRegistry::Custom(C::azalea_read(buf)?))
104    }
105    fn azalea_write(&self, buf: &mut impl Write) -> io::Result<()> {
106        match self {
107            CustomRegistry::Direct(direct_registry) => {
108                // write the id + 1
109                (direct_registry.to_u32() + 1).azalea_write_var(buf)
110            }
111            CustomRegistry::Custom(custom_registry) => {
112                // write 0, then the custom registry
113                0u32.azalea_write_var(buf)?;
114                custom_registry.azalea_write(buf)
115            }
116        }
117    }
118}
119
120#[derive(Clone, PartialEq)]
121pub enum HolderSet<D: Registry, Identifier: AzBuf> {
122    Direct {
123        contents: Vec<D>,
124    },
125    Named {
126        key: Identifier,
127        contents: Vec<Identifier>,
128    },
129}
130impl<D: Registry, Identifier: AzBuf> AzBuf for HolderSet<D, Identifier> {
131    fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
132        let size = i32::azalea_read_var(buf)?.wrapping_sub(1);
133        if size == -1 {
134            let key = Identifier::azalea_read(buf)?;
135            Ok(Self::Named {
136                key,
137                contents: Vec::new(),
138            })
139        } else {
140            let mut contents = Vec::new();
141            for _ in 0..size {
142                contents.push(D::azalea_read(buf)?);
143            }
144            Ok(Self::Direct { contents })
145        }
146    }
147    fn azalea_write(&self, buf: &mut impl Write) -> io::Result<()> {
148        match self {
149            Self::Direct { contents } => {
150                (contents.len() as i32 + 1).azalea_write_var(buf)?;
151                for item in contents {
152                    item.azalea_write(buf)?;
153                }
154            }
155            Self::Named { key, contents: _ } => {
156                0i32.azalea_write_var(buf)?;
157                key.azalea_write(buf)?;
158            }
159        }
160        Ok(())
161    }
162}
163impl<D: Registry + Debug, Identifier: AzBuf + Debug> Debug for HolderSet<D, Identifier> {
164    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
165        match self {
166            Self::Direct { contents } => f.debug_list().entries(contents).finish(),
167            Self::Named { key, contents } => f
168                .debug_struct("Named")
169                .field("key", key)
170                .field("contents", contents)
171                .finish(),
172        }
173    }
174}
175impl<D: Registry, Identifier: AzBuf> From<Vec<D>> for HolderSet<D, Identifier> {
176    fn from(contents: Vec<D>) -> Self {
177        Self::Direct { contents }
178    }
179}
180#[cfg(feature = "serde")]
181impl<D: Registry + Serialize, Identifier: AzBuf + Serialize> Serialize
182    for HolderSet<D, Identifier>
183{
184    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
185    where
186        S: serde::Serializer,
187    {
188        match self {
189            Self::Direct { contents } => {
190                if contents.len() == 1 {
191                    contents[0].serialize(serializer)
192                } else {
193                    contents.serialize(serializer)
194                }
195            }
196            Self::Named { key, contents: _ } => key.serialize(serializer),
197        }
198    }
199}
200impl<D: Registry, Identifier: AzBuf> Default for HolderSet<D, Identifier> {
201    fn default() -> Self {
202        Self::Direct {
203            contents: Vec::new(),
204        }
205    }
206}
207impl<D: Registry, Identifier: AzBuf + From<D> + PartialEq> HolderSet<D, Identifier> {
208    pub fn contains(&self, value: D) -> bool {
209        match self {
210            HolderSet::Direct { contents } => contents.contains(&value),
211            HolderSet::Named { key: _, contents } => contents.contains(&Identifier::from(value)),
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: AzBuf> {
219    Reference(R),
220    Direct(Direct),
221}
222impl<R: Registry, Direct: AzBuf> AzBuf 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    fn azalea_write(&self, buf: &mut impl Write) -> io::Result<()> {
236        match self {
237            Self::Reference(value) => (value.to_u32() + 1).azalea_write_var(buf),
238            Self::Direct(value) => {
239                0u32.azalea_write_var(buf)?;
240                value.azalea_write(buf)
241            }
242        }
243    }
244}
245impl<R: Registry + Debug, Direct: AzBuf + Debug> Debug for Holder<R, Direct> {
246    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
247        match self {
248            Self::Reference(value) => f.debug_tuple("Reference").field(value).finish(),
249            Self::Direct(value) => f.debug_tuple("Direct").field(value).finish(),
250        }
251    }
252}
253impl<R: Registry + Clone, Direct: AzBuf + Clone> Clone for Holder<R, Direct> {
254    fn clone(&self) -> Self {
255        match self {
256            Self::Reference(value) => Self::Reference(*value),
257            Self::Direct(value) => Self::Direct(value.clone()),
258        }
259    }
260}
261impl<R: Registry + PartialEq, Direct: AzBuf + PartialEq> PartialEq for Holder<R, Direct> {
262    fn eq(&self, other: &Self) -> bool {
263        match (self, other) {
264            (Self::Reference(a), Self::Reference(b)) => a == b,
265            (Self::Direct(a), Self::Direct(b)) => a == b,
266            _ => false,
267        }
268    }
269}
270impl<R: Registry + Default, Direct: AzBuf> Default for Holder<R, Direct> {
271    fn default() -> Self {
272        Self::Reference(R::default())
273    }
274}
275#[cfg(feature = "serde")]
276impl<R: Registry + Serialize, Direct: AzBuf + Serialize> Serialize for Holder<R, Direct> {
277    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
278    where
279        S: serde::Serializer,
280    {
281        match self {
282            Self::Reference(value) => value.serialize(serializer),
283            Self::Direct(value) => value.serialize(serializer),
284        }
285    }
286}
287
288impl<R: Registry + FromNbtTag, Direct: AzBuf + FromNbtTag> FromNbtTag for Holder<R, Direct> {
289    fn from_nbt_tag(tag: NbtTag) -> Option<Self> {
290        if let Some(reference) = R::from_nbt_tag(tag) {
291            return Some(Self::Reference(reference));
292        };
293        Direct::from_nbt_tag(tag).map(Self::Direct)
294    }
295}
296
297/// A registry which has its values decided by the server in the
298/// `ClientboundRegistryData` packet.
299///
300/// These can be resolved into their actual values with
301/// `ResolvableDataRegistry` from azalea-core.
302pub trait DataRegistry: AzBuf + PartialEq + PartialOrd + Ord + Copy + Hash {
303    const NAME: &'static str;
304    type Key: DataRegistryKey;
305
306    fn protocol_id(&self) -> u32;
307    fn new_raw(id: u32) -> Self;
308}
309pub trait DataRegistryKey {
310    type Borrow<'a>: DataRegistryKeyRef<'a>;
311
312    fn from_ident(ident: Identifier) -> Self;
313    fn into_ident(self) -> Identifier;
314}
315pub trait DataRegistryKeyRef<'a> {
316    type Owned: DataRegistryKey;
317
318    fn to_owned(self) -> Self::Owned;
319    fn from_ident(ident: &'a Identifier) -> Self;
320    fn into_ident(self) -> Identifier;
321}
322impl<T: DataRegistry> Registry for T {
323    fn from_u32(value: u32) -> Option<Self> {
324        Some(Self::new_raw(value))
325    }
326
327    fn to_u32(&self) -> u32 {
328        self.protocol_id()
329    }
330}