feat(inventory): implement lore methods for item stack (#3025)

This commit is contained in:
Noël Hagestein
2026-08-23 16:56:26 +02:00
committed by GitHub
parent 89f554ed36
commit f8932f4f3e
7 changed files with 1727 additions and 1631 deletions

View File

@@ -177,8 +177,33 @@ impl DataComponentImpl for ItemModelImpl {
}
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct LoreImpl;
pub struct LoreImpl {
pub lines: Vec<TextComponent>,
}
impl LoreImpl {
pub fn read_data(data: &NbtTag) -> Option<Self> {
let NbtTag::List(lines) = data else {
return None;
};
Some(Self {
lines: lines
.iter()
.filter_map(NbtTag::extract_string)
.map(|line| TextComponent::text(line.to_owned()))
.collect(),
})
}
}
impl DataComponentImpl for LoreImpl {
fn write_data(&self) -> NbtTag {
NbtTag::List(
self.lines
.iter()
.map(|line| NbtTag::String(line.clone().get_text().into_boxed_str()))
.collect(),
)
}
default_impl!(Lore);
}

View File

@@ -539,6 +539,7 @@ pub fn read_data(id: DataComponent, data: &NbtTag) -> Option<Box<dyn DataCompone
DataComponent::Fireworks => Some(FireworksImpl::read_data(data)?.to_dyn()),
DataComponent::FireworkExplosion => Some(FireworkExplosionImpl::read_data(data)?.to_dyn()),
DataComponent::CustomName => Some(CustomNameImpl::read_data(data)?.to_dyn()),
DataComponent::Lore => Some(LoreImpl::read_data(data)?.to_dyn()),
DataComponent::ItemName => Some(ItemNameImpl::read_data(data)?.to_dyn()),
DataComponent::ItemModel => Some(ItemModelImpl::read_data(data)?.to_dyn()),
DataComponent::Consumable => Some(ConsumableImpl::read_data(data)?.to_dyn()),

File diff suppressed because it is too large Load Diff

View File

@@ -206,6 +206,27 @@ impl ItemStack {
}
}
pub fn set_lore(&mut self, lines: Vec<pumpkin_util::text::TextComponent>) {
let lore = Some(Box::new(crate::data_component_impl::LoreImpl { lines }) as _);
if let Some((_, component)) = self
.patch
.iter_mut()
.find(|(id, _)| *id == DataComponent::Lore)
{
*component = lore;
} else {
self.patch.push((DataComponent::Lore, lore));
}
}
pub fn add_lore(&mut self, line: pumpkin_util::text::TextComponent) {
let mut lines = self
.get_data_component::<crate::data_component_impl::LoreImpl>()
.map_or_else(Vec::new, |lore| lore.lines.clone());
lines.push(line);
self.set_lore(lines);
}
pub const EMPTY: &'static Self = &Self {
item_count: 0,
item: &Item::AIR,
@@ -745,7 +766,7 @@ mod tests {
use crate::data_component::DataComponent;
use crate::data_component_impl::{
CustomDataImpl, CustomNameImpl, DataComponentImpl, EnchantmentsImpl, ItemNameImpl,
UnbreakableImpl,
LoreImpl, UnbreakableImpl,
};
/// Helper: creates a fresh Iron Sword (max_damage 250, damage 0).
@@ -906,6 +927,20 @@ mod tests {
);
}
#[test]
fn lore_can_be_set_and_appended() {
let mut stack = ItemStack::new(1, &Item::WOODEN_AXE);
stack.set_lore(vec![pumpkin_util::text::TextComponent::text("First line")]);
stack.add_lore(pumpkin_util::text::TextComponent::text("Second line"));
let lore = stack
.get_data_component::<LoreImpl>()
.expect("lore component should be present");
assert_eq!(lore.lines.len(), 2);
assert_eq!(lore.lines[0].clone().get_text(), "First line");
assert_eq!(lore.lines[1].clone().get_text(), "Second line");
}
#[test]
fn custom_data_survives_item_stack_nbt_roundtrip() {
let mut stack = ItemStack::new(1, &Item::WOODEN_AXE);