Make a bat flap the sculk sensors while it is awake

Entity.processFlappingMovement emits a flap game event when the entity flaps over air;
Bee and Bat each override isFlapping, a bee every other tick while flying and a bat every
tenth tick while it is not resting. Horizon only modelled the bee, so a bat flying around
was silent to sculk sensors and a warden.
This commit is contained in:
MSedgeMC committed 2026-11-01 18:07:37 +00:00
1 parent 1bd24e4042
commit e35d09582c
1 file changed
+32 -5
+32 -5
View File
@@ -1713,6 +1713,7 @@ impl Game<'_> {
Option<i64>,
Option<u32>,
u32,
bool,
)> = self
.mobs
.iter()
@@ -1727,10 +1728,11 @@ impl Game<'_> {
m.last_damage.map(|(_, t)| t),
m.extra.mount,
m.age,
m.species() == Species::Bat && horizon_client::mobs::bat::resting(m),
)
})
.collect();
for (id, at, on_ground, in_water, species, damaged, vehicle, age) in snapshot {
for (id, at, on_ground, in_water, species, damaged, vehicle, age, resting) in snapshot {
if on_ground {
self.step_on_redstone_ore(at, false, false);
}
@@ -1749,10 +1751,10 @@ impl Game<'_> {
false,
warden,
);
// Entity.processFlappingMovement with Bee.isFlapping: a bee off
// the ground over air flaps on every other tick (the mob's own
// `MobEvent::GameEvent` is not read here).
if species == Species::Bee && !on_ground && age.is_multiple_of(2) {
// Entity.processFlappingMovement: what flaps this move flaps
// over air only (the mob's own `MobEvent::GameEvent` is not
// read here).
if flaps(species, resting, on_ground, age) {
let below = self.world.block(
at[0].floor() as i32,
(at[1] - 1.0e-5).floor() as i32,
@@ -1954,6 +1956,17 @@ pub(super) fn darkness_blend_added(e: &EffectInstance, blend: bool) -> (f32, f32
(factor, factor)
}
/// `Entity.processFlappingMovement`'s per-tick gate, before its air-below
/// test: `Bee.isFlapping` (flying, every other tick) and `Bat.isFlapping`
/// (awake, every tenth tick).
fn flaps(species: Species, resting: bool, on_ground: bool, age: u32) -> bool {
match species {
Species::Bee => !on_ground && age.is_multiple_of(2),
Species::Bat => !resting && age.is_multiple_of(10),
_ => false,
}
}
#[cfg(test)]
mod tests {
use super::*;
@@ -1973,6 +1986,20 @@ mod tests {
assert_eq!(index.iter().last(), Some(&(41, 4, 0)));
}
/// A bat flaps every tenth tick while it is not resting, whether it is on
/// the ground or not; a resting bat never flaps and nothing else does.
#[test]
fn a_bat_flaps_every_tenth_tick_unless_it_is_resting() {
assert!(flaps(Species::Bat, false, false, 0));
assert!(flaps(Species::Bat, false, true, 10));
assert!(!flaps(Species::Bat, false, false, 11));
assert!(!flaps(Species::Bat, true, false, 20), "resting");
assert!(flaps(Species::Bee, false, false, 4));
assert!(!flaps(Species::Bee, false, true, 4), "a bee on the ground");
assert!(!flaps(Species::Bat, false, false, 5));
assert!(!flaps(Species::Cow, false, false, 0));
}
#[test]
fn centres_and_blocks_agree() {
assert_eq!(center((1, 2, 3)), [1.5, 2.5, 3.5]);