Merge pull request #2514 from kacpherek/fix/amethyst-step-chime

🤖 Agent: Merged by Ludovic's AI agent (Claude, contrib-gate-19). Thanks @kacpherek: Play the amethyst chime when walking on amethyst blocks. I checked it against vanilla 26.3, and it passed every harness it reaches in a union with your other PRs, plus lan_e2e in both modes.
This commit is contained in:
Ludovic Marie
2026-10-27 09:33:40 +01:00
committed by GitHub
3 changed files with 54 additions and 0 deletions
+8
View File
@@ -4740,6 +4740,14 @@ impl Game<'_> {
self.audio
.play("minecraft:entity.player.swim", Some(feet), volume, pitch);
}
MotionEvent::Chime { volume, pitch } => {
self.audio.play(
"minecraft:block.amethyst_block.chime",
Some(feet),
volume,
pitch,
);
}
MotionEvent::Drown => {
// LivingEntity.makeDrownParticles: eight bubbles moving
// with the player.
+8
View File
@@ -3403,6 +3403,14 @@ impl Game<'_> {
self.audio
.play("minecraft:entity.player.swim", Some(feet), volume, pitch);
}
horizon_client::motion::MotionEvent::Chime { volume, pitch } => {
self.audio.play(
"minecraft:block.amethyst_block.chime",
Some(feet),
volume,
pitch,
);
}
// NetherPortalBlock.entityInside on the client's own level:
// the portal overlay and its trigger sound (the server moves
// the player).
+38
View File
@@ -55,6 +55,8 @@ pub struct MotionResources {
/// `BlockTags.SOUL_SPEED_BLOCKS`: what Soul Speed's effects look for.
pub soul_speed_blocks: BTreeSet<String>,
pub fall_reset: BTreeSet<String>,
/// `BlockTags.CRYSTAL_SOUND_BLOCKS`: blocks that chime under footsteps.
pub crystal_sound: BTreeSet<String>,
pub landing: BlockLandingRegistry,
pub health: crate::health::HealthResources,
pub fluids: FluidResources,
@@ -115,6 +117,7 @@ impl MotionResources {
glide_through: tag("minecraft:can_glide_through")?,
soul_speed_blocks: tag("minecraft:soul_speed_blocks")?,
fall_reset: tag("minecraft:fall_damage_resetting")?,
crystal_sound: tag("minecraft:crystal_sound_blocks")?,
})
}
}
@@ -165,6 +168,11 @@ pub enum MotionEvent {
state: BlockStateId,
in_water: bool,
},
/// `Entity.playAmethystStepSound`: `block.amethyst_block.chime`.
Chime {
volume: f32,
pitch: f32,
},
/// `Entity.waterSwimSound`: `entity.player.swim`.
Swim {
volume: f32,
@@ -309,6 +317,10 @@ pub struct PlayerMotion {
/// `Entity.moveDist`, `flyDist` and `nextStep`: footsteps come once per
/// metre walked, not once per move.
pub steps: MovementDistances,
/// `Entity.crystalSoundIntensity` and `lastCrystalSoundPlayTick`: the
/// amethyst chime grows with steps taken close together.
pub crystal_sound_intensity: f32,
pub last_crystal_sound_play_tick: i32,
pub needs_sync: bool,
pub sync_position: bool,
/// Moved by an ender pearl (`ServerPlayer.teleport`): a server sends the
@@ -501,6 +513,8 @@ impl PlayerMotion {
next_step: 1.0,
..MovementDistances::default()
},
crystal_sound_intensity: 0.0,
last_crystal_sound_play_tick: 0,
needs_sync: false,
sync_position: false,
teleported: false,
@@ -2164,6 +2178,30 @@ impl MovementEmissionWorld for MotionWorld<'_, '_, '_> {
state,
in_water,
});
// Entity.walkingStepSound: the amethyst chime after the step.
let name = &self
.assets
.registry
.state(state)
.ok_or("missing scene state")?
.name;
let tick = self.player.health.tick_count;
if self.resources.crystal_sound.contains(name)
&& tick >= self.player.last_crystal_sound_play_tick + 20
{
// Entity.playAmethystStepSound (the level random stands in for
// the entity's).
let elapsed = f64::from(tick - self.player.last_crystal_sound_play_tick);
let decayed = self.player.crystal_sound_intensity * 0.997_f64.powf(elapsed) as f32;
let intensity = 1.0_f32.min(decayed + 0.07);
self.player.crystal_sound_intensity = intensity;
let pitch = 0.5 + intensity * self.scene.random.next_float() * 1.2;
let volume = 0.1 + intensity * 1.2;
self.player
.events
.push(MotionEvent::Chime { volume, pitch });
self.player.last_crystal_sound_play_tick = tick;
}
Ok(())
}
fn step_event(&mut self, _: BlockStateId) -> Result<()> {