diff --git a/src/main/java/com/minelittlepony/unicopia/FlightType.java b/src/main/java/com/minelittlepony/unicopia/FlightType.java index e2329c0f..762a5f54 100644 --- a/src/main/java/com/minelittlepony/unicopia/FlightType.java +++ b/src/main/java/com/minelittlepony/unicopia/FlightType.java @@ -38,6 +38,10 @@ public enum FlightType { return this == INSECTOID ? USounds.ENTITY_PLAYER_CHANGELING_BUZZ : USounds.ENTITY_PLAYER_PEGASUS_WINGSFLAP; } + public float getWingFlapSoundPitch() { + return this == INSECTOID ? 0.66F : 1; + } + /** * Predicate for abilities to control whether a player can fly. * diff --git a/src/main/java/com/minelittlepony/unicopia/client/ClientInteractionManager.java b/src/main/java/com/minelittlepony/unicopia/client/ClientInteractionManager.java index 760c4d1d..2477ba5c 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/ClientInteractionManager.java +++ b/src/main/java/com/minelittlepony/unicopia/client/ClientInteractionManager.java @@ -64,28 +64,34 @@ public class ClientInteractionManager extends InteractionManager { client.execute(() -> { SoundManager soundManager = client.getSoundManager(); - if (type == SOUND_EARS_RINGING && source instanceof LivingEntity) { - soundManager.play(new LoopingSoundInstance<>((LivingEntity)source, + if (type == SOUND_EARS_RINGING && source instanceof LivingEntity living) { + soundManager.play(new LoopingSoundInstance<>(living, createTicker(100).and(e -> !e.isRemoved()), USounds.ENTITY_PLAYER_EARS_RINGING, 0.01F, 2, Random.create(seed)).setFadeIn() ); - } else if (type == SOUND_BEE && source instanceof BeeEntity) { + } else if (type == SOUND_BEE && source instanceof BeeEntity bee) { soundManager.playNextTick( - ((BeeEntity)source).hasAngerTime() - ? new AggressiveBeeSoundInstance(((BeeEntity)source)) - : new PassiveBeeSoundInstance(((BeeEntity)source)) + bee.hasAngerTime() + ? new AggressiveBeeSoundInstance(bee) + : new PassiveBeeSoundInstance(bee) ); - } else if (type == SOUND_MINECART && source instanceof AbstractMinecartEntity) { - soundManager.play(new MovingMinecartSoundInstance((AbstractMinecartEntity)source)); - } else if (type == SOUND_CHANGELING_BUZZ && source instanceof PlayerEntity) { - soundManager.play(new LoopingSoundInstance<>((PlayerEntity)source, e -> { + } else if (type == SOUND_MINECART && source instanceof AbstractMinecartEntity minecart) { + soundManager.play(new MovingMinecartSoundInstance(minecart)); + } else if (type == SOUND_CHANGELING_BUZZ && source instanceof PlayerEntity player) { + soundManager.play(new MotionBasedSoundInstance<>(USounds.ENTITY_PLAYER_CHANGELING_BUZZ, player, e -> { PlayerPhysics physics = Pony.of(e).getPhysics(); return physics.isFlying() && physics.getFlightType() == FlightType.INSECTOID; - }, USounds.ENTITY_PLAYER_CHANGELING_BUZZ, 1F, 1F, Random.create(seed))); - } else if (type == SOUND_GLIDING && source instanceof PlayerEntity && isClientPlayer((PlayerEntity) source)) { - soundManager.play(new MotionBasedSoundInstance(SoundEvents.ITEM_ELYTRA_FLYING, (PlayerEntity)source, Random.create(seed))); - } else if (type == SOUND_GLIDING && source instanceof PlayerEntity) { - soundManager.play(new MotionBasedSoundInstance(USounds.ENTITY_PLAYER_PEGASUS_FLYING, (PlayerEntity)source, Random.create(seed))); + }, 0.25F, 0.5F, 0.66F, Random.create(seed))); + } else if (type == SOUND_GLIDING && source instanceof PlayerEntity player && isClientPlayer(player)) { + soundManager.play(new MotionBasedSoundInstance<>(SoundEvents.ITEM_ELYTRA_FLYING, player, e -> { + Pony pony = Pony.of(e); + return pony.getPhysics().isFlying() && pony.getPhysics().getFlightType().isAvian(); + }, 0, 1, 1, Random.create(seed))); + } else if (type == SOUND_GLIDING && source instanceof PlayerEntity player) { + soundManager.play(new MotionBasedSoundInstance<>(USounds.ENTITY_PLAYER_PEGASUS_FLYING, player, e -> { + Pony pony = Pony.of(e); + return pony.getPhysics().isFlying() && pony.getPhysics().getFlightType().isAvian(); + }, 0, 1, 1, Random.create(seed))); } else if (type == SOUND_MAGIC_BEAM) { soundManager.play(new LoopedEntityTrackingSoundInstance(USounds.SPELL_CAST_SHOOT, 0.3F, 1F, source, seed)); } else if (type == SOUND_HEART_BEAT) { diff --git a/src/main/java/com/minelittlepony/unicopia/client/sound/MotionBasedSoundInstance.java b/src/main/java/com/minelittlepony/unicopia/client/sound/MotionBasedSoundInstance.java index 368f6cf5..759a74c4 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/sound/MotionBasedSoundInstance.java +++ b/src/main/java/com/minelittlepony/unicopia/client/sound/MotionBasedSoundInstance.java @@ -1,55 +1,57 @@ package com.minelittlepony.unicopia.client.sound; -import com.minelittlepony.unicopia.entity.player.Pony; +import java.util.function.Predicate; -import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.Entity; import net.minecraft.sound.SoundEvent; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.random.Random; -public class MotionBasedSoundInstance extends FadeOutSoundInstance { - +public class MotionBasedSoundInstance extends FadeOutSoundInstance { // Tune these if you want to change the way this sounds! // Currently just hardcoded for flying because nothing else uses this class private static final float MAX_VELOCITY = 1.5F; // Max velocity before we clamp volume (units/tick?) - private static final float VOLUME_AT_MAX = 1; private static final float ATTEN_EXPO = 2; // Exponent for velocity based attenuation private static final int FADEIN_TICKS = 20; // Ticks for fade-in private static final float MIN_PITCH = 0.7F; // Pitch at 0-speed private static final float MAX_PITCH = 2.6F; // Pitch at reference speed MAX_VELOCITY private static final float MAX_RATE_TICKS = 20; // How many ticks it takes to go from 0 to max volume (filter!) - private final PlayerEntity player; + private final E entity; private int tickCount; private float currentVal; // Cache last tick's curve value - public MotionBasedSoundInstance(SoundEvent sound, PlayerEntity player, Random random) { - super(sound, player.getSoundCategory(), 0.1F, random); - this.player = player; + private final float minVolume; + private final float maxVolume; + private final float referencePitch; + private final Predicate playingCondition; + + public MotionBasedSoundInstance(SoundEvent sound, E entity, Predicate playingCondition, float minVolume, float maxVolume, float pitch, Random random) { + super(sound, entity.getSoundCategory(), 0.1F, random); + this.entity = entity; + this.pitch = pitch; + this.referencePitch = pitch; + this.minVolume = minVolume; + this.maxVolume = maxVolume; + this.playingCondition = playingCondition; } @Override protected boolean shouldKeepPlaying() { ++tickCount; - if (player.isRemoved()) { - return false; - } - - Pony pony = Pony.of(player); - - if (!pony.getPhysics().isFlying() || !pony.getPhysics().getFlightType().isAvian()) { + if (entity.isRemoved() || !playingCondition.test(entity)) { return false; } // Update effect position - x = (float)player.getX(); - y = (float)player.getY(); - z = (float)player.getZ(); + x = (float)entity.getX(); + y = (float)entity.getY(); + z = (float)entity.getZ(); // Get velocity - float f = (float)player.getVelocity().horizontalLength(); + float f = (float)entity.getVelocity().horizontalLength(); float lastVal = currentVal; @@ -62,7 +64,7 @@ public class MotionBasedSoundInstance extends FadeOutSoundInstance { if (f >= 1.0E-7D) { // Multiply output volume by reference volume for overall gain control. - volume = currentVal * VOLUME_AT_MAX; + volume = MathHelper.lerp(currentVal, minVolume, maxVolume); } else { volume = 0.0F; } @@ -73,7 +75,7 @@ public class MotionBasedSoundInstance extends FadeOutSoundInstance { } // Control pitch with velocity - pitch = MathHelper.lerp(currentVal,MIN_PITCH,MAX_PITCH); + pitch = MathHelper.lerp(currentVal, MIN_PITCH, MAX_PITCH) * referencePitch; // Setting target volume every frame breaks interpolation. We set volume directly, // so that FadeOutSoundInstance only handles stopping the sound with an actual fade out! diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java index 2dd27150..9a812384 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java @@ -293,7 +293,9 @@ public class PlayerPhysics extends EntityPhysics implements Tickab strafe = 1; ticksToGlide = MAX_TICKS_TO_GLIDE; if (!SpellPredicate.IS_DISGUISE.isOn(pony)) { - entity.playSound(type.getWingFlapSound(), 0.25F, 1); + if (type != FlightType.INSECTOID) { + entity.playSound(type.getWingFlapSound(), 0.25F, entity.getSoundPitch() * type.getWingFlapSoundPitch()); + } entity.getWorld().emitGameEvent(entity, GameEvent.ELYTRA_GLIDE, entity.getPos()); } } else { @@ -362,31 +364,35 @@ public class PlayerPhysics extends EntityPhysics implements Tickab entity.playSound(USounds.ENTITY_PLAYER_PEGASUS_MOLT, 0.3F, 1); UCriteria.SHED_FEATHER.trigger(entity); } + } else { + applyThrust(velocity); } moveFlying(velocity); - if (type.isAvian()) { - if (entity.getWorld().isClient && ticksInAir % IDLE_FLAP_INTERVAL == 0 && entity.getVelocity().length() < 0.29) { - flapping = true; - ticksToGlide = MAX_TICKS_TO_GLIDE; - } + if (entity.getWorld().isClient && ticksInAir % IDLE_FLAP_INTERVAL == 0 && entity.getVelocity().length() < 0.29) { + flapping = true; + ticksToGlide = MAX_TICKS_TO_GLIDE; + } - if (!SpellPredicate.IS_DISGUISE.isOn(pony)) { - if (ticksInAir % GLIDING_SOUND_INTERVAL == 1 && pony.isClient()) { + if (type.isAvian()) { + if (!SpellPredicate.IS_DISGUISE.isOn(pony) && pony.isClient()) { + if (ticksInAir % GLIDING_SOUND_INTERVAL == 5) { InteractionManager.instance().playLoopingSound(entity, InteractionManager.SOUND_GLIDING, entity.getId()); } } - velocity.y -= 0.02 * getGravitySignum(); - velocity.x *= 0.9896; - velocity.z *= 0.9896; + } else if (type == FlightType.INSECTOID && !SpellPredicate.IS_DISGUISE.isOn(pony)) { if (entity.getWorld().isClient && !soundPlaying) { soundPlaying = true; InteractionManager.instance().playLoopingSound(entity, InteractionManager.SOUND_CHANGELING_BUZZ, entity.getId()); } } + + velocity.y -= 0.02 * getGravitySignum(); + velocity.x *= 0.9896; + velocity.z *= 0.9896; } private void tickArtificialFlight(MutableVector velocity) { @@ -517,12 +523,12 @@ public class PlayerPhysics extends EntityPhysics implements Tickab wallHitCooldown = MAX_WALL_HIT_CALLDOWN; if (bouncyness > 0) { - entity.playSound(USounds.ENTITY_PLAYER_REBOUND, 1, 1); + entity.playSound(USounds.ENTITY_PLAYER_REBOUND, 1, entity.getSoundPitch()); ProjectileUtil.ricochet(entity, Vec3d.of(pos), 0.4F + Math.min(2, bouncyness / 18F)); velocity.fromImmutable(entity.getVelocity()); distance /= bouncyness; } else { - entity.playSound(distance > 4 ? SoundEvents.ENTITY_PLAYER_BIG_FALL : SoundEvents.ENTITY_PLAYER_SMALL_FALL, 1, 1); + entity.playSound(distance > 4 ? SoundEvents.ENTITY_PLAYER_BIG_FALL : SoundEvents.ENTITY_PLAYER_SMALL_FALL, 1, entity.getSoundPitch()); } entity.damage(entity.getDamageSources().flyIntoWall(), distance); } @@ -572,7 +578,9 @@ public class PlayerPhysics extends EntityPhysics implements Tickab if (thrustScale <= 0.000001F & flapping) { flapping = false; if (!SpellPredicate.IS_DISGUISE.isOn(pony)) { - entity.playSound(getFlightType().getWingFlapSound(), 0.5F, 1); + if (getFlightType() != FlightType.INSECTOID) { + entity.playSound(getFlightType().getWingFlapSound(), 0.25F, entity.getSoundPitch() * getFlightType().getWingFlapSoundPitch()); + } entity.getWorld().emitGameEvent(entity, GameEvent.ELYTRA_GLIDE, entity.getPos()); } thrustScale = 1; @@ -601,7 +609,6 @@ public class PlayerPhysics extends EntityPhysics implements Tickab if (velocity.y < 0 && hovering) { velocity.y *= 0.01; } - } private void applyTurbulance(MutableVector velocity) {