steel_core/entity/projectile/throwable_item.rs
1//! Vanilla `ThrowableItemProjectile` — carries a synced rendered item stack.
2//!
3//! Vanilla stores the item in `DATA_ITEM_STACK` (synced entity data). Steel keeps
4//! it in the generated `*EntityData` layer, so this trait has no base struct: the
5//! concrete entity implements [`ThrowableItemProjectile::set_item`] /
6//! [`ThrowableItemProjectile::get_item`] against its synced data.
7
8use simdnbt::ToNbtTag;
9use simdnbt::borrow::NbtCompound as BorrowedNbtCompoundView;
10use simdnbt::owned::NbtCompound;
11use steel_registry::item_stack::ItemStack;
12use steel_registry::items::ItemRef;
13
14use crate::entity::projectile::ThrowableProjectile;
15
16/// Vanilla-shaped behavior shared by entities that extend `ThrowableItemProjectile`.
17pub trait ThrowableItemProjectile: ThrowableProjectile {
18 /// Returns the item stack used when no persisted item can be loaded
19 /// (e.g. a plain ender pearl, snowball, or egg).
20 fn get_default_item(&self) -> ItemRef;
21
22 /// Sets the rendered item stack (vanilla `setItem`, count clamped to 1).
23 ///
24 /// The concrete entity stores this in its synced data layer.
25 fn set_item(&self, item: ItemStack);
26
27 /// Returns the rendered item stack (vanilla `getItem`).
28 fn get_item(&self) -> ItemStack;
29
30 /// Sets the rendered item stack, clamping its count to 1.
31 fn set_item_clamped(&self, item: ItemStack) {
32 self.set_item(item.copy_with_count(1));
33 }
34
35 /// Saves the item stack to NBT, omitting the tag entirely when the stack is empty.
36 fn save_throwable_item(&self, nbt: &mut NbtCompound) {
37 let item = self.get_item();
38 if !item.is_empty() {
39 nbt.insert("Item", item.to_nbt_tag());
40 }
41 }
42
43 /// Loads the item stack, falling back to the default item (vanilla
44 /// `readAdditionalSaveData`).
45 fn load_throwable_item(&self, nbt: BorrowedNbtCompoundView<'_, '_>) {
46 let item = nbt
47 .compound("Item")
48 .and_then(|tag| ItemStack::from_borrowed_compound(&tag))
49 .unwrap_or_else(|| ItemStack::new(self.get_default_item()));
50 self.set_item_clamped(item);
51 }
52}