From c75b89fd89971353ace6502c0353e1d35fda5e46 Mon Sep 17 00:00:00 2001 From: "Eshan I." <2027eiyer@tjhsst.edu> Date: Sun, 9 Aug 2026 09:59:09 -0400 Subject: [PATCH] fix(item): require a non-empty charged list to fire a crossbow (#2805) Item::CROSSBOW ships a ChargedProjectiles component by default, carrying an empty projectile list (crates/pumpkin-data/src/generated/item.rs, the CROSSBOW components table). normal_use tested only for the presence of that component, which is therefore true for every crossbow including a freshly crafted one. The result is that the first right-click on an uncharged crossbow takes the fire branch, fire_projectiles iterates an empty list and does nothing, and charging never starts, so the crossbow cannot be used at all until something else happens to write a non-empty patch. Vanilla gates on the list being present AND non-empty: ChargedProjectiles chargedProjectiles = itemStack.get(DataComponents.CHARGED_PROJECTILES); if (chargedProjectiles != null && !chargedProjectiles.isEmpty()) { (CrossbowItem.java:67-68, 26.2.) Matching that here restores the charge-then-fire cycle. Test plan: - cargo fmt --all - RUSTFLAGS="-D warnings" cargo clippy -p pumpkin --all-targets --- crates/pumpkin/src/item/items/crossbow.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/crates/pumpkin/src/item/items/crossbow.rs b/crates/pumpkin/src/item/items/crossbow.rs index 04b40b59b..bae7fd987 100644 --- a/crates/pumpkin/src/item/items/crossbow.rs +++ b/crates/pumpkin/src/item/items/crossbow.rs @@ -34,9 +34,12 @@ impl ItemBehaviour for CrossbowItem { let inventory = player.inventory(); let stack = inventory.held_item().await; + // Every crossbow carries a ChargedProjectiles component by default, so its mere + // presence does not mean the crossbow is loaded. Vanilla checks the list is also + // non-empty (CrossbowItem.java:68). if stack .get_data_component::() - .is_some() + .is_some_and(|charged| !charged.projectiles.is_empty()) { Self::fire_projectiles(player).await; return;