Merge pull request #8392 from MSedgeMC/fix/dolphin-attack-sound

🤖 Agent: checked in the 26.3 jar: Dolphin.playAttackSound is playSound(DOLPHIN_ATTACK, 1.0, 1.0) and Entity.playSound returns for a silent entity, so the new !m.silent on the axolotl arm fixes a second mismatch too; the test skips in CI without the extracted mob types.
This commit is contained in:
Ludovic Marie authored and GitHub committed 2026-11-03 18:25:10 +01:00
commit 68586a41aa
3 files changed
+77 -1

No files matched your search

+75 -1
View File
@@ -2528,11 +2528,19 @@ pub fn do_hurt_target(m: &mut Mob, who: Who, cx: &mut Cx) {
.push(MobEvent::Sound("entity.panda.bite", at, 1.0, 1.0));
}
// Axolotl.playAttackSound: playSound(AXOLOTL_ATTACK, 1.0, 1.0).
if m.species() == Species::Axolotl {
if m.species() == Species::Axolotl && !m.silent {
let at = [m.position.x, m.position.y, m.position.z];
cx.events
.push(MobEvent::Sound("entity.axolotl.attack", at, 1.0, 1.0));
}
// Dolphin.playAttackSound: playSound(DOLPHIN_ATTACK, 1.0, 1.0), once
// the blow landed. A dolphin that is hurt takes its attacker as a target
// and strikes with the melee goal, so its bite is heard as it lands.
if m.species() == Species::Dolphin && !m.silent {
let at = [m.position.x, m.position.y, m.position.z];
cx.events
.push(MobEvent::Sound("entity.dolphin.attack", at, 1.0, 1.0));
}
let _ = Fluid::None;
}
/// Mob.ate (sheep regrow wool, babies grow).
@@ -3270,6 +3278,72 @@ mod hit_effect_tests {
}
}
#[cfg(test)]
mod attack_sound_tests {
use super::*;
use crate::mobs::world::with_test_world;
use std::sync::Arc;
/// The sounds `do_hurt_target` raises for `kind` on a blow that landed,
/// with `silent` set on the attacker; `None` without the extracted data.
fn attack_sounds(kind: &str, silent: bool) -> Option<Vec<(&'static str, f32, f32)>> {
let mut heard = Vec::new();
let ran = with_test_world(&[], |w, types| {
let mut m = Mob::new(
1,
Arc::new(types.types[kind].clone()),
Vec3::new(0.5, 64.0, 0.5),
0.0,
);
m.silent = silent;
let (mut lr, mut events) = (horizon_core::random::LegacyRandom::new(0), Vec::new());
let mut cx = Cx {
w,
lr: &mut lr,
events: &mut events,
};
do_hurt_target(&mut m, Who::Mob(2), &mut cx);
heard = events
.iter()
.filter_map(|e| match e {
MobEvent::Sound(s, _, volume, pitch) => Some((*s, *volume, *pitch)),
_ => None,
})
.collect();
});
if !ran {
return None;
}
Some(heard)
}
/// `Mob.doHurtTarget` ends with `playAttackSound`, which `Dolphin`,
/// `Axolotl` and `Panda` override with their own bite at volume 1 and
/// pitch 1. Without the dolphin arm its bite is silent (no sound event at
/// all); the axolotl and the panda sit next to it as the control.
#[test]
fn a_dolphins_blow_plays_its_attack_sound() {
let Some(dolphin) = attack_sounds("minecraft:dolphin", false) else {
return;
};
assert_eq!(dolphin, vec![("entity.dolphin.attack", 1.0, 1.0)]);
for (kind, sound) in [
("minecraft:axolotl", "entity.axolotl.attack"),
("minecraft:panda", "entity.panda.bite"),
] {
assert_eq!(
attack_sounds(kind, false),
Some(vec![(sound, 1.0, 1.0)]),
"{kind}"
);
}
// Entity.playSound skips a silent entity, so neither attack sound plays.
for kind in ["minecraft:dolphin", "minecraft:axolotl", "minecraft:panda"] {
assert_eq!(attack_sounds(kind, true), Some(vec![]), "{kind}");
}
}
}
#[cfg(test)]
mod same_vehicle_push_tests {
use super::*;
+1
View File
@@ -53,6 +53,7 @@ Axolotl.applyImplicitComponent port crates/horizon-client/src/entity_nbt.rs::app
Axolotl.getBreedOffspring port crates/horizon-client/src/game/creatures.rs::Game::breed gap: baby takes the first parent's colour; no random parent, no 1-in-1200 blue, not set persistent
Axolotl.createAttributes skip:data attributes come from entity-types.json
Axolotl.mobInteract port crates/horizon-client/src/game/creatures.rs::Game::interact_mob a water bucket scoops it up (bucketable)
Axolotl.playAttackSound port crates/horizon-client/src/mobs/ai.rs::do_hurt_target AXOLOTL_ATTACK at 1.0/1.0 after the blow lands, skipped for a silent mob
Axolotl.loadFromBucketTag port crates/horizon-client/src/entity_nbt.rs::apply_item_components age, age lock and hunting cooldown from the bucket_entity_data component
Axolotl.applySupportingEffects inline crates/horizon-client/src/game/creatures.rs::Game::handle_mob_events the AxolotlSupportPlayer event: regeneration and no mining fatigue, host player only
Axolotl.usePlayerItem port crates/horizon-client/src/game/creatures.rs::Game::interact_mob a fed tropical fish bucket leaves a water bucket in its place (creative keeps the fish bucket and adds the bucket)
1 AbstractFish.addAdditionalSaveData inline crates/horizon-client/src/entity_nbt.rs::mob_to_nbt FromBucket always written; tadpole getter is always true
53 Axolotl.getBreedOffspring port crates/horizon-client/src/game/creatures.rs::Game::breed gap: baby takes the first parent's colour; no random parent, no 1-in-1200 blue, not set persistent
54 Axolotl.createAttributes skip:data attributes come from entity-types.json
55 Axolotl.mobInteract port crates/horizon-client/src/game/creatures.rs::Game::interact_mob a water bucket scoops it up (bucketable)
56 Axolotl.playAttackSound port crates/horizon-client/src/mobs/ai.rs::do_hurt_target AXOLOTL_ATTACK at 1.0/1.0 after the blow lands, skipped for a silent mob
57 Axolotl.loadFromBucketTag port crates/horizon-client/src/entity_nbt.rs::apply_item_components age, age lock and hunting cooldown from the bucket_entity_data component
58 Axolotl.applySupportingEffects inline crates/horizon-client/src/game/creatures.rs::Game::handle_mob_events the AxolotlSupportPlayer event: regeneration and no mining fatigue, host player only
59 Axolotl.usePlayerItem port crates/horizon-client/src/game/creatures.rs::Game::interact_mob a fed tropical fish bucket leaves a water bucket in its place (creative keeps the fish bucket and adds the bucket)
+1
View File
@@ -114,6 +114,7 @@ Dolphin.readAdditionalSaveData port crates/horizon-client/src/entity_nbt.rs::mob
Dolphin.registerGoals port crates/horizon-client/src/mobs/aquatic.rs::register gap: player: no MoveToItemGoal and PlayWithItemsGoal (dolphins ignore items thrown in the water), no FollowPlayerRiddenEntityGoal for boats or nautiluses, no AvoidEntity of guardians, and HurtByTarget does not skip guardians
Dolphin.createAttributes skip:data attributes come from the entity tables
Dolphin.canAttack port crates/horizon-client/src/mobs/goals.rs::spares_target a baby dolphin takes nobody as its target
Dolphin.playAttackSound port crates/horizon-client/src/mobs/ai.rs::do_hurt_target the dolphin arm: DOLPHIN_ATTACK at 1.0/1.0 after the blow lands, skipped for a silent mob
Dolphin.pickUpItem port crates/horizon-client/src/game/foxes.rs::Game::tick_dolphins the game finds the first allowed item in the water within 8 blocks and takes it
Dolphin.handleEntityEvent port crates/horizon-client-render/src/particles.rs::entity_event_burst event 38: seven happy villager particles about the dolphin
Dolphin.closeToNextPos inline crates/horizon-client/src/mobs/dolphin.rs::SwimToTreasure::tick nav target within 12 blocks (144 squared) of the dolphin
1 MemoryMap.equals skip:java map equality of a built memory set
114 Dolphin.registerGoals port crates/horizon-client/src/mobs/aquatic.rs::register gap: player: no MoveToItemGoal and PlayWithItemsGoal (dolphins ignore items thrown in the water), no FollowPlayerRiddenEntityGoal for boats or nautiluses, no AvoidEntity of guardians, and HurtByTarget does not skip guardians
115 Dolphin.createAttributes skip:data attributes come from the entity tables
116 Dolphin.canAttack port crates/horizon-client/src/mobs/goals.rs::spares_target a baby dolphin takes nobody as its target
117 Dolphin.playAttackSound port crates/horizon-client/src/mobs/ai.rs::do_hurt_target the dolphin arm: DOLPHIN_ATTACK at 1.0/1.0 after the blow lands, skipped for a silent mob
118 Dolphin.pickUpItem port crates/horizon-client/src/game/foxes.rs::Game::tick_dolphins the game finds the first allowed item in the water within 8 blocks and takes it
119 Dolphin.handleEntityEvent port crates/horizon-client-render/src/particles.rs::entity_event_burst event 38: seven happy villager particles about the dolphin
120 Dolphin.closeToNextPos inline crates/horizon-client/src/mobs/dolphin.rs::SwimToTreasure::tick nav target within 12 blocks (144 squared) of the dolphin