aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormat <git@matdoes.dev>2026-02-07 21:25:42 +0300
committermat <git@matdoes.dev>2026-02-07 05:48:18 -1245
commit8d718a627349bdf1e531fba318abc634a3bec9da (patch)
tree9b02cebd67e47dbccd986b2ec3d91781468464b4
parent4bf82475c6a425bcf6f7d5880009fb9e47be998b (diff)
downloadazalea-drasl-8d718a627349bdf1e531fba318abc634a3bec9da.tar.xz
replace hard-coded block break speed checks
-rw-r--r--azalea-client/src/plugins/mining.rs4
-rw-r--r--azalea-entity/src/attributes.rs2
-rw-r--r--azalea-entity/src/lib.rs1
-rw-r--r--azalea-entity/src/mining.rs114
-rw-r--r--azalea-registry/azalea-registry-macros/src/lib.rs28
-rw-r--r--azalea-registry/src/lib.rs8
-rw-r--r--azalea/src/auto_tool.rs16
7 files changed, 76 insertions, 97 deletions
diff --git a/azalea-client/src/plugins/mining.rs b/azalea-client/src/plugins/mining.rs
index 5e724071..480ba46b 100644
--- a/azalea-client/src/plugins/mining.rs
+++ b/azalea-client/src/plugins/mining.rs
@@ -342,7 +342,7 @@ pub fn handle_mining_queued(
if block_is_solid
&& get_mine_progress(
block.as_ref(),
- held_item.kind(),
+ held_item,
fluid_on_eyes,
physics,
attributes,
@@ -657,7 +657,7 @@ pub fn continue_mining_block(
let block = Box::<dyn BlockTrait>::from(target_block_state);
**mine_progress += get_mine_progress(
block.as_ref(),
- current_mining_item.kind(),
+ current_mining_item,
fluid_on_eyes,
physics,
attributes,
diff --git a/azalea-entity/src/attributes.rs b/azalea-entity/src/attributes.rs
index 69e98a7b..26f0618e 100644
--- a/azalea-entity/src/attributes.rs
+++ b/azalea-entity/src/attributes.rs
@@ -21,6 +21,7 @@ pub struct Attributes {
pub attack_speed: AttributeInstance,
pub water_movement_efficiency: AttributeInstance,
pub mining_efficiency: AttributeInstance,
+ pub block_break_speed: AttributeInstance,
pub block_interaction_range: AttributeInstance,
pub entity_interaction_range: AttributeInstance,
@@ -41,6 +42,7 @@ impl Attributes {
Attribute::BlockInteractionRange => &mut self.block_interaction_range,
Attribute::EntityInteractionRange => &mut self.entity_interaction_range,
Attribute::StepHeight => &mut self.step_height,
+ Attribute::BlockBreakSpeed => &mut self.block_break_speed,
_ => return None,
};
Some(value)
diff --git a/azalea-entity/src/lib.rs b/azalea-entity/src/lib.rs
index fab973b1..fa4feffb 100644
--- a/azalea-entity/src/lib.rs
+++ b/azalea-entity/src/lib.rs
@@ -398,6 +398,7 @@ impl Attributes {
block_interaction_range: AttributeInstance::new(4.5),
entity_interaction_range: AttributeInstance::new(3.0),
step_height: AttributeInstance::new(0.6),
+ block_break_speed: AttributeInstance::new(1.0),
}
}
}
diff --git a/azalea-entity/src/mining.rs b/azalea-entity/src/mining.rs
index bda75bd9..bc2e6c46 100644
--- a/azalea-entity/src/mining.rs
+++ b/azalea-entity/src/mining.rs
@@ -1,9 +1,6 @@
use azalea_block::{BlockBehavior, BlockTrait};
-use azalea_core::tier::get_item_tier;
-use azalea_registry::{
- builtin::{BlockKind, ItemKind, MobEffect},
- tags,
-};
+use azalea_inventory::{ItemStack, components::Tool};
+use azalea_registry::builtin::{BlockKind, MobEffect};
use crate::{ActiveEffects, Attributes, FluidOnEyes, Physics};
@@ -19,7 +16,7 @@ use crate::{ActiveEffects, Attributes, FluidOnEyes, Physics};
/// to your mining speed.
pub fn get_mine_progress(
block: &dyn BlockTrait,
- held_item: ItemKind,
+ held_item: &ItemStack,
fluid_on_eyes: &FluidOnEyes,
physics: &Physics,
attributes: &Attributes,
@@ -45,34 +42,26 @@ pub fn get_mine_progress(
attributes,
active_effects,
);
- (base_destroy_speed / destroy_time) / divisor as f32
+ (base_destroy_speed / destroy_time) / (divisor as f32)
}
-fn has_correct_tool_for_drops(block: &dyn BlockTrait, tool: ItemKind) -> bool {
+fn has_correct_tool_for_drops(block: &dyn BlockTrait, item: &ItemStack) -> bool {
if !block.behavior().requires_correct_tool_for_drops {
return true;
}
+ let Some(tool) = item.get_component::<Tool>() else {
+ return false;
+ };
let registry_block = block.as_registry_block();
- if tool == ItemKind::Shears {
- matches!(
- registry_block,
- BlockKind::Cobweb | BlockKind::RedstoneWire | BlockKind::Tripwire
- )
- } else if tags::items::SWORDS.contains(&tool) {
- registry_block == BlockKind::Cobweb
- } else if tags::items::PICKAXES.contains(&tool)
- || tags::items::SHOVELS.contains(&tool)
- || tags::items::HOES.contains(&tool)
- || tags::items::AXES.contains(&tool)
- {
- let tier = get_item_tier(tool).expect("all pickaxes and shovels should be matched");
- let tier_level = tier.level();
- !((tier_level < 3 && tags::blocks::NEEDS_DIAMOND_TOOL.contains(&registry_block))
- || (tier_level < 2 && tags::blocks::NEEDS_IRON_TOOL.contains(&registry_block))
- || (tier_level < 1 && tags::blocks::NEEDS_STONE_TOOL.contains(&registry_block)))
- } else {
- false
+ for rule in &tool.rules {
+ if let Some(correct) = rule.correct_for_drops
+ && rule.blocks.contains(registry_block)
+ {
+ return correct;
+ }
}
+
+ false
}
/// Returns the destroy speed of the given block with the given tool, taking
@@ -82,21 +71,21 @@ fn has_correct_tool_for_drops(block: &dyn BlockTrait, tool: ItemKind) -> bool {
/// `ItemKind::Air`.
fn destroy_speed(
block: BlockKind,
- tool: ItemKind,
+ tool: &ItemStack,
_fluid_on_eyes: &FluidOnEyes,
physics: &Physics,
attributes: &Attributes,
active_effects: &ActiveEffects,
) -> f32 {
- let mut base_destroy_speed = base_destroy_speed(block, tool);
+ let mut speed = base_destroy_speed(block, tool);
- if base_destroy_speed > 1. {
+ if speed > 1. {
// efficiency enchantment
- base_destroy_speed += attributes.mining_efficiency.calculate() as f32;
+ speed += attributes.mining_efficiency.calculate() as f32;
}
if let Some(dig_speed_amplifier) = active_effects.get_dig_speed_amplifier() {
- base_destroy_speed *= 1. + (dig_speed_amplifier + 1) as f32 * 0.2;
+ speed *= 1. + (dig_speed_amplifier + 1) as f32 * 0.2;
}
if let Some(dig_slowdown) = active_effects.get_level(MobEffect::MiningFatigue) {
@@ -106,9 +95,11 @@ fn destroy_speed(
2 => 0.0027,
_ => 8.1E-4,
};
- base_destroy_speed *= multiplier;
+ speed *= multiplier;
}
+ speed *= attributes.block_break_speed.calculate() as f32;
+
// TODO
// if **fluid_on_eyes == FluidKind::Water
// && enchantments::get_enchant_level(registry::Enchantment::AquaAffinity,
@@ -118,56 +109,21 @@ fn destroy_speed(
// }
if !physics.on_ground {
- base_destroy_speed /= 5.;
+ speed /= 5.;
}
- base_destroy_speed
+ speed
}
-fn base_destroy_speed(block: BlockKind, tool: ItemKind) -> f32 {
- if tool == ItemKind::Shears {
- if block == BlockKind::Cobweb || tags::blocks::LEAVES.contains(&block) {
- 15.
- } else if tags::blocks::WOOL.contains(&block) {
- 5.
- } else if matches!(block, BlockKind::Vine | BlockKind::GlowLichen) {
- 2.
- } else {
- 1.
- }
- } else if tags::items::SWORDS.contains(&tool) {
- if block == BlockKind::Cobweb {
- 15.
- } else if tags::blocks::SWORD_EFFICIENT.contains(&block) {
- 1.5
- } else {
- 1.
+fn base_destroy_speed(block: BlockKind, item: &ItemStack) -> f32 {
+ let tool = item.get_component::<Tool>();
+ let Some(tool) = tool else { return 1. };
+ for rule in &tool.rules {
+ if let Some(speed) = rule.speed
+ && rule.blocks.contains(block)
+ {
+ return speed;
}
- } else if tags::items::PICKAXES.contains(&tool) {
- if tags::blocks::MINEABLE_PICKAXE.contains(&block) {
- get_item_tier(tool).unwrap().speed()
- } else {
- 1.
- }
- } else if tags::items::SHOVELS.contains(&tool) {
- if tags::blocks::MINEABLE_SHOVEL.contains(&block) {
- get_item_tier(tool).unwrap().speed()
- } else {
- 1.
- }
- } else if tags::items::HOES.contains(&tool) {
- if tags::blocks::MINEABLE_HOE.contains(&block) {
- get_item_tier(tool).unwrap().speed()
- } else {
- 1.
- }
- } else if tags::items::AXES.contains(&tool) {
- if tags::blocks::MINEABLE_AXE.contains(&block) {
- get_item_tier(tool).unwrap().speed()
- } else {
- 1.
- }
- } else {
- 1.
}
+ tool.default_mining_speed
}
diff --git a/azalea-registry/azalea-registry-macros/src/lib.rs b/azalea-registry/azalea-registry-macros/src/lib.rs
index 6c7d4840..a8c6fe18 100644
--- a/azalea-registry/azalea-registry-macros/src/lib.rs
+++ b/azalea-registry/azalea-registry-macros/src/lib.rs
@@ -140,28 +140,35 @@ pub fn registry(input: TokenStream) -> TokenStream {
});
// Display that uses registry ids
- let mut display_items = quote! {};
+ let mut to_str_items = quote! {};
let mut from_str_items = quote! {};
for item in &input.items {
let name = &item.name;
let id = &item.id;
- display_items.extend(quote! {
- Self::#name => write!(f, concat!("minecraft:", #id)),
+ to_str_items.extend(quote! {
+ Self::#name => concat!("minecraft:", #id),
});
from_str_items.extend(quote! {
#id => Ok(Self::#name),
});
}
generated.extend(quote! {
- /// Convert the value to a stringified identifier, formatted like
- /// `"minecraft:air"`.
- impl std::fmt::Display for #name {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ impl #name {
+ /// Convert the value to a stringified identifier, formatted like
+ /// `"minecraft:air"`.
+ pub fn to_str(&self) -> &'static str {
match self {
- #display_items
+ #to_str_items
}
}
}
+ impl std::fmt::Display for #name {
+ /// Convert the value to a stringified identifier, formatted like
+ /// `"minecraft:air"`.
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ write!(f, "{}", self.to_str())
+ }
+ }
impl<'a> TryFrom<&'a crate::Identifier> for #name {
type Error = ();
fn try_from(ident: &'a crate::Identifier) -> Result<Self, Self::Error> {
@@ -172,6 +179,11 @@ pub fn registry(input: TokenStream) -> TokenStream {
}
}
}
+ impl<'a> From<#name> for crate::Identifier {
+ fn from(value: #name) -> Self {
+ Self::new(value.to_str())
+ }
+ }
/// Parse the value from a stringified identifier, formatted like
/// either `"air"` or `"minecraft:air"`.
impl std::str::FromStr for #name {
diff --git a/azalea-registry/src/lib.rs b/azalea-registry/src/lib.rs
index fe6b85b3..e60a0968 100644
--- a/azalea-registry/src/lib.rs
+++ b/azalea-registry/src/lib.rs
@@ -204,6 +204,14 @@ impl<D: Registry, Identifier: AzBuf> Default for HolderSet<D, Identifier> {
}
}
}
+impl<D: Registry, Identifier: AzBuf + From<D> + PartialEq> HolderSet<D, Identifier> {
+ pub fn contains(&self, value: D) -> bool {
+ match self {
+ HolderSet::Direct { contents } => contents.contains(&value),
+ HolderSet::Named { key: _, contents } => contents.contains(&Identifier::from(value)),
+ }
+ }
+}
/// A reference to either a registry or a custom value (usually something with
/// an `Identifier`).
diff --git a/azalea/src/auto_tool.rs b/azalea/src/auto_tool.rs
index 519c5dc9..5fe0f529 100644
--- a/azalea/src/auto_tool.rs
+++ b/azalea/src/auto_tool.rs
@@ -2,7 +2,7 @@ use azalea_block::{BlockState, BlockTrait, fluid_state::FluidKind};
use azalea_core::position::BlockPos;
use azalea_entity::{ActiveEffects, Attributes, FluidOnEyes, Physics, inventory::Inventory};
use azalea_inventory::{ItemStack, Menu, components};
-use azalea_registry::builtin::{BlockKind, EntityKind, ItemKind};
+use azalea_registry::builtin::{BlockKind, EntityKind};
use crate::Client;
@@ -92,13 +92,13 @@ pub fn accurate_best_tool_in_hotbar_for_block(
}
// find the first slot that has an item without durability
- for (i, item_slot) in hotbar_slots.iter().enumerate() {
+ for (i, item_stack_data) in hotbar_slots.iter().enumerate() {
let this_item_speed;
- match item_slot {
+ match item_stack_data {
ItemStack::Empty => {
this_item_speed = Some(azalea_entity::mining::get_mine_progress(
block.as_ref(),
- ItemKind::Air,
+ &ItemStack::Empty,
fluid_on_eyes,
physics,
attributes,
@@ -111,7 +111,7 @@ pub fn accurate_best_tool_in_hotbar_for_block(
if !item_stack.component_patch.has::<components::Damage>() {
this_item_speed = Some(azalea_entity::mining::get_mine_progress(
block.as_ref(),
- item_stack.kind,
+ item_stack_data,
fluid_on_eyes,
physics,
attributes,
@@ -131,11 +131,11 @@ pub fn accurate_best_tool_in_hotbar_for_block(
}
// now check every item
- for (i, item_slot) in hotbar_slots.iter().enumerate() {
- if let ItemStack::Present(item_slot) = item_slot {
+ for (i, item_stack) in hotbar_slots.iter().enumerate() {
+ if item_stack.is_present() {
let this_item_speed = azalea_entity::mining::get_mine_progress(
block.as_ref(),
- item_slot.kind,
+ item_stack,
fluid_on_eyes,
physics,
attributes,