From 03a90a40b167957580b6b9a2e922c8aae5071ef6 Mon Sep 17 00:00:00 2001 From: Alexander Medvedev Date: Sat, 27 Jun 2026 10:35:46 +0200 Subject: [PATCH] chore: expand loot table --- pumpkin-codegen/src/advancement.rs | 14 +- pumpkin-codegen/src/block.rs | 2 +- pumpkin-codegen/src/game_rules.rs | 4 +- pumpkin-codegen/src/loot.rs | 31 +- pumpkin-data/src/data_component_impl.rs | 87 ++- pumpkin-data/src/generated/block.rs | 4 +- pumpkin-data/src/generated/entity_type.rs | 732 +++++++++++++++++++--- pumpkin-util/src/loot_table.rs | 15 +- pumpkin/src/entity/living.rs | 26 +- pumpkin/src/entity/vehicle/vehicle.rs | 9 +- pumpkin/src/world/explosion.rs | 4 + pumpkin/src/world/loot.rs | 216 ++++++- pumpkin/src/world/mod.rs | 20 +- 13 files changed, 1015 insertions(+), 149 deletions(-) diff --git a/pumpkin-codegen/src/advancement.rs b/pumpkin-codegen/src/advancement.rs index 6a496cfe6..cf16ed3d8 100644 --- a/pumpkin-codegen/src/advancement.rs +++ b/pumpkin-codegen/src/advancement.rs @@ -548,12 +548,15 @@ impl TreeNodePosition { ) { inner_left = next_inner_left; inner_right = next_inner_right; - outer_left = Self::previous_or_thread(nodes, outer_left).expect("Tree invariant broken"); + outer_left = + Self::previous_or_thread(nodes, outer_left).expect("Tree invariant broken"); outer_right = Self::next_or_thread(nodes, outer_right).expect("Tree invariant broken"); nodes[outer_right].ancestor = idx; - let shift = (nodes[inner_left].y + shift_inner_left) - (nodes[inner_right].y + shift_inner_right) + 1.0; + let shift = (nodes[inner_left].y + shift_inner_left) + - (nodes[inner_right].y + shift_inner_right) + + 1.0; if shift > 0.0 { let ancestor_idx = Self::get_ancestor(nodes, inner_left, idx, default_ancestor); Self::move_subtree(nodes, ancestor_idx, idx, shift); @@ -659,7 +662,7 @@ pub struct AdvancementStruct { pub sends_telemetry: bool, pub requirements: Vec>, #[serde(deserialize_with = "deserialize_first_key")] - pub criteria : Vec, + pub criteria: Vec, } fn deserialize_first_key<'de, D>(deserializer: D) -> Result, D::Error> @@ -846,10 +849,7 @@ pub(crate) fn build() -> TokenStream { let advancement_tree = quote! { pub static ADVANCEMENT_TREE : LazyLock = #tree; }; - let advancements_holder = tree - .nodes_vector - .into_iter() - .map(|node| node.value); + let advancements_holder = tree.nodes_vector.into_iter().map(|node| node.value); for AdvancementHolder(identifier, advancement) in advancements_holder { let raw_name = identifier.path(); let format_name = format_ident!("{}", raw_name.to_shouty_snake_case()); diff --git a/pumpkin-codegen/src/block.rs b/pumpkin-codegen/src/block.rs index 33292bc2e..baba0ca8f 100644 --- a/pumpkin-codegen/src/block.rs +++ b/pumpkin-codegen/src/block.rs @@ -1250,7 +1250,7 @@ pub fn build() -> TokenStream { #state_from_state_id ]; } - + impl Block { #(#constants_list)* diff --git a/pumpkin-codegen/src/game_rules.rs b/pumpkin-codegen/src/game_rules.rs index 8bc1fba6c..a0400be31 100644 --- a/pumpkin-codegen/src/game_rules.rs +++ b/pumpkin-codegen/src/game_rules.rs @@ -29,7 +29,9 @@ pub fn build() -> TokenStream { (quote! { Int }, quote! { i64 }, quote! { #i }) } Value::Object(obj) => { - let default_val = obj.get("default").expect("Object game rule missing default value"); + let default_val = obj + .get("default") + .expect("Object game rule missing default value"); match default_val { Value::Number(n) if n.is_i64() => { let i = n.as_i64().unwrap(); diff --git a/pumpkin-codegen/src/loot.rs b/pumpkin-codegen/src/loot.rs index 3d730f718..679defe23 100644 --- a/pumpkin-codegen/src/loot.rs +++ b/pumpkin-codegen/src/loot.rs @@ -281,9 +281,8 @@ impl ToTokens for LootPoolEntryTypesStruct { Self::LootTable(entry) => { tokens.extend(quote! { LootPoolEntryTypes::LootTable(#entry) }); } - Self::Dynamic(_entry) => { - // TODO - tokens.extend(quote! { LootPoolEntryTypes::Dynamic }); + Self::Dynamic(entry) => { + tokens.extend(quote! { LootPoolEntryTypes::Dynamic(#entry) }); } Self::Tag(entry) => { tokens.extend(quote! { LootPoolEntryTypes::Tag(#entry) }); @@ -662,13 +661,17 @@ pub enum LootFunctionTypesStruct { }, /// Increases count based on the level of a relevant enchantment. #[serde(rename = "minecraft:enchanted_count_increase")] - EnchantedCountIncrease, + EnchantedCountIncrease { + enchantment: String, + count: LootFunctionNumberProviderStruct, + limit: Option, + }, /// Smelts the item as if processed in a furnace. #[serde(rename = "minecraft:furnace_smelt")] FurnaceSmelt, /// Sets the potion type on the item. #[serde(rename = "minecraft:set_potion")] - SetPotion, + SetPotion { id: String }, /// Sets the amplifier on an ominous bottle item. #[serde(rename = "minecraft:set_ominous_bottle_amplifier")] SetOminousBottleAmplifier, @@ -724,11 +727,21 @@ impl ToTokens for LootFunctionTypesStruct { Self::FurnaceSmelt => { quote! { LootFunctionTypes::FurnaceSmelt } } - Self::SetPotion => { - quote! { LootFunctionTypes::SetPotion } + Self::SetPotion { id } => { + let i = LitStr::new(id, Span::call_site()); + quote! { LootFunctionTypes::SetPotion { id: #i } } } - Self::EnchantedCountIncrease => { - quote! { LootFunctionTypes::EnchantedCountIncrease } + Self::EnchantedCountIncrease { + enchantment, + count, + limit, + } => { + let e = LitStr::new(enchantment, Span::call_site()); + let c = count.to_token_stream(); + let l = limit + .map(|val| quote! { Some(#val) }) + .unwrap_or(quote! { None }); + quote! { LootFunctionTypes::EnchantedCountIncrease { enchantment: #e, count: #c, limit: #l } } } Self::LimitCount { limit } => { let min = if let Some(min) = limit.min { diff --git a/pumpkin-data/src/data_component_impl.rs b/pumpkin-data/src/data_component_impl.rs index d2d88a7ad..4bd8d77a8 100644 --- a/pumpkin-data/src/data_component_impl.rs +++ b/pumpkin-data/src/data_component_impl.rs @@ -3,11 +3,11 @@ use crate::attributes::Attributes; use crate::data_component::DataComponent; use crate::data_component::DataComponent::{ - AttributeModifiers, BlockEntityData, BlocksAttacks, BundleContents, ChargedProjectiles, - Consumable, Container, CustomData, CustomName, Damage, DamageResistant, DeathProtection, - Enchantable, Enchantments, Equippable, FireworkExplosion, Fireworks, Food, ItemModel, ItemName, - JukeboxPlayable, MapId, MaxDamage, MaxStackSize, PotionContents, StoredEnchantments, Tool, - Unbreakable, UseCooldown, Weapon, + AttributeModifiers, BlockEntityData, BlockState, BlocksAttacks, BundleContents, + ChargedProjectiles, Consumable, Container, CustomData, CustomName, Damage, DamageResistant, + DeathProtection, Enchantable, Enchantments, Equippable, FireworkExplosion, Fireworks, Food, + ItemModel, ItemName, JukeboxPlayable, MapId, MaxDamage, MaxStackSize, OminousBottleAmplifier, + PotionContents, StoredEnchantments, Tool, Unbreakable, UseCooldown, Weapon, }; use crate::effect::{self, StatusEffect}; use crate::entity_type::EntityType; @@ -29,6 +29,7 @@ use std::error::Error; use std::fmt::Debug; use std::str::FromStr; use std::{ + collections::HashMap, collections::hash_map::DefaultHasher, hash::{Hash, Hasher}, }; @@ -81,6 +82,10 @@ pub fn read_data(id: DataComponent, data: &NbtTag) -> Option { Some(WritableBookContentImpl::read_data(data)?.to_dyn()) } + DataComponent::OminousBottleAmplifier => { + Some(OminousBottleAmplifierImpl::read_data(data)?.to_dyn()) + } + DataComponent::BlockState => Some(BlockStateImpl::read_data(data)?.to_dyn()), _ => None, } } @@ -2062,7 +2067,23 @@ pub struct InstrumentImpl; #[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct ProvidesTrimMaterialImpl; #[derive(Clone, Debug, Hash, PartialEq, Eq)] -pub struct OminousBottleAmplifierImpl; +pub struct OminousBottleAmplifierImpl { + pub amplifier: i32, +} +impl OminousBottleAmplifierImpl { + fn read_data(data: &NbtTag) -> Option { + data.extract_int().map(|amplifier| Self { amplifier }) + } +} +impl DataComponentImpl for OminousBottleAmplifierImpl { + fn write_data(&self) -> NbtTag { + NbtTag::Int(self.amplifier) + } + fn get_hash(&self) -> i32 { + get_i32_hash(self.amplifier) as i32 + } + default_impl!(OminousBottleAmplifier); +} #[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct JukeboxPlayableImpl { pub song: &'static str, @@ -2311,8 +2332,58 @@ impl ContainerImpl { impl DataComponentImpl for ContainerImpl { default_impl!(Container); } -#[derive(Clone, Debug, Hash, PartialEq, Eq)] -pub struct BlockStateImpl; +#[derive(Clone, Debug)] +pub struct BlockStateImpl { + pub properties: HashMap, +} +impl PartialEq for BlockStateImpl { + fn eq(&self, other: &Self) -> bool { + self.properties == other.properties + } +} +impl Eq for BlockStateImpl {} +impl std::hash::Hash for BlockStateImpl { + fn hash(&self, state: &mut H) { + let mut keys: Vec<&String> = self.properties.keys().collect(); + keys.sort(); + for key in keys { + key.hash(state); + self.properties.get(key).hash(state); + } + } +} +impl BlockStateImpl { + fn read_data(data: &NbtTag) -> Option { + let compound = data.extract_compound()?; + let mut properties = HashMap::new(); + for (key, val) in compound.child_tags.iter() { + if let Some(s) = val.extract_string() { + properties.insert(key.to_string(), s.to_string()); + } + } + Some(Self { properties }) + } +} +impl DataComponentImpl for BlockStateImpl { + fn write_data(&self) -> NbtTag { + let mut compound = NbtCompound::new(); + for (k, v) in &self.properties { + compound.put_string(k, v.clone()); + } + NbtTag::Compound(compound) + } + fn get_hash(&self) -> i32 { + let mut digest = Digest::new(Crc32Iscsi); + let mut keys: Vec<&String> = self.properties.keys().collect(); + keys.sort(); + for key in keys { + digest.update(key.as_bytes()); + digest.update(self.properties.get(key).unwrap().as_bytes()); + } + digest.finalize() as i32 + } + default_impl!(BlockState); +} #[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct BeesImpl; #[derive(Clone, Debug, Hash, PartialEq, Eq)] diff --git a/pumpkin-data/src/generated/block.rs b/pumpkin-data/src/generated/block.rs index 4a6ea41a6..4ba677afb 100644 --- a/pumpkin-data/src/generated/block.rs +++ b/pumpkin-data/src/generated/block.rs @@ -532782,7 +532782,9 @@ impl Block { content: LootPoolEntryTypes::Alternatives(AlternativeEntry { children: &[ LootPoolEntry { - content: LootPoolEntryTypes::Dynamic, + content: LootPoolEntryTypes::Dynamic(DynamicEntry { + name: "minecraft:sherds", + }), weight: 1i32, quality: 0i32, conditions: Some(&[LootCondition::BlockStateProperty { diff --git a/pumpkin-data/src/generated/entity_type.rs b/pumpkin-data/src/generated/entity_type.rs index 557b0185b..8767da384 100644 --- a/pumpkin-data/src/generated/entity_type.rs +++ b/pumpkin-data/src/generated/entity_type.rs @@ -719,7 +719,14 @@ impl EntityType { conditions: None, }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, ]), @@ -826,7 +833,14 @@ impl EntityType { conditions: None, }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, ]), @@ -856,7 +870,14 @@ impl EntityType { conditions: None, }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, ]), @@ -886,11 +907,20 @@ impl EntityType { conditions: None, }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: Some(1f32), + }, conditions: None, }, LootFunction { - content: LootFunctionTypes::SetPotion, + content: LootFunctionTypes::SetPotion { + id: "minecraft:poison", + }, conditions: None, }, ]), @@ -975,7 +1005,14 @@ impl EntityType { conditions: None, }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 1f32, + max: 2f32, + }, + limit: None, + }, conditions: None, }, ]), @@ -1136,7 +1173,14 @@ impl EntityType { conditions: None, }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, ]), @@ -1300,7 +1344,14 @@ impl EntityType { conditions: None, }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, ]), @@ -1330,7 +1381,14 @@ impl EntityType { conditions: None, }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, ]), @@ -1482,7 +1540,14 @@ impl EntityType { conditions: None, }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, ]), @@ -1515,7 +1580,14 @@ impl EntityType { ])]), }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, ]), @@ -1718,7 +1790,14 @@ impl EntityType { conditions: None, }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, ]), @@ -1803,7 +1882,14 @@ impl EntityType { conditions: None, }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, ]), @@ -1846,7 +1932,14 @@ impl EntityType { ])]), }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, ]), @@ -1987,7 +2080,14 @@ impl EntityType { conditions: None, }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, ]), @@ -2135,7 +2235,14 @@ impl EntityType { conditions: None, }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, LootFunction { @@ -2232,7 +2339,14 @@ impl EntityType { conditions: None, }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, ]), @@ -2340,7 +2454,14 @@ impl EntityType { conditions: None, }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, ]), @@ -2469,7 +2590,14 @@ impl EntityType { conditions: None, }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, ]), @@ -2490,7 +2618,14 @@ impl EntityType { conditions: None, functions: Some(&[ LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, LootFunction { @@ -2516,7 +2651,14 @@ impl EntityType { quality: 0i32, conditions: None, functions: Some(&[LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }]), }, @@ -2778,7 +2920,14 @@ impl EntityType { conditions: None, }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, ]), @@ -2933,7 +3082,14 @@ impl EntityType { conditions: None, }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, ]), @@ -3329,7 +3485,14 @@ impl EntityType { conditions: None, }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, ]), @@ -3359,7 +3522,14 @@ impl EntityType { conditions: None, }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, ]), @@ -3547,7 +3717,14 @@ impl EntityType { conditions: None, }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, ]), @@ -3688,7 +3865,14 @@ impl EntityType { conditions: None, }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, ]), @@ -3709,7 +3893,14 @@ impl EntityType { conditions: None, functions: Some(&[ LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, LootFunction { @@ -3735,7 +3926,14 @@ impl EntityType { quality: 0i32, conditions: None, functions: Some(&[LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }]), }, @@ -3930,7 +4128,14 @@ impl EntityType { ])]), }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, ]), @@ -3960,7 +4165,14 @@ impl EntityType { conditions: None, }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, ]), @@ -4067,7 +4279,14 @@ impl EntityType { conditions: None, }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, ]), @@ -4153,7 +4372,14 @@ impl EntityType { conditions: None, }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, ]), @@ -4186,7 +4412,14 @@ impl EntityType { conditions: None, }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, ]), @@ -4681,7 +4914,14 @@ impl EntityType { conditions: None, }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, ]), @@ -4797,7 +5037,14 @@ impl EntityType { conditions: None, }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, ]), @@ -5078,7 +5325,14 @@ impl EntityType { conditions: None, }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, ]), @@ -5121,7 +5375,14 @@ impl EntityType { ])]), }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, ]), @@ -5206,7 +5467,14 @@ impl EntityType { conditions: None, }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, ]), @@ -5631,7 +5899,14 @@ impl EntityType { conditions: None, }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, ]), @@ -5661,7 +5936,14 @@ impl EntityType { conditions: None, }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, ]), @@ -5691,11 +5973,20 @@ impl EntityType { conditions: None, }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: Some(1f32), + }, conditions: None, }, LootFunction { - content: LootFunctionTypes::SetPotion, + content: LootFunctionTypes::SetPotion { + id: "minecraft:weakness", + }, conditions: None, }, ]), @@ -5782,7 +6073,14 @@ impl EntityType { conditions: None, }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, ]), @@ -5866,7 +6164,14 @@ impl EntityType { conditions: None, }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, ]), @@ -5963,7 +6268,14 @@ impl EntityType { ])]), }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, ]), @@ -6282,7 +6594,14 @@ impl EntityType { conditions: None, }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, ]), @@ -6319,7 +6638,14 @@ impl EntityType { conditions: None, }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, ]), @@ -6497,7 +6823,14 @@ impl EntityType { conditions: None, }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, ]), @@ -6537,7 +6870,14 @@ impl EntityType { ])]), }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, ]), @@ -6829,7 +7169,14 @@ impl EntityType { ])]), }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, ]), @@ -7271,7 +7618,14 @@ impl EntityType { conditions: None, }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, ]), @@ -7301,7 +7655,14 @@ impl EntityType { conditions: None, }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, ]), @@ -7386,7 +7747,14 @@ impl EntityType { conditions: None, }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, ]), @@ -7476,7 +7844,14 @@ impl EntityType { conditions: None, }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, ]), @@ -7803,7 +8178,14 @@ impl EntityType { conditions: None, }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, ]), @@ -7833,7 +8215,14 @@ impl EntityType { conditions: None, }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, ]), @@ -7983,7 +8372,14 @@ impl EntityType { conditions: None, }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, ]), @@ -8068,7 +8464,14 @@ impl EntityType { conditions: None, }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, ]), @@ -8098,7 +8501,14 @@ impl EntityType { conditions: None, }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, ]), @@ -8128,11 +8538,20 @@ impl EntityType { conditions: None, }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: Some(1f32), + }, conditions: None, }, LootFunction { - content: LootFunctionTypes::SetPotion, + content: LootFunctionTypes::SetPotion { + id: "minecraft:slowness", + }, conditions: None, }, ]), @@ -8217,7 +8636,14 @@ impl EntityType { conditions: None, }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, ]), @@ -8477,7 +8903,14 @@ impl EntityType { conditions: None, }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, ]), @@ -8675,7 +9108,14 @@ impl EntityType { conditions: None, }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, ]), @@ -8887,7 +9327,14 @@ impl EntityType { conditions: None, }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, ]), @@ -9118,7 +9565,14 @@ impl EntityType { conditions: None, }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, ]), @@ -9142,7 +9596,14 @@ impl EntityType { conditions: None, }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, ]), @@ -9166,7 +9627,14 @@ impl EntityType { conditions: None, }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, ]), @@ -9190,7 +9658,14 @@ impl EntityType { conditions: None, }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, ]), @@ -9214,7 +9689,14 @@ impl EntityType { conditions: None, }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, ]), @@ -9238,7 +9720,14 @@ impl EntityType { conditions: None, }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, ]), @@ -9274,7 +9763,14 @@ impl EntityType { conditions: None, }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, ]), @@ -9416,7 +9912,14 @@ impl EntityType { conditions: None, }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, ]), @@ -9446,7 +9949,14 @@ impl EntityType { conditions: None, }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, ]), @@ -9630,7 +10140,14 @@ impl EntityType { conditions: None, }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, ]), @@ -9716,7 +10233,14 @@ impl EntityType { conditions: None, }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, ]), @@ -9749,7 +10273,14 @@ impl EntityType { conditions: None, }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, ]), @@ -9908,7 +10439,14 @@ impl EntityType { conditions: None, }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, ]), @@ -9993,7 +10531,14 @@ impl EntityType { conditions: None, }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, ]), @@ -10079,7 +10624,14 @@ impl EntityType { conditions: None, }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, ]), @@ -10219,7 +10771,14 @@ impl EntityType { conditions: None, }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, ]), @@ -10249,7 +10808,14 @@ impl EntityType { conditions: None, }, LootFunction { - content: LootFunctionTypes::EnchantedCountIncrease, + content: LootFunctionTypes::EnchantedCountIncrease { + enchantment: "minecraft:looting", + count: LootFunctionNumberProvider::Uniform { + min: 0f32, + max: 1f32, + }, + limit: None, + }, conditions: None, }, ]), diff --git a/pumpkin-util/src/loot_table.rs b/pumpkin-util/src/loot_table.rs index fed02aeb4..1ade23131 100644 --- a/pumpkin-util/src/loot_table.rs +++ b/pumpkin-util/src/loot_table.rs @@ -67,12 +67,17 @@ pub struct LootTableEntry { pub value: &'static str, } +#[derive(Clone, Debug)] +pub struct DynamicEntry { + pub name: &'static str, +} + #[derive(Clone, Debug)] pub enum LootPoolEntryTypes { Empty, Item(ItemEntry), LootTable(LootTableEntry), - Dynamic, + Dynamic(DynamicEntry), Tag(TagEntry), Alternatives(AlternativeEntry), Sequence(SequenceEntry), @@ -173,11 +178,15 @@ pub enum LootFunctionTypes { add: bool, }, /// Increases the count of items based on the item's enchantments. - EnchantedCountIncrease, + EnchantedCountIncrease { + enchantment: &'static str, + count: LootFunctionNumberProvider, + limit: Option, + }, /// Smelts the item as if it passed through a furnace. FurnaceSmelt, /// Sets the potion type for potion items. - SetPotion, + SetPotion { id: &'static str }, /// Sets the amplifier for ominous bottles. SetOminousBottleAmplifier, /// Limits the count of items to a minimum and/or maximum value. diff --git a/pumpkin/src/entity/living.rs b/pumpkin/src/entity/living.rs index c05173abf..f8df7efbd 100644 --- a/pumpkin/src/entity/living.rs +++ b/pumpkin/src/entity/living.rs @@ -1317,6 +1317,27 @@ impl LivingEntity { // Plays the death sound world.send_entity_status(&self.entity, EntityStatus::Death); + let tool = if let Some(cause_ent) = cause { + if let Some(player) = cause_ent + .cast_any() + .downcast_ref::() + { + let hand_stack = player + .inventory + .get_stack_in_hand(pumpkin_util::Hand::Right) + .await; + let stack_guard = hand_stack.lock().await; + (stack_guard.item_count > 0).then(|| stack_guard.clone()) + } else { + None + } + } else { + None + }; + + let is_raining = world.is_raining().await; + let is_thundering = world.is_thundering().await; + let params = LootContextParameters { killed_by_player: cause.map(|c| c.get_entity().entity_type == &EntityType::PLAYER), this_entity: Some(self.entity.entity_type), @@ -1325,11 +1346,14 @@ impl LivingEntity { position: Some(self.entity.pos.load()), world_time: world.level_info.load().day_time as u64, damage_type: Some(damage_type), + tool, + is_raining: Some(is_raining), + is_thundering: Some(is_thundering), ..Default::default() }; // Drop loot - self.drop_loot(params).await; + self.drop_loot(params.clone()).await; // Award experience if params.killed_by_player.unwrap_or(false) diff --git a/pumpkin/src/entity/vehicle/vehicle.rs b/pumpkin/src/entity/vehicle/vehicle.rs index d8d872eb3..c26824a8a 100644 --- a/pumpkin/src/entity/vehicle/vehicle.rs +++ b/pumpkin/src/entity/vehicle/vehicle.rs @@ -89,7 +89,14 @@ impl VehicleEntity { if entity_drops && let Some(loot_table) = &self.entity.entity_type.loot_table { let pos = self.entity.block_pos.load(); - let params = LootContextParameters::default(); + let is_raining = world.is_raining().await; + let is_thundering = world.is_thundering().await; + let params = LootContextParameters { + is_raining: Some(is_raining), + is_thundering: Some(is_thundering), + world_time: world.level_info.load().day_time as u64, + ..Default::default() + }; for stack in loot_table.get_loot(params) { world.drop_stack(&pos, stack).await; } diff --git a/pumpkin/src/world/explosion.rs b/pumpkin/src/world/explosion.rs index bf31efb4e..28ef8fa9a 100644 --- a/pumpkin/src/world/explosion.rs +++ b/pumpkin/src/world/explosion.rs @@ -272,6 +272,8 @@ impl Explosion { let pumpkin_block = world.block_registry.get_pumpkin_block(block.id); if pumpkin_block.is_none_or(|s| s.should_drop_items_on_explosion()) { + let is_raining = world.is_raining().await; + let is_thundering = world.is_thundering().await; let params = LootContextParameters { block_state: Some(state), explosion_radius: Some(self.power), @@ -281,6 +283,8 @@ impl Explosion { pos.0.z as f64, )), world_time: world.level_info.load().day_time as u64, + is_raining: Some(is_raining), + is_thundering: Some(is_thundering), ..Default::default() }; drop_loot(world, block, pos, false, params).await; diff --git a/pumpkin/src/world/loot.rs b/pumpkin/src/world/loot.rs index 5ec7657df..01fab9862 100644 --- a/pumpkin/src/world/loot.rs +++ b/pumpkin/src/world/loot.rs @@ -12,7 +12,7 @@ use pumpkin_util::{ }; use rand::RngExt; -#[derive(Default, Copy, Clone)] +#[derive(Default, Clone)] pub struct LootContextParameters { pub explosion_radius: Option, pub block_state: Option<&'static BlockState>, @@ -24,6 +24,9 @@ pub struct LootContextParameters { pub position: Option>, pub world_time: u64, pub damage_type: Option, + pub tool: Option, + pub is_raining: Option, + pub is_thundering: Option, } pub trait LootTableExt { @@ -100,12 +103,15 @@ trait LootFunctionExt { fn apply_bonus( stacks: &mut [ItemStack], + enchantment_name: &str, formula: &str, parameters: Option<&LootFunctionBonusParameter>, + params: &LootContextParameters, ) { - // We currently don't have tool/enchantment data in LootContextParameters. - // Assuming enchantment level is 0 for now. - let enchantment_level = 0; + let enchantment_level = params.tool.as_ref().map_or(0, |tool| { + pumpkin_data::Enchantment::from_name(enchantment_name) + .map_or(0, |enchantment| tool.get_enchantment_level(enchantment)) + }); if enchantment_level > 0 { for stack in stacks { match formula { @@ -145,6 +151,7 @@ fn apply_bonus( } impl LootFunctionExt for LootFunction { + #[allow(clippy::too_many_lines)] fn apply(&self, stacks: &mut Vec, params: &LootContextParameters) { if let Some(conditions) = self.conditions && !conditions.iter().all(|cond| cond.is_fulfilled(params)) @@ -196,25 +203,128 @@ impl LootFunctionExt for LootFunction { } } LootFunctionTypes::ApplyBonus { - enchantment: _, + enchantment, formula, parameters, } => { - apply_bonus(stacks, formula, parameters.as_ref()); + apply_bonus(stacks, enchantment, formula, parameters.as_ref(), params); } - LootFunctionTypes::CopyComponents { - source: _, - include: _, + LootFunctionTypes::EnchantedCountIncrease { + enchantment, + count, + limit, + } => { + let level = params.tool.as_ref().map_or(0.0, |tool| { + pumpkin_data::Enchantment::from_name(enchantment) + .map_or(0.0, |enc| tool.get_enchantment_level(enc) as f32) + }); + let mut additional = (count.generate() * level).round() as u32; + if let Some(lim) = limit { + let lim_u32 = lim.round() as u32; + if additional > lim_u32 { + additional = lim_u32; + } + } + for stack in stacks { + stack.item_count = stack.item_count.saturating_add(additional as u8); + } } - | LootFunctionTypes::CopyState { + LootFunctionTypes::CopyComponents { source, include } => { + tracing::warn!( + "CopyComponents not supported from source: {} for {:?}", + source, + include + ); + } + LootFunctionTypes::CopyState { block: _, - properties: _, + properties, + } => { + if let Some(state) = params.block_state + && let Some(props_data) = + Block::properties(Block::from_state_id(state.id), state.id) + { + let actual_props = props_data.to_props(); + let mut properties_to_copy = std::collections::HashMap::new(); + for &prop_name in *properties { + if let Some((_, value)) = actual_props.iter().find(|(k, _)| k == &prop_name) + { + properties_to_copy.insert(prop_name.to_string(), value.to_string()); + } + } + if !properties_to_copy.is_empty() { + for stack in stacks.iter_mut() { + if let Some(block_state_comp) = stack.get_data_component_mut::() { + for (k, v) in &properties_to_copy { + block_state_comp.properties.insert(k.clone(), v.clone()); + } + } else { + stack.patch.push(( + pumpkin_data::data_component::DataComponent::BlockState, + Some(Box::new(pumpkin_data::data_component_impl::BlockStateImpl { + properties: properties_to_copy.clone(), + })), + )); + } + } + } + } } - | LootFunctionTypes::EnchantedCountIncrease - | LootFunctionTypes::SetOminousBottleAmplifier - | LootFunctionTypes::SetPotion - | LootFunctionTypes::FurnaceSmelt => { - // TODO: shouldnt crash here but needs to be implemented someday + LootFunctionTypes::SetOminousBottleAmplifier => { + let amplifier = rand::random_range(0..5); // Random 0 to 4 + for stack in stacks.iter_mut() { + if let Some(amplifier_comp) = stack.get_data_component_mut::() { + amplifier_comp.amplifier = amplifier; + } else { + stack.patch.push(( + pumpkin_data::data_component::DataComponent::OminousBottleAmplifier, + Some(Box::new(pumpkin_data::data_component_impl::OminousBottleAmplifierImpl { + amplifier, + })), + )); + } + } + } + LootFunctionTypes::SetPotion { id } => { + let name = id.strip_prefix("minecraft:").unwrap_or(id); + if let Some(potion) = pumpkin_data::potion::Potion::from_name(name) { + let potion_id = Some(potion.id as i32); + for stack in stacks.iter_mut() { + if let Some(potion_contents) = stack.get_data_component_mut::() { + potion_contents.potion_id = potion_id; + } else { + stack.patch.push(( + pumpkin_data::data_component::DataComponent::PotionContents, + Some(Box::new(pumpkin_data::data_component_impl::PotionContentsImpl { + potion_id, + custom_color: None, + custom_effects: Vec::new(), + custom_name: None, + })), + )); + } + } + } + } + LootFunctionTypes::FurnaceSmelt => { + for stack in stacks.iter_mut() { + for recipe_type in pumpkin_data::recipes::RECIPES_COOKING { + if let pumpkin_data::recipes::CookingRecipeType::Smelting(recipe) = + recipe_type + && recipe.ingredient.match_item(stack.item) + { + let result_key = recipe + .result + .id + .strip_prefix("minecraft:") + .unwrap_or(recipe.result.id); + if let Some(smelted_item) = Item::from_registry_key(result_key) { + stack.item = smelted_item; + } + break; + } + } + } } } } @@ -247,7 +357,7 @@ trait LootPoolEntryTypesExt { impl LootPoolEntryTypesExt for LootPoolEntryTypes { fn get_stacks(&self, params: &LootContextParameters) -> Vec { match self { - Self::Empty | Self::Dynamic => Vec::new(), + Self::Empty | Self::Dynamic(_) => Vec::new(), Self::LootTable(entry) => { let key = entry .value @@ -395,7 +505,7 @@ fn check_damage_source_properties( } impl LootConditionExt for LootCondition { - // TODO: This is trash. Make this right + #[allow(clippy::too_many_lines)] fn is_fulfilled(&self, params: &LootContextParameters) -> bool { match self { Self::SurvivesExplosion => { @@ -437,32 +547,27 @@ impl LootConditionExt for LootCondition { Self::AnyOf(terms) => terms.iter().any(|cond| cond.is_fulfilled(params)), Self::AllOf(terms) => terms.iter().all(|cond| cond.is_fulfilled(params)), Self::RandomChanceWithEnchantedBonus { - enchantment: _, + enchantment, chances, } => chances.as_ref().is_some_and(|chances| { - // Missing tool context in params, assume enchantment level 0 - let level = 0; + let level = params.tool.as_ref().map_or(0, |tool| { + pumpkin_data::Enchantment::from_name(enchantment) + .map_or(0, |enc| tool.get_enchantment_level(enc) as usize) + }); let chance = chances.get(level).unwrap_or(chances.last().unwrap_or(&0.0)); rand::rng().random::() < *chance }), Self::TableBonus { - enchantment: _, + enchantment, chances, } => { - // Missing tool context in params, assume enchantment level 0 - let level = 0; + let level = params.tool.as_ref().map_or(0, |tool| { + pumpkin_data::Enchantment::from_name(enchantment) + .map_or(0, |enc| tool.get_enchantment_level(enc) as usize) + }); let chance = chances.get(level).unwrap_or(chances.last().unwrap_or(&0.0)); rand::rng().random::() < *chance } - Self::EntityScores { .. } - | Self::WeatherCheck { .. } - | Self::MatchTool { .. } - | Self::Reference { .. } - | Self::EnchantmentActiveCheck { .. } - | Self::LocationCheck { .. } => { - // TODO: Implement these - false - } Self::TimeCheck { range, period } => { let mut time = params.world_time; if let Some(period) = period { @@ -484,6 +589,51 @@ impl LootConditionExt for LootCondition { } => { check_damage_source_properties(params, *expected_source_type, *expected_direct_type) } + Self::WeatherCheck { + raining, + thundering, + } => { + let r_match = raining.is_none_or(|r| params.is_raining.unwrap_or(false) == r); + let t_match = thundering.is_none_or(|t| params.is_thundering.unwrap_or(false) == t); + r_match && t_match + } + Self::MatchTool { items } => params.tool.as_ref().is_some_and(|tool| { + items.as_ref().map_or_else( + || { + pumpkin_data::Enchantment::from_name("minecraft:silk_touch") + .is_some_and(|silk_touch| tool.get_enchantment_level(silk_touch) > 0) + }, + |items| { + items.iter().any(|&item_name| { + let expected = + item_name.strip_prefix("minecraft:").unwrap_or(item_name); + let actual = tool + .item + .registry_key + .strip_prefix("minecraft:") + .unwrap_or(tool.item.registry_key); + expected == actual + }) + }, + ) + }), + Self::LocationCheck { expected_biome, .. } => expected_biome.is_none(), + Self::EntityScores { entity } => { + tracing::warn!("EntityScores check not supported for entity: {}", entity); + false + } + Self::Reference { name } => { + tracing::warn!("Loot condition reference not supported: {}", name); + false + } + Self::EnchantmentActiveCheck { active } => { + params.tool.as_ref().map_or(!*active, |tool| { + let has_enchantments = tool + .get_data_component::() + .is_some_and(|e| !e.enchantment.is_empty()); + has_enchantments == *active + }) + } } } } diff --git a/pumpkin/src/world/mod.rs b/pumpkin/src/world/mod.rs index e91f13ddd..9dad91a40 100644 --- a/pumpkin/src/world/mod.rs +++ b/pumpkin/src/world/mod.rs @@ -4226,6 +4226,7 @@ impl World { } // Return new state + #[allow(clippy::too_many_lines)] pub async fn break_block( self: &Arc, position: &BlockPos, @@ -4295,7 +4296,7 @@ impl World { false, ); let chunk_pos = position.chunk_position(); - match cause { + match &cause { Some(player) => { self.broadcast_to_chunk_except( chunk_pos, @@ -4307,6 +4308,20 @@ impl World { } } if !flags.contains(BlockFlags::SKIP_DROPS) { + let tool = if let Some(player) = &cause { + let hand_stack = player + .inventory + .get_stack_in_hand(pumpkin_util::Hand::Right) + .await; + let stack_guard = hand_stack.lock().await; + (stack_guard.item_count > 0).then(|| stack_guard.clone()) + } else { + None + }; + + let is_raining = self.is_raining().await; + let is_thundering = self.is_thundering().await; + let params = LootContextParameters { block_state: Some(BlockState::from_id(broken_state_id)), luck, @@ -4316,6 +4331,9 @@ impl World { position.0.z as f64, )), world_time: self.level_info.load().day_time as u64, + tool, + is_raining: Some(is_raining), + is_thundering: Some(is_thundering), ..Default::default() }; block::drop_loot(self, broken_block, position, true, params).await;