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
|
use azalea_block::{BlockState, BlockTrait, fluid_state::FluidKind};
use azalea_client::{Client, inventory::Inventory};
use azalea_entity::{FluidOnEyes, Physics};
use azalea_inventory::{ItemStack, Menu, components};
#[derive(Debug)]
pub struct BestToolResult {
pub index: usize,
pub percentage_per_tick: f32,
}
pub trait AutoToolClientExt {
fn best_tool_in_hotbar_for_block(&self, block: BlockState) -> BestToolResult;
}
impl AutoToolClientExt for Client {
fn best_tool_in_hotbar_for_block(&self, block: BlockState) -> BestToolResult {
let mut ecs = self.ecs.lock();
let (inventory, physics, fluid_on_eyes) =
self.query::<(&Inventory, &Physics, &FluidOnEyes)>(&mut ecs);
let menu = &inventory.inventory_menu;
accurate_best_tool_in_hotbar_for_block(block, menu, physics, fluid_on_eyes)
}
}
/// Returns the best tool in the hotbar for the given block.
///
/// Note that this doesn't take into account whether the player is on the ground
/// or in water, use [`accurate_best_tool_in_hotbar_for_block`] instead if you
/// care about those things.
pub fn best_tool_in_hotbar_for_block(block: BlockState, menu: &Menu) -> BestToolResult {
let mut physics = Physics::default();
physics.set_on_ground(true);
accurate_best_tool_in_hotbar_for_block(
block,
menu,
&physics,
&FluidOnEyes::new(FluidKind::Empty),
)
}
pub fn accurate_best_tool_in_hotbar_for_block(
block: BlockState,
menu: &Menu,
physics: &Physics,
fluid_on_eyes: &FluidOnEyes,
) -> BestToolResult {
let hotbar_slots = &menu.slots()[menu.hotbar_slots_range()];
let mut best_speed = 0.;
let mut best_slot = None;
let block = Box::<dyn BlockTrait>::from(block);
let registry_block = block.as_registry_block();
if matches!(
registry_block,
azalea_registry::Block::Water | azalea_registry::Block::Lava
) {
// can't mine fluids
return BestToolResult {
index: 0,
percentage_per_tick: 0.,
};
}
// find the first slot that has an item without durability
for (i, item_slot) in hotbar_slots.iter().enumerate() {
let this_item_speed;
match item_slot {
ItemStack::Empty => {
this_item_speed = Some(azalea_entity::mining::get_mine_progress(
block.as_ref(),
azalea_registry::Item::Air,
menu,
fluid_on_eyes,
physics,
));
}
ItemStack::Present(item_stack) => {
// lazy way to avoid checking durability since azalea doesn't have durability
// data yet
if !item_stack.components.has::<components::Damage>() {
this_item_speed = Some(azalea_entity::mining::get_mine_progress(
block.as_ref(),
item_stack.kind,
menu,
fluid_on_eyes,
physics,
));
} else {
this_item_speed = None;
}
}
}
if let Some(this_item_speed) = this_item_speed
&& this_item_speed > best_speed
{
best_slot = Some(i);
best_speed = this_item_speed;
}
}
// now check every item
for (i, item_slot) in hotbar_slots.iter().enumerate() {
if let ItemStack::Present(item_slot) = item_slot {
let this_item_speed = azalea_entity::mining::get_mine_progress(
block.as_ref(),
item_slot.kind,
menu,
fluid_on_eyes,
physics,
);
if this_item_speed > best_speed {
best_slot = Some(i);
best_speed = this_item_speed;
}
}
}
BestToolResult {
index: best_slot.unwrap_or(0),
percentage_per_tick: best_speed,
}
}
|