From ca12692dc7eb682286a1405c0512db8ed162df1d Mon Sep 17 00:00:00 2001 From: LostLuma Date: Fri, 29 Sep 2023 03:28:55 +0200 Subject: [PATCH] Pause soundmanager instead of stopping all sounds for zero volumes --- .../java/dynamic_fps/impl/DynamicFPSMod.java | 38 +++++++++++-------- .../impl/mixin/SoundEngineMixin.java | 25 ++++++++++++ src/main/resources/dynamic_fps.mixins.json | 1 + 3 files changed, 49 insertions(+), 15 deletions(-) create mode 100644 src/main/java/dynamic_fps/impl/mixin/SoundEngineMixin.java diff --git a/src/main/java/dynamic_fps/impl/DynamicFPSMod.java b/src/main/java/dynamic_fps/impl/DynamicFPSMod.java index dacbed60..8acbdaa0 100644 --- a/src/main/java/dynamic_fps/impl/DynamicFPSMod.java +++ b/src/main/java/dynamic_fps/impl/DynamicFPSMod.java @@ -109,6 +109,10 @@ public static int targetFrameRate() { return config.frameRateTarget(); } + public static float volumeMultiplier() { + return config.volumeMultiplier(); + } + public static boolean shouldShowToasts() { return config.showToasts(); } @@ -200,23 +204,27 @@ private static void checkForStateChanges() { } } - private static boolean willPauseSounds() { - return !minecraft.isWindowActive() && minecraft.options.pauseOnLostFocus && minecraft.screen == null; - } - private static void setVolumeMultiplier(float multiplier) { - // setting the volume to 0 stops all sounds (including music), which we want to - // avoid if possible. - // if the client would pause anyway, we don't need to do anything because that - // will already pause all sounds. - if (multiplier == 0 && willPauseSounds()) - return; + // Set the sound engine to a new volume multiplier, + // Or instead pause it when the multiplier is zero. - var baseVolume = minecraft.options.getSoundSourceVolume(SoundSource.MASTER); - minecraft.getSoundManager().updateSourceVolume( - SoundSource.MASTER, - baseVolume * multiplier - ); + // We can not set the sound engine to a zero volume + // Because it stops all actively playing sounds and + // Makes for a rather jarring experience when music + // Is stopped. Also fixes now-playing compatibility + + var manager = minecraft.getSoundManager(); + + if (multiplier == 0) { + manager.pause(); + } else { + manager.resume(); + + manager.updateSourceVolume( + SoundSource.MASTER, + minecraft.options.getSoundSourceVolume(SoundSource.MASTER) * multiplier + ); + } } private static boolean checkForRender(long timeSinceLastRender) { diff --git a/src/main/java/dynamic_fps/impl/mixin/SoundEngineMixin.java b/src/main/java/dynamic_fps/impl/mixin/SoundEngineMixin.java new file mode 100644 index 00000000..d99aa446 --- /dev/null +++ b/src/main/java/dynamic_fps/impl/mixin/SoundEngineMixin.java @@ -0,0 +1,25 @@ +package dynamic_fps.impl.mixin; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import dynamic_fps.impl.DynamicFPSMod; +import net.minecraft.client.sounds.SoundEngine; + +@Mixin(SoundEngine.class) +public class SoundEngineMixin { + /** + * Cancels playing sounds while we are overwriting the volume to be off. + * + * This is done in favor of actually setting the volume to zero, because it + * Allows pausing and resuming the sound engine without cancelling active sounds. + */ + @Inject(method = { "play", "playDelayed" }, at = @At("HEAD"), cancellable = true) + private void play(CallbackInfo callbackInfo) { + if (DynamicFPSMod.volumeMultiplier() == 0.0f) { + callbackInfo.cancel(); + } + } +} diff --git a/src/main/resources/dynamic_fps.mixins.json b/src/main/resources/dynamic_fps.mixins.json index b7b2616f..da9d1887 100644 --- a/src/main/resources/dynamic_fps.mixins.json +++ b/src/main/resources/dynamic_fps.mixins.json @@ -10,6 +10,7 @@ "LoadingOverlayMixin", "MinecraftMixin", "ScreenMixin", + "SoundEngineMixin", "StatsScreenMixin", "ToastComponentMixin", "WindowMixin",