1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
use azalea_block::{BlockBehavior, BlockTrait};
use azalea_inventory::{ItemStack, components::Tool};
use azalea_registry::builtin::{BlockKind, MobEffect};
use crate::{ActiveEffects, Attributes, FluidOnEyes, Physics};
/// How much progress is made towards mining the block per tick, as a
/// percentage.
///
/// If this is 1, then the block gets broken instantly.
///
/// You can divide 1 by this and then round up to get the number of ticks it
/// takes to mine the block.
///
/// The player inventory is needed to check your armor and offhand for modifiers
/// to your mining speed.
pub fn get_mine_progress(
block: &dyn BlockTrait,
held_item: &ItemStack,
fluid_on_eyes: &FluidOnEyes,
physics: &Physics,
attributes: &Attributes,
active_effects: &ActiveEffects,
) -> f32 {
let block_behavior: BlockBehavior = block.behavior();
let destroy_time = block_behavior.destroy_time;
if destroy_time == -1. {
return 0.;
}
let divisor = if has_correct_tool_for_drops(block, held_item) {
30
} else {
100
};
let base_destroy_speed = destroy_speed(
block.as_block_kind(),
held_item,
fluid_on_eyes,
physics,
attributes,
active_effects,
);
(base_destroy_speed / destroy_time) / (divisor as f32)
}
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_block_kind();
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
/// enchantments and effects into account.
///
/// If the player is not holding anything, then `tool` should be
/// `ItemKind::Air`.
fn destroy_speed(
block: BlockKind,
tool: &ItemStack,
_fluid_on_eyes: &FluidOnEyes,
physics: &Physics,
attributes: &Attributes,
active_effects: &ActiveEffects,
) -> f32 {
let mut speed = base_destroy_speed(block, tool);
if speed > 1. {
// efficiency enchantment
speed += attributes.mining_efficiency.calculate() as f32;
}
if let Some(dig_speed_amplifier) = active_effects.get_dig_speed_amplifier() {
speed *= 1. + (dig_speed_amplifier + 1) as f32 * 0.2;
}
if let Some(dig_slowdown) = active_effects.get_level(MobEffect::MiningFatigue) {
let multiplier = match dig_slowdown {
0 => 0.3,
1 => 0.09,
2 => 0.0027,
_ => 8.1E-4,
};
speed *= multiplier;
}
speed *= attributes.block_break_speed.calculate() as f32;
// TODO
// if **fluid_on_eyes == FluidKind::Water
// && enchantments::get_enchant_level(registry::Enchantment::AquaAffinity,
// player_inventory) == 0
// {
// base_destroy_speed /= 5.;
// }
if !physics.on_ground {
speed /= 5.;
}
speed
}
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;
}
}
tool.default_mining_speed
}
|