# Adding an Item Behavior This guide details how to implement custom interactive mechanics for an item in Pumpkin. --- ## When Is an Item Behavior Needed? - **Passive Items** (e.g., diamonds, gold ingots, sticks): Do **not** require custom Rust code. Their stack sizes, tool categories, and crafting recipes are handled automatically by `pumpkin-data` and `pumpkin-inventory`. - **Interactive Items** (e.g., snowballs, ender pearls, hoes, bows, potions): Require an implementation of `ItemBehaviour` to handle right-click events, cooldowns, animations, and entity spawns. --- ## Step 1: Define the Item Struct & Metadata Create a new file under `crates/pumpkin/src/item/items/.rs` (e.g., `items/snowball.rs`): ```rust use std::sync::Arc; use pumpkin_data::entity::EntityType; use pumpkin_data::item::Item; use pumpkin_data::sound::{Sound, SoundCategory}; use crate::entity::Entity; use crate::entity::player::Player; use crate::entity::projectile::snowball::SnowballEntity; use crate::item::{ItemBehaviour, ItemMetadata}; pub struct SnowBallItem; // 1. Declare the associated numeric Item ID(s) impl ItemMetadata for SnowBallItem { fn ids() -> Box<[u16]> { [Item::SNOWBALL.id].into() } } // 2. Implement the interaction behavior impl ItemBehaviour for SnowBallItem { fn normal_use(&self, _item: &Item, player: &Player) { let position = player.position(); let world = player.world(); // Play throw sound effect world.play_sound( Sound::EntitySnowballThrow, SoundCategory::Neutral, &position, ); // Construct and launch the projectile entity let entity = Entity::new(world.clone(), position, &EntityType::SNOWBALL); let snowball = SnowballEntity::new_shot(entity, player.get_entity()); let (yaw, pitch) = player.rotation(); snowball.thrown.set_velocity_from(pitch, yaw, 0.0, 1.5, 1.0); world.spawn_entity(Arc::new(snowball)); // Safely decrement held item unless in Creative mode let mut held = player.inventory.held_item(); held.decrement_unless_creative(player.gamemode.load(), 1); player.inventory.set_held_item(held); } } ``` --- ## Step 2: `ItemBehaviour` Hook Reference The `ItemBehaviour` trait provides comprehensive hooks for different interaction models: ### Instant Single-Use Hooks | Hook | Signature | Description | | :--- | :--- | :--- | | `normal_use` | `(&self, item: &Item, player: &Player)` | Triggered on right-clicking into open air. | | `normal_use_with_rotation` | `(&self, item: &Item, player: &Player, yaw: f32, pitch: f32)` | Provides client-reported view angles for precise raycasting and aiming. | | `use_on_block` | `(&self, item: &mut ItemStack, player: &Player, location: BlockPos, face: BlockDirection, cursor_pos: Vector3, block: &Block, server: &Server) -> BlockActionResult` | Triggered when right-clicking a block face (e.g., stripping logs with an axe, tilling farmland with a hoe). | | `use_on_entity` | `(&self, item: &mut ItemStack, player: &Player, entity: Arc)` | Triggered when right-clicking another living entity (e.g., shearing sheep, nametags). | ### Channeled & Timed Hooks | Hook | Signature | Description | | :--- | :--- | :--- | | `get_use_duration` | `(&self) -> i32` | Duration in game ticks required to complete the action (e.g., `32` ticks for food, `72000` ticks for bows). | | `on_use_tick` | `(&self, stack: &ItemStack, player: &Player, remaining_use_ticks: i32)` | Executed on each tick while right-click is held. | | `on_stopped_using` | `(&self, stack: &ItemStack, player: &Player)` | Triggered when the player releases right-click (e.g., firing a charged bow). | --- ## Step 3: Durability & Cooldowns ### Decrementing Stacks Safely Always use `decrement_unless_creative` to ensure survival players consume items while creative players retain them: ```rust item_stack.decrement_unless_creative(player.gamemode.load(), 1); ``` ### Applying Cooldowns To prevent action spamming (e.g., Ender Pearls, Chorus Fruit): ```rust // Start a 20-tick (1-second) cooldown on Ender Pearls player.start_cooldown(Item::ENDER_PEARL.registry_key.to_string(), 20); ``` --- ## Step 4: Registering the Item 1. Export your module in `crates/pumpkin/src/item/items/mod.rs`: ```rust pub mod snowball; ``` 2. Register the struct in `crates/pumpkin/src/item/registry.rs`: ```rust items.register(SnowBallItem); ``` When the server initializes, `items.register` maps the IDs declared in `ItemMetadata::ids()` to your behavior instance.