aboutsummaryrefslogtreecommitdiff
path: root/azalea-inventory/src
diff options
context:
space:
mode:
authormat <27899617+mat-1@users.noreply.github.com>2025-12-09 13:29:59 -0600
committerGitHub <noreply@github.com>2025-12-09 13:29:59 -0600
commit26d619c9a329087a23d6577ee74bd764f50cd773 (patch)
tree8020fe902257764a23a445c6ed9987ea4848189d /azalea-inventory/src
parent84cd261118c9d1e3145d4d1751c0d22098cd8cd8 (diff)
downloadazalea-drasl-26d619c9a329087a23d6577ee74bd764f50cd773.tar.xz
Enchantments (#286)
* start implementing enchants * store parsed registries * more work on enchants * implement deserializer for some entity effects * mostly working definitions for enchants * fix tests * detect equipment changes * fix errors * update changelog * fix some imports * remove outdated todo * add basic test for enchants applying attributes * use git simdnbt
Diffstat (limited to 'azalea-inventory/src')
-rw-r--r--azalea-inventory/src/components/mod.rs76
-rw-r--r--azalea-inventory/src/default_components/generated.rs1
-rw-r--r--azalea-inventory/src/lib.rs20
-rw-r--r--azalea-inventory/src/slot.rs17
4 files changed, 84 insertions, 30 deletions
diff --git a/azalea-inventory/src/components/mod.rs b/azalea-inventory/src/components/mod.rs
index 9c27db8c..87d4256b 100644
--- a/azalea-inventory/src/components/mod.rs
+++ b/azalea-inventory/src/components/mod.rs
@@ -4,6 +4,7 @@ use core::f64;
use std::{
any::Any,
collections::HashMap,
+ fmt::{self, Display},
io::{self, Cursor},
mem::ManuallyDrop,
};
@@ -11,12 +12,13 @@ use std::{
use azalea_buf::{AzBuf, AzaleaRead, AzaleaWrite, BufReadError};
use azalea_chat::FormattedText;
use azalea_core::{
+ attribute_modifier_operation::AttributeModifierOperation,
checksum::{Checksum, get_checksum},
codec_utils::*,
filterable::Filterable,
identifier::Identifier,
position::GlobalPos,
- registry_holder::{DamageTypeElement, RegistryHolder},
+ registry_holder::{RegistryHolder, dimension_type::DamageTypeElement},
sound::CustomSound,
};
use azalea_registry::{
@@ -115,7 +117,7 @@ macro_rules! define_data_components {
}
}
pub fn azalea_read_as(
- kind: registry::DataComponentKind,
+ kind: DataComponentKind,
buf: &mut Cursor<&[u8]>,
) -> Result<Self, BufReadError> {
trace!("Reading data component {kind}");
@@ -131,7 +133,7 @@ macro_rules! define_data_components {
/// `kind` must be the correct value for this union.
pub unsafe fn azalea_write_as(
&self,
- kind: registry::DataComponentKind,
+ kind: DataComponentKind,
buf: &mut impl std::io::Write,
) -> io::Result<()> {
let mut value = Vec::new();
@@ -147,7 +149,7 @@ macro_rules! define_data_components {
/// `kind` must be the correct value for this union.
pub unsafe fn clone_as(
&self,
- kind: registry::DataComponentKind,
+ kind: DataComponentKind,
) -> Self {
match kind {
$( DataComponentKind::$x => {
@@ -161,7 +163,7 @@ macro_rules! define_data_components {
pub unsafe fn eq_as(
&self,
other: &Self,
- kind: registry::DataComponentKind,
+ kind: DataComponentKind,
) -> bool {
match kind {
$( DataComponentKind::$x => unsafe { self.$x.eq(&other.$x) }, )*
@@ -353,11 +355,12 @@ pub enum Rarity {
Epic,
}
-#[derive(Clone, PartialEq, AzBuf, Serialize)]
+#[derive(Clone, PartialEq, AzBuf, Serialize, Default)]
#[serde(transparent)]
pub struct Enchantments {
+ /// Enchantment levels here are 1-indexed, level 0 does not exist.
#[var]
- pub levels: HashMap<Enchantment, u32>,
+ pub levels: HashMap<Enchantment, i32>,
}
#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
@@ -421,14 +424,6 @@ pub enum EquipmentSlotGroup {
Body,
}
-#[derive(Clone, Copy, PartialEq, AzBuf, Debug, Serialize)]
-#[serde(rename_all = "snake_case")]
-pub enum AttributeModifierOperation {
- AddValue,
- AddMultipliedBase,
- AddMultipliedTotal,
-}
-
// this is duplicated in azalea-entity, BUT the one there has a different
// protocol format (and we can't use it anyways because it would cause a
// circular dependency)
@@ -450,7 +445,7 @@ pub struct AttributeModifiersEntry {
pub display: AttributeModifierDisplay,
}
-#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
+#[derive(Clone, PartialEq, AzBuf, Debug, Serialize, Default)]
#[serde(transparent)]
pub struct AttributeModifiers {
pub modifiers: Vec<AttributeModifiersEntry>,
@@ -1108,7 +1103,8 @@ impl Default for Equippable {
}
}
-#[derive(Clone, Copy, Debug, PartialEq, AzBuf, Serialize)]
+/// An enum that represents inventory slots that can hold items.
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, AzBuf, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum EquipmentSlot {
Mainhand,
@@ -1117,9 +1113,55 @@ pub enum EquipmentSlot {
Legs,
Chest,
Head,
+ /// This is for animal armor, use [`Self::Chest`] for the chestplate slot.
Body,
Saddle,
}
+impl EquipmentSlot {
+ #[must_use]
+ pub fn from_byte(byte: u8) -> Option<Self> {
+ let value = match byte {
+ 0 => Self::Mainhand,
+ 1 => Self::Offhand,
+ 2 => Self::Feet,
+ 3 => Self::Legs,
+ 4 => Self::Chest,
+ 5 => Self::Head,
+ _ => return None,
+ };
+ Some(value)
+ }
+ pub fn values() -> [Self; 8] {
+ [
+ Self::Mainhand,
+ Self::Offhand,
+ Self::Feet,
+ Self::Legs,
+ Self::Chest,
+ Self::Head,
+ Self::Body,
+ Self::Saddle,
+ ]
+ }
+ /// Get the display name for the equipment slot, like "mainhand".
+ pub fn name(self) -> &'static str {
+ match self {
+ Self::Mainhand => "mainhand",
+ Self::Offhand => "offhand",
+ Self::Feet => "feet",
+ Self::Legs => "legs",
+ Self::Chest => "chest",
+ Self::Head => "head",
+ Self::Body => "body",
+ Self::Saddle => "saddle",
+ }
+ }
+}
+impl Display for EquipmentSlot {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "{}", self.name())
+ }
+}
#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
pub struct Glider;
diff --git a/azalea-inventory/src/default_components/generated.rs b/azalea-inventory/src/default_components/generated.rs
index 7daa545e..11f8d160 100644
--- a/azalea-inventory/src/default_components/generated.rs
+++ b/azalea-inventory/src/default_components/generated.rs
@@ -6,6 +6,7 @@
use std::collections::HashMap;
use azalea_chat::translatable_component::TranslatableComponent;
+use azalea_core::attribute_modifier_operation::AttributeModifierOperation;
use azalea_registry::{
Attribute, Block, DataRegistry, EntityKind, HolderSet, Item, MobEffect, SoundEvent,
};
diff --git a/azalea-inventory/src/lib.rs b/azalea-inventory/src/lib.rs
index 4a15ea31..87cd61e4 100644
--- a/azalea-inventory/src/lib.rs
+++ b/azalea-inventory/src/lib.rs
@@ -49,10 +49,16 @@ impl Menu {
///
/// Will panic if the menu isn't `Menu::Player`.
pub fn as_player(&self) -> &Player {
+ self.try_as_player()
+ .expect("Called `Menu::as_player` on a menu that wasn't `Player`.")
+ }
+ /// Get the [`Player`] from this [`Menu`], or returns `None` if the menu
+ /// isn't a player menu.
+ pub fn try_as_player(&self) -> Option<&Player> {
if let Menu::Player(player) = &self {
- player
+ Some(player)
} else {
- unreachable!("Called `Menu::as_player` on a menu that wasn't `Player`.")
+ None
}
}
@@ -63,10 +69,16 @@ impl Menu {
///
/// Will panic if the menu isn't `Menu::Player`.
pub fn as_player_mut(&mut self) -> &mut Player {
+ self.try_as_player_mut()
+ .expect("Called `Menu::as_player_mut` on a menu that wasn't `Player`.")
+ }
+ /// Same as [`Menu::try_as_player`], but returns a mutable reference to the
+ /// [`Player`].
+ pub fn try_as_player_mut(&mut self) -> Option<&mut Player> {
if let Menu::Player(player) = self {
- player
+ Some(player)
} else {
- unreachable!("Called `Menu::as_player_mut` on a menu that wasn't `Player`.")
+ None
}
}
}
diff --git a/azalea-inventory/src/slot.rs b/azalea-inventory/src/slot.rs
index d19ab177..c3134214 100644
--- a/azalea-inventory/src/slot.rs
+++ b/azalea-inventory/src/slot.rs
@@ -1,7 +1,7 @@
use std::{
any::Any,
borrow::Cow,
- fmt,
+ fmt::{self, Debug},
io::{self, Cursor, Write},
};
@@ -79,11 +79,10 @@ impl ItemStack {
}
}
- /// Get the `kind` of the item in this slot, or
- /// [`azalea_registry::Item::Air`]
- pub fn kind(&self) -> azalea_registry::Item {
+ /// Get the `kind` of the item in this slot, or [`Item::Air`]
+ pub fn kind(&self) -> Item {
match self {
- ItemStack::Empty => azalea_registry::Item::Air,
+ ItemStack::Empty => Item::Air,
ItemStack::Present(i) => i.kind,
}
}
@@ -152,7 +151,7 @@ impl Serialize for ItemStack {
#[derive(Debug, Clone, PartialEq, Serialize)]
pub struct ItemStackData {
#[serde(rename = "id")]
- pub kind: azalea_registry::Item,
+ pub kind: Item,
/// The amount of the item in this slot.
///
/// The count can be zero or negative, but this is rare.
@@ -184,7 +183,7 @@ impl ItemStackData {
/// Check if the count of the item is <= 0 or if the item is air.
pub fn is_empty(&self) -> bool {
- self.count <= 0 || self.kind == azalea_registry::Item::Air
+ self.count <= 0 || self.kind == Item::Air
}
/// Whether this item is the same as another item, ignoring the count.
@@ -222,7 +221,7 @@ impl AzaleaRead for ItemStack {
if count <= 0 {
Ok(ItemStack::Empty)
} else {
- let kind = azalea_registry::Item::azalea_read(buf)?;
+ let kind = Item::azalea_read(buf)?;
let component_patch = DataComponentPatch::azalea_read(buf)?;
Ok(ItemStack::Present(ItemStackData {
count,
@@ -449,7 +448,7 @@ impl Clone for DataComponentPatch {
DataComponentPatch { components }
}
}
-impl fmt::Debug for DataComponentPatch {
+impl Debug for DataComponentPatch {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_set().entries(self.components.keys()).finish()
}