azalea_entity/
effects.rs

1use std::{
2    collections::HashMap,
3    io::{self, Cursor, Write},
4};
5
6use azalea_buf::{AzBuf, AzaleaRead, AzaleaWrite, BufReadError};
7use azalea_core::bitset::FixedBitSet;
8use azalea_registry::MobEffect;
9use bevy_ecs::component::Component;
10
11/// Data about an active mob effect.
12#[derive(Clone, Debug, Default, PartialEq, AzBuf)]
13pub struct MobEffectData {
14    /// The effect's amplifier level, starting at 0 if present.
15    #[var]
16    pub amplifier: u32,
17    #[var]
18    pub duration_ticks: u32,
19
20    pub flags: MobEffectFlags,
21}
22
23#[derive(Clone, Debug, Default, PartialEq)]
24pub struct MobEffectFlags {
25    pub ambient: bool,
26    pub show_particles: bool,
27    pub show_icon: bool,
28    pub blend: bool,
29}
30
31impl AzaleaRead for MobEffectFlags {
32    fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
33        let bitset = FixedBitSet::<8>::azalea_read(buf)?;
34        let ambient = bitset.index(0);
35        let show_particles = bitset.index(1);
36        let show_icon = bitset.index(2);
37        let blend = bitset.index(3);
38        Ok(Self {
39            ambient,
40            show_particles,
41            show_icon,
42            blend,
43        })
44    }
45}
46
47impl AzaleaWrite for MobEffectFlags {
48    fn azalea_write(&self, buf: &mut impl Write) -> io::Result<()> {
49        let mut bitset = FixedBitSet::<8>::new();
50        if self.ambient {
51            bitset.set(0);
52        }
53        if self.show_particles {
54            bitset.set(1);
55        }
56        if self.show_icon {
57            bitset.set(2);
58        }
59        if self.blend {
60            bitset.set(3);
61        }
62        bitset.azalea_write(buf)
63    }
64}
65
66/// An ECS component that stores the active mob effects on an entity.
67#[derive(Component, Clone, Debug, Default)]
68pub struct ActiveEffects(pub HashMap<MobEffect, MobEffectData>);
69impl ActiveEffects {
70    pub fn insert(&mut self, effect: MobEffect, data: MobEffectData) {
71        self.0.insert(effect, data);
72    }
73
74    pub fn remove(&mut self, effect: MobEffect) -> Option<MobEffectData> {
75        self.0.remove(&effect)
76    }
77
78    /// Get the amplifier level for the effect, starting at 0.
79    pub fn get_level(&self, effect: MobEffect) -> Option<u32> {
80        self.0.get(&effect).map(|data| data.amplifier)
81    }
82
83    pub fn get(&self, effect: MobEffect) -> Option<&MobEffectData> {
84        self.0.get(&effect)
85    }
86
87    /// Returns the amplifier for dig speed (haste / conduit power), if present.
88    pub fn get_dig_speed_amplifier(&self) -> Option<u32> {
89        let haste_level = self
90            .get_level(MobEffect::Haste)
91            .map(|level| level + 1)
92            .unwrap_or_default();
93        let conduit_power_level = self
94            .get_level(MobEffect::ConduitPower)
95            .map(|level| level + 1)
96            .unwrap_or_default();
97
98        let effect_plus_one = u32::max(haste_level, conduit_power_level);
99        if effect_plus_one > 0 {
100            Some(effect_plus_one - 1)
101        } else {
102            None
103        }
104    }
105}