azalea/client_impl/
attack.rs

1use azalea_client::attack::{
2    AttackEvent, AttackStrengthScale, TicksSinceLastAttack, get_attack_strength_delay,
3};
4use azalea_entity::Attributes;
5use bevy_ecs::entity::Entity;
6
7use crate::Client;
8
9impl Client {
10    /// Attack an entity in the world.
11    ///
12    /// This doesn't automatically look at the entity or perform any
13    /// range/visibility checks, so it might trigger anticheats.
14    pub fn attack(&self, entity: Entity) {
15        self.ecs.write().write_message(AttackEvent {
16            entity: self.entity,
17            target: entity,
18        });
19    }
20
21    /// Whether the player has an attack cooldown.
22    ///
23    /// Also see [`Client::attack_cooldown_remaining_ticks`].
24    pub fn has_attack_cooldown(&self) -> bool {
25        let Some(attack_strength_scale) = self.get_component::<AttackStrengthScale>() else {
26            // they don't even have an AttackStrengthScale so they probably can't even
27            // attack? whatever, just return false
28            return false;
29        };
30        **attack_strength_scale < 1.0
31    }
32
33    /// Returns the number of ticks until we can attack at full strength again.
34    ///
35    /// Also see [`Client::has_attack_cooldown`].
36    pub fn attack_cooldown_remaining_ticks(&self) -> usize {
37        let ecs = self.ecs.read();
38
39        let Some(attributes) = ecs.get::<Attributes>(self.entity) else {
40            return 0;
41        };
42        let Some(ticks_since_last_attack) = ecs.get::<TicksSinceLastAttack>(self.entity) else {
43            return 0;
44        };
45
46        let attack_strength_delay = get_attack_strength_delay(attributes);
47        let remaining_ticks = attack_strength_delay - **ticks_since_last_attack as f32;
48
49        remaining_ticks.max(0.).ceil() as usize
50    }
51}