aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md1
-rw-r--r--azalea-client/src/plugins/packet/game/mod.rs10
-rw-r--r--azalea-entity/src/effects.rs106
-rw-r--r--azalea-entity/src/mining.rs10
-rw-r--r--azalea-physics/src/lib.rs6
-rw-r--r--azalea-protocol/src/packets/game/c_update_mob_effect.rs45
6 files changed, 78 insertions, 100 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3ddad98b..1d83334b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -21,6 +21,7 @@ is breaking anyways, semantic versioning is not followed.
- Rename `SendPacketEvent` to `SendGamePacketEvent` and `PingEvent` to `GamePingEvent`.
- Swap the order of the type parameters in entity filtering functions so query is first, then filter.
- Add optional `timeout_ticks` field to `Client::open_container_at`.
+- Implement initial support for mob effects, including jump boost, haste, conduit power, and mining fatigue. (@ShayBox)
### Fixed
diff --git a/azalea-client/src/plugins/packet/game/mod.rs b/azalea-client/src/plugins/packet/game/mod.rs
index 40446cee..fd5ebef2 100644
--- a/azalea-client/src/plugins/packet/game/mod.rs
+++ b/azalea-client/src/plugins/packet/game/mod.rs
@@ -8,7 +8,7 @@ use azalea_core::{
};
use azalea_entity::{
ActiveEffects, Dead, EntityBundle, EntityKindComponent, HasClientLoaded, LoadedBy, LocalEntity,
- LookDirection, MobEffectData, Physics, PlayerAbilities, Position, RelativeEntityUpdate,
+ LookDirection, Physics, PlayerAbilities, Position, RelativeEntityUpdate,
indexing::{EntityIdIndex, EntityUuidIndex},
metadata::{Health, apply_metadata},
};
@@ -1108,13 +1108,7 @@ impl GamePacketHandler<'_> {
debug!("Got update mob effect packet {p:?}");
let mob_effect = p.mob_effect;
- let effect_data = MobEffectData::new(
- p.effect_amplifier,
- p.effect_duration_ticks,
- p.flags.ambient,
- p.flags.show_particles,
- p.flags.show_icon,
- );
+ let effect_data = &p.data;
as_system::<(Commands, Query<(&EntityIdIndex, &InstanceHolder)>)>(
self.ecs,
diff --git a/azalea-entity/src/effects.rs b/azalea-entity/src/effects.rs
index d905414d..9519c627 100644
--- a/azalea-entity/src/effects.rs
+++ b/azalea-entity/src/effects.rs
@@ -1,46 +1,69 @@
-use std::collections::HashMap;
+use std::{
+ collections::HashMap,
+ io::{self, Cursor, Write},
+};
+use azalea_buf::{AzBuf, AzaleaRead, AzaleaWrite, BufReadError};
+use azalea_core::bitset::FixedBitSet;
use azalea_registry::MobEffect;
use bevy_ecs::component::Component;
-/// Data about an active mob effect that the client knows about.
-#[derive(Clone, Debug, Default)]
+/// Data about an active mob effect.
+#[derive(Clone, Debug, Default, PartialEq, AzBuf)]
pub struct MobEffectData {
+ /// The effect's amplifier level, starting at 0 if present.
+ #[var]
pub amplifier: u32,
+ #[var]
pub duration_ticks: u32,
+
+ pub flags: MobEffectFlags,
+}
+
+#[derive(Clone, Debug, Default, PartialEq)]
+pub struct MobEffectFlags {
pub ambient: bool,
pub show_particles: bool,
pub show_icon: bool,
+ pub blend: bool,
}
-impl MobEffectData {
- pub fn new(
- amplifier: u32,
- duration_ticks: u32,
- ambient: bool,
- show_particles: bool,
- show_icon: bool,
- ) -> Self {
- Self {
- amplifier,
- duration_ticks,
+
+impl AzaleaRead for MobEffectFlags {
+ fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
+ let bitset = FixedBitSet::<8>::azalea_read(buf)?;
+ let ambient = bitset.index(0);
+ let show_particles = bitset.index(1);
+ let show_icon = bitset.index(2);
+ let blend = bitset.index(3);
+ Ok(Self {
ambient,
show_particles,
show_icon,
- }
+ blend,
+ })
}
+}
- pub fn is_ambient(&self) -> bool {
- self.ambient
- }
- pub fn should_show_particles(&self) -> bool {
- self.show_particles
- }
- pub fn should_show_icon(&self) -> bool {
- self.show_icon
+impl AzaleaWrite for MobEffectFlags {
+ fn azalea_write(&self, buf: &mut impl Write) -> io::Result<()> {
+ let mut bitset = FixedBitSet::<8>::new();
+ if self.ambient {
+ bitset.set(0);
+ }
+ if self.show_particles {
+ bitset.set(1);
+ }
+ if self.show_icon {
+ bitset.set(2);
+ }
+ if self.blend {
+ bitset.set(3);
+ }
+ bitset.azalea_write(buf)
}
}
-/// Component storing the active mob effects on an entity.
+/// An ECS component that stores the active mob effects on an entity.
#[derive(Component, Clone, Debug, Default)]
pub struct ActiveEffects(pub HashMap<MobEffect, MobEffectData>);
impl ActiveEffects {
@@ -52,6 +75,7 @@ impl ActiveEffects {
self.0.remove(&effect)
}
+ /// Get the amplifier level for the effect, starting at 0.
pub fn get_level(&self, effect: MobEffect) -> Option<u32> {
self.0.get(&effect).map(|data| data.amplifier)
}
@@ -59,27 +83,23 @@ impl ActiveEffects {
pub fn get(&self, effect: MobEffect) -> Option<&MobEffectData> {
self.0.get(&effect)
}
-}
-/// Returns the level (amplifier) of the given effect, or `None` if the effect
-/// is not active. The lowest level is 0.
-pub fn get_effect(active_effects: &ActiveEffects, effect: MobEffect) -> Option<u32> {
- active_effects.get_level(effect)
-}
-
-/// Returns the amplifier for dig speed (haste / conduit power), if present.
-pub fn get_dig_speed_amplifier(active_effects: &ActiveEffects) -> Option<u32> {
- let effect_plus_one = u32::max(
- get_effect(active_effects, MobEffect::Haste)
+ /// Returns the amplifier for dig speed (haste / conduit power), if present.
+ pub fn get_dig_speed_amplifier(&self) -> Option<u32> {
+ let haste_level = self
+ .get_level(MobEffect::Haste)
.map(|level| level + 1)
- .unwrap_or_default(),
- get_effect(active_effects, MobEffect::ConduitPower)
+ .unwrap_or_default();
+ let conduit_power_level = self
+ .get_level(MobEffect::ConduitPower)
.map(|level| level + 1)
- .unwrap_or_default(),
- );
- if effect_plus_one > 0 {
- Some(effect_plus_one - 1)
- } else {
- None
+ .unwrap_or_default();
+
+ let effect_plus_one = u32::max(haste_level, conduit_power_level);
+ if effect_plus_one > 0 {
+ Some(effect_plus_one - 1)
+ } else {
+ None
+ }
}
}
diff --git a/azalea-entity/src/mining.rs b/azalea-entity/src/mining.rs
index 7c142020..2008da34 100644
--- a/azalea-entity/src/mining.rs
+++ b/azalea-entity/src/mining.rs
@@ -1,8 +1,8 @@
use azalea_block::{BlockBehavior, BlockTrait};
use azalea_core::tier::get_item_tier;
-use azalea_registry as registry;
+use azalea_registry::{self as registry, MobEffect};
-use crate::{ActiveEffects, FluidOnEyes, Physics, effects};
+use crate::{ActiveEffects, FluidOnEyes, Physics};
/// How much progress is made towards mining the block per tick, as a
/// percentage.
@@ -98,13 +98,11 @@ fn destroy_speed(
// efficiency_level + 1) as f32; }
// }
- if let Some(dig_speed_amplifier) = effects::get_dig_speed_amplifier(active_effects) {
+ if let Some(dig_speed_amplifier) = active_effects.get_dig_speed_amplifier() {
base_destroy_speed *= 1. + (dig_speed_amplifier + 1) as f32 * 0.2;
}
- if let Some(dig_slowdown) =
- effects::get_effect(active_effects, registry::MobEffect::MiningFatigue)
- {
+ if let Some(dig_slowdown) = active_effects.get_level(MobEffect::MiningFatigue) {
let multiplier = match dig_slowdown {
0 => 0.3,
1 => 0.09,
diff --git a/azalea-physics/src/lib.rs b/azalea-physics/src/lib.rs
index e3b95484..ad4626fb 100644
--- a/azalea-physics/src/lib.rs
+++ b/azalea-physics/src/lib.rs
@@ -350,10 +350,14 @@ pub fn jump_from_ground(
let base_jump = jump_power(&world, position);
let jump_power = base_jump + jump_boost_power(active_effects);
+ if jump_power <= 1.0E-5 {
+ return;
+ }
+
let old_delta_movement = physics.velocity;
physics.velocity = Vec3 {
x: old_delta_movement.x,
- y: f64::from(jump_power),
+ y: f64::max(jump_power as f64, old_delta_movement.y),
z: old_delta_movement.z,
};
if *sprinting {
diff --git a/azalea-protocol/src/packets/game/c_update_mob_effect.rs b/azalea-protocol/src/packets/game/c_update_mob_effect.rs
index 896d547b..e9892950 100644
--- a/azalea-protocol/src/packets/game/c_update_mob_effect.rs
+++ b/azalea-protocol/src/packets/game/c_update_mob_effect.rs
@@ -1,6 +1,5 @@
-use std::io::{Cursor, Write};
-
-use azalea_buf::{AzBuf, AzaleaRead, AzaleaWrite, BufReadError};
+use azalea_buf::AzBuf;
+use azalea_entity::MobEffectData;
use azalea_protocol_macros::ClientboundGamePacket;
use azalea_registry::MobEffect;
use azalea_world::MinecraftEntityId;
@@ -10,43 +9,5 @@ pub struct ClientboundUpdateMobEffect {
#[var]
pub entity_id: MinecraftEntityId,
pub mob_effect: MobEffect,
- #[var]
- pub effect_amplifier: u32,
- #[var]
- pub effect_duration_ticks: u32,
- pub flags: MobEffectFlags,
-}
-
-#[derive(Clone, Debug, Default, PartialEq)]
-pub struct MobEffectFlags {
- pub ambient: bool,
- pub show_particles: bool,
- pub show_icon: bool,
-}
-
-impl AzaleaRead for MobEffectFlags {
- fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
- let bits = u8::azalea_read(buf)?;
- Ok(MobEffectFlags {
- ambient: bits & 0x01 != 0,
- show_particles: bits & 0x02 != 0,
- show_icon: bits & 0x04 != 0,
- })
- }
-}
-
-impl AzaleaWrite for MobEffectFlags {
- fn azalea_write(&self, buf: &mut impl Write) -> std::io::Result<()> {
- let mut bits = 0;
- if self.ambient {
- bits |= 0x01;
- }
- if self.show_particles {
- bits |= 0x02;
- }
- if self.show_icon {
- bits |= 0x04;
- }
- bits.azalea_write(buf)
- }
+ pub data: MobEffectData,
}