From e5047bd4c99febacbd60141f73f11c61fe9c8191 Mon Sep 17 00:00:00 2001 From: Alexander Medvedev Date: Sat, 8 Aug 2026 16:12:56 +0200 Subject: [PATCH] fix: data component try_from_name --- .../src/data_component_impl/combat.rs | 22 +++++++-- .../src/data_component_impl/mod.rs | 47 +++++++++++++++++-- .../src/generated/data_component.rs | 7 ++- .../pumpkin-data/src/generated/enchantment.rs | 7 ++- tools/pumpkin-codegen/src/data_component.rs | 2 +- tools/pumpkin-codegen/src/enchantments.rs | 2 +- 6 files changed, 74 insertions(+), 13 deletions(-) diff --git a/crates/pumpkin-data/src/data_component_impl/combat.rs b/crates/pumpkin-data/src/data_component_impl/combat.rs index ea8c2bf05..22f8c1c41 100644 --- a/crates/pumpkin-data/src/data_component_impl/combat.rs +++ b/crates/pumpkin-data/src/data_component_impl/combat.rs @@ -54,10 +54,17 @@ pub struct EnchantmentsImpl { } impl EnchantmentsImpl { pub fn read_data(data: &NbtTag) -> Option { - let data = &data.extract_compound()?.child_tags; + let compound = data.extract_compound()?; + let data = if let Some(NbtTag::Compound(levels)) = compound.child_tags.get("levels") { + &levels.child_tags + } else { + &compound.child_tags + }; let mut enc = Vec::with_capacity(data.len()); for (name, level) in data { - enc.push((Enchantment::from_name(name.as_ref())?, level.extract_int()?)); + let enchantment = Enchantment::from_name(name.as_ref()) + .or_else(|| Enchantment::from_name(&format!("minecraft:{name}")))?; + enc.push((enchantment, level.extract_int()?)); } Some(Self { enchantment: Cow::from(enc), @@ -597,10 +604,17 @@ pub struct StoredEnchantmentsImpl { } impl StoredEnchantmentsImpl { pub fn read_data(data: &NbtTag) -> Option { - let data = &data.extract_compound()?.child_tags; + let compound = data.extract_compound()?; + let data = if let Some(NbtTag::Compound(levels)) = compound.child_tags.get("levels") { + &levels.child_tags + } else { + &compound.child_tags + }; let mut enc = Vec::with_capacity(data.len()); for (name, level) in data { - enc.push((Enchantment::from_name(name.as_ref())?, level.extract_int()?)); + let enchantment = Enchantment::from_name(name.as_ref()) + .or_else(|| Enchantment::from_name(&format!("minecraft:{name}")))?; + enc.push((enchantment, level.extract_int()?)); } Some(Self { enchantment: Cow::from(enc), diff --git a/crates/pumpkin-data/src/data_component_impl/mod.rs b/crates/pumpkin-data/src/data_component_impl/mod.rs index 6b1a59b58..6432be3e5 100644 --- a/crates/pumpkin-data/src/data_component_impl/mod.rs +++ b/crates/pumpkin-data/src/data_component_impl/mod.rs @@ -42,9 +42,11 @@ impl Clone for Box { pub fn get(value: &dyn DataComponentImpl) -> &T { value.as_any().downcast_ref::().unwrap_or_else(|| { panic!( - "you are trying to cast {} to {}", + "you are trying to cast {} ({}) to {} ({})", value.get_self_enum().to_name(), - T::get_enum().to_name() + std::any::type_name_of_val(value), + T::get_enum().to_name(), + std::any::type_name::() ) }) } @@ -52,10 +54,12 @@ pub fn get(value: &dyn DataComponentImpl) -> &T #[inline] pub fn get_mut(value: &mut dyn DataComponentImpl) -> &mut T { let name = value.get_self_enum().to_name(); + let val_type = std::any::type_name_of_val(value); value.as_mut_any().downcast_mut::().unwrap_or_else(|| { panic!( - "you are trying to cast {name} to {}", - T::get_enum().to_name() + "you are trying to cast {name} ({val_type}) to {} ({})", + T::get_enum().to_name(), + std::any::type_name::() ) }) } @@ -63,7 +67,11 @@ pub fn get_mut(value: &mut dyn DataComponentImpl macro_rules! default_impl { ($t: ident) => { fn equal(&self, other: &dyn crate::data_component_impl::DataComponentImpl) -> bool { - self == crate::data_component_impl::get::(other) + if let Some(other) = other.as_any().downcast_ref::() { + self == other + } else { + false + } } #[inline] fn get_enum() -> crate::data_component::DataComponent @@ -745,4 +753,33 @@ mod tests { ); assert_round_trip(LockImpl { predicate }, LockImpl::read_data); } + + #[test] + fn equal_with_different_types_returns_false() { + let enc = EnchantmentsImpl { + enchantment: Cow::Borrowed(&[(&crate::Enchantment::SHARPNESS, 2)]), + }; + let max_stack = MaxStackSizeImpl { size: 64 }; + assert!(!enc.equal(&max_stack)); + } + + #[test] + fn enchantments_read_data_formats() { + let mut direct = NbtCompound::new(); + direct.put_int("sharpness", 2); + let enc1 = EnchantmentsImpl::read_data(&NbtTag::Compound(direct)).unwrap(); + assert!(enc1.enchantment[0].0 == &crate::Enchantment::SHARPNESS); + assert_eq!(enc1.enchantment[0].1, 2); + + let mut levels = NbtCompound::new(); + levels.put_int("minecraft:sharpness", 2); + let mut wrapped = NbtCompound::new(); + wrapped + .child_tags + .insert("levels".into(), NbtTag::Compound(levels)); + let enc2 = EnchantmentsImpl::read_data(&NbtTag::Compound(wrapped)).unwrap(); + assert_eq!(enc2.enchantment.len(), 1); + assert!(enc2.enchantment[0].0 == &crate::Enchantment::SHARPNESS); + assert_eq!(enc2.enchantment[0].1, 2); + } } diff --git a/crates/pumpkin-data/src/generated/data_component.rs b/crates/pumpkin-data/src/generated/data_component.rs index c266d4ff5..ebaef149f 100644 --- a/crates/pumpkin-data/src/generated/data_component.rs +++ b/crates/pumpkin-data/src/generated/data_component.rs @@ -240,7 +240,12 @@ impl DataComponent { #[must_use] #[allow(clippy::too_many_lines)] pub fn try_from_name(name: &str) -> Option { - match name { + let name = if name.contains(':') { + std::borrow::Cow::Borrowed(name) + } else { + std::borrow::Cow::Owned(format!("minecraft:{name}")) + }; + match name.as_ref() { "minecraft:custom_data" => Some(Self::CustomData), "minecraft:max_stack_size" => Some(Self::MaxStackSize), "minecraft:max_damage" => Some(Self::MaxDamage), diff --git a/crates/pumpkin-data/src/generated/enchantment.rs b/crates/pumpkin-data/src/generated/enchantment.rs index 9fd05acc4..2e1d14f68 100644 --- a/crates/pumpkin-data/src/generated/enchantment.rs +++ b/crates/pumpkin-data/src/generated/enchantment.rs @@ -984,7 +984,12 @@ impl Enchantment { }, }; pub fn from_name(name: &str) -> Option<&'static Self> { - match name { + let name = if name.contains(':') { + std::borrow::Cow::Borrowed(name) + } else { + std::borrow::Cow::Owned(format!("minecraft:{name}")) + }; + match name.as_ref() { "minecraft:aqua_affinity" => Some(&Self::AQUA_AFFINITY), "minecraft:bane_of_arthropods" => Some(&Self::BANE_OF_ARTHROPODS), "minecraft:binding_curse" => Some(&Self::BINDING_CURSE), diff --git a/tools/pumpkin-codegen/src/data_component.rs b/tools/pumpkin-codegen/src/data_component.rs index b55af5c07..52c8a44d9 100644 --- a/tools/pumpkin-codegen/src/data_component.rs +++ b/tools/pumpkin-codegen/src/data_component.rs @@ -36,7 +36,7 @@ pub fn build() -> TokenStream { // TODO use phf name_to_enum.extend(quote! { - #raw_name => Some(Self::#pascal_case), + #raw_name | #strip_name => Some(Self::#pascal_case), }); // Enum -> &str diff --git a/tools/pumpkin-codegen/src/enchantments.rs b/tools/pumpkin-codegen/src/enchantments.rs index de12b8626..fcb57bb22 100644 --- a/tools/pumpkin-codegen/src/enchantments.rs +++ b/tools/pumpkin-codegen/src/enchantments.rs @@ -187,7 +187,7 @@ pub fn build() -> TokenStream { }]); } - name_to_type.extend(quote! { #name => Some(&Self::#format_name), }); + name_to_type.extend(quote! { #name | #raw_name => Some(&Self::#format_name), }); id_to_type.extend(quote! { #id => Some(&Self::#format_name), }); }