From eb30ab145ae6bff73b04eea4432c01dab67c1d6d Mon Sep 17 00:00:00 2001 From: malte0811 Date: Sun, 4 Feb 2024 18:00:39 +0100 Subject: [PATCH] Fix earmuff behavior for long-running sounds Previously the earmuffs would only affect sounds when they started, i.e. a sound started before putting on earmuffs would never get attenuated while a sound started while wearing earmuffs would be attenuated forever. --- .../client/ClientEventHandler.java | 30 ----- .../client/EarmuffHandler.java | 95 +++++++++++++++ .../common/config/IEClientConfig.java | 2 + .../common/util/sound/IEMuffledSound.java | 109 ------------------ .../util/sound/IEMuffledTickableSound.java | 34 ------ .../coremods/client/SoundEngineMixin.java | 35 ++++++ .../immersiveengineering.mixins.json | 3 +- 7 files changed, 134 insertions(+), 174 deletions(-) create mode 100644 src/main/java/blusunrize/immersiveengineering/client/EarmuffHandler.java delete mode 100644 src/main/java/blusunrize/immersiveengineering/common/util/sound/IEMuffledSound.java delete mode 100644 src/main/java/blusunrize/immersiveengineering/common/util/sound/IEMuffledTickableSound.java create mode 100644 src/main/java/blusunrize/immersiveengineering/mixin/coremods/client/SoundEngineMixin.java diff --git a/src/main/java/blusunrize/immersiveengineering/client/ClientEventHandler.java b/src/main/java/blusunrize/immersiveengineering/client/ClientEventHandler.java index 3f85358792..ecf2d93f5b 100644 --- a/src/main/java/blusunrize/immersiveengineering/client/ClientEventHandler.java +++ b/src/main/java/blusunrize/immersiveengineering/client/ClientEventHandler.java @@ -47,8 +47,6 @@ import blusunrize.immersiveengineering.common.register.IEPotions; import blusunrize.immersiveengineering.common.util.ItemNBTHelper; import blusunrize.immersiveengineering.common.util.Utils; -import blusunrize.immersiveengineering.common.util.sound.IEMuffledSound; -import blusunrize.immersiveengineering.common.util.sound.IEMuffledTickableSound; import com.google.common.collect.ImmutableList; import com.mojang.blaze3d.platform.Lighting; import com.mojang.blaze3d.systems.RenderSystem; @@ -65,7 +63,6 @@ import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.entity.LivingEntityRenderer; import net.minecraft.client.resources.language.I18n; -import net.minecraft.client.resources.sounds.TickableSoundInstance; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.core.Direction.Axis; @@ -98,7 +95,6 @@ import net.neoforged.neoforge.capabilities.Capabilities.EnergyStorage; import net.neoforged.neoforge.client.event.*; import net.neoforged.neoforge.client.event.InputEvent.MouseScrollingEvent; -import net.neoforged.neoforge.client.event.sound.PlaySoundEvent; import net.neoforged.neoforge.client.gui.overlay.ExtendedGui; import net.neoforged.neoforge.client.gui.overlay.VanillaGuiOverlay; import net.neoforged.neoforge.energy.IEnergyStorage; @@ -263,32 +259,6 @@ public void onItemTooltip(ItemTooltipEvent event) ))); } - @SubscribeEvent - public void onPlaySound(PlaySoundEvent event) - { - if(event.getSound()==null) - return; - else - event.getSound().getSource(); - if(!EarmuffsItem.affectedSoundCategories.contains(event.getSound().getSource().getName())) - return; - if(ClientUtils.mc().player!=null) - { - ItemStack earmuffs = EarmuffsItem.EARMUFF_GETTERS.getFrom(ClientUtils.mc().player); - if(!earmuffs.isEmpty()&& - !ItemNBTHelper.getBoolean(earmuffs, "IE:Earmuffs:Cat_"+event.getSound().getSource().getName())) - { - for(String blacklist : IEClientConfig.earDefenders_SoundBlacklist.get()) - if(blacklist!=null&&blacklist.equalsIgnoreCase(event.getSound().getLocation().toString())) - return; - if(event.getSound() instanceof TickableSoundInstance) - event.setSound(new IEMuffledTickableSound((TickableSoundInstance)event.getSound(), EarmuffsItem.getVolumeMod(earmuffs))); - else - event.setSound(new IEMuffledSound(event.getSound(), EarmuffsItem.getVolumeMod(earmuffs))); - } - } - } - @SubscribeEvent public void onRenderItemFrame(RenderItemInFrameEvent event) { diff --git a/src/main/java/blusunrize/immersiveengineering/client/EarmuffHandler.java b/src/main/java/blusunrize/immersiveengineering/client/EarmuffHandler.java new file mode 100644 index 0000000000..af76b9b4b7 --- /dev/null +++ b/src/main/java/blusunrize/immersiveengineering/client/EarmuffHandler.java @@ -0,0 +1,95 @@ +/* + * BluSunrize + * Copyright (c) 2024 + * + * This code is licensed under "Blu's License of Common Sense" + * Details can be found in the license file in the root folder of this project + */ + +package blusunrize.immersiveengineering.client; + +import blusunrize.immersiveengineering.api.Lib; +import blusunrize.immersiveengineering.common.config.IEClientConfig; +import blusunrize.immersiveengineering.common.items.EarmuffsItem; +import blusunrize.immersiveengineering.common.util.ItemNBTHelper; +import net.minecraft.client.Minecraft; +import net.minecraft.client.resources.sounds.SoundInstance; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.sounds.SoundSource; +import net.minecraft.world.item.ItemStack; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.Mod.EventBusSubscriber; +import net.neoforged.fml.common.Mod.EventBusSubscriber.Bus; +import net.neoforged.neoforge.event.TickEvent.ClientTickEvent; +import net.neoforged.neoforge.event.TickEvent.Phase; + +import java.util.EnumMap; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; + +@EventBusSubscriber(value = Dist.CLIENT, modid = Lib.MODID, bus = Bus.FORGE) +public class EarmuffHandler +{ + private static final Map LAST_MULTIPLIERS = makeDefaultMultipliers(); + private static Set IGNORED_SOUNDS = Set.of(); + + /** + * Only the volume multiplier for ticking sounds is updated tick-by-tick. For non-ticking sounds (e.g. records) we + * need to force the volume update when necessary. + */ + @SubscribeEvent + public static void updateEarmuffMultipliers(ClientTickEvent ev) + { + if(ev.phase!=Phase.START||ClientUtils.mc().player==null) + return; + Map newMultipliers = makeDefaultMultipliers(); + ItemStack earmuffs = EarmuffsItem.EARMUFF_GETTERS.getFrom(ClientUtils.mc().player); + if(!earmuffs.isEmpty()) + for(SoundSource source : SoundSource.values()) + if(EarmuffsItem.affectedSoundCategories.contains(source.getName())) + if(!ItemNBTHelper.getBoolean(earmuffs, "IE:Earmuffs:Cat_"+source.getName())) + { + // The max call is just a last safeguard against overly high attenuation (see documentation on + // EarmuffsItem.MIN_MULTIPLIER). The workbench config UI should limit the attenuation by itself. + final float newMultiplier = Math.max( + EarmuffsItem.MIN_MULTIPLIER, EarmuffsItem.getVolumeMod(earmuffs) + ); + newMultipliers.put(source, newMultiplier); + } + for(SoundSource source : SoundSource.values()) + if(LAST_MULTIPLIERS.get(source).floatValue()!=newMultipliers.get(source)) + { + LAST_MULTIPLIERS.put(source, newMultipliers.get(source)); + Minecraft.getInstance().getSoundManager().updateSourceVolume( + source, Minecraft.getInstance().options.getSoundSourceVolume(source) + ); + } + } + + public static float getVolumeMultiplier(SoundInstance sound) + { + if(IGNORED_SOUNDS.contains(sound.getLocation())) + return 1; + else + return LAST_MULTIPLIERS.get(sound.getSource()); + } + + public static void onConfigUpdate() + { + IGNORED_SOUNDS = IEClientConfig.earDefenders_SoundBlacklist.get().stream() + .map(ResourceLocation::tryParse) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + } + + private static Map makeDefaultMultipliers() + { + Map result = new EnumMap<>(SoundSource.class); + for(SoundSource type : SoundSource.values()) + result.put(type, 1f); + return result; + } +} diff --git a/src/main/java/blusunrize/immersiveengineering/common/config/IEClientConfig.java b/src/main/java/blusunrize/immersiveengineering/common/config/IEClientConfig.java index 04542b515f..10738bd1e7 100644 --- a/src/main/java/blusunrize/immersiveengineering/common/config/IEClientConfig.java +++ b/src/main/java/blusunrize/immersiveengineering/common/config/IEClientConfig.java @@ -12,6 +12,7 @@ import blusunrize.immersiveengineering.ImmersiveEngineering; import blusunrize.immersiveengineering.api.Lib; import blusunrize.immersiveengineering.api.fluid.FluidUtils; +import blusunrize.immersiveengineering.client.EarmuffHandler; import blusunrize.immersiveengineering.common.wires.IEWireTypes.IEWireType; import com.google.common.collect.ImmutableList; import net.neoforged.api.distmarker.Dist; @@ -122,6 +123,7 @@ public static void onConfigChange(ModConfigEvent ev) ImmersiveEngineering.proxy.resetManual(); } FluidUtils.enableFractionDisplay = fractionDisplay.get(); + EarmuffHandler.onConfigUpdate(); } } } diff --git a/src/main/java/blusunrize/immersiveengineering/common/util/sound/IEMuffledSound.java b/src/main/java/blusunrize/immersiveengineering/common/util/sound/IEMuffledSound.java deleted file mode 100644 index 38aa2399de..0000000000 --- a/src/main/java/blusunrize/immersiveengineering/common/util/sound/IEMuffledSound.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * BluSunrize - * Copyright (c) 2017 - * - * This code is licensed under "Blu's License of Common Sense" - * Details can be found in the license file in the root folder of this project - */ - -package blusunrize.immersiveengineering.common.util.sound; - -import net.minecraft.client.resources.sounds.Sound; -import net.minecraft.client.resources.sounds.SoundInstance; -import net.minecraft.client.sounds.SoundManager; -import net.minecraft.client.sounds.WeighedSoundEvents; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.sounds.SoundSource; - -import javax.annotation.Nullable; - -public class IEMuffledSound implements SoundInstance -{ - SoundInstance originalSound; - float volumeMod; - - public IEMuffledSound(SoundInstance originalSound, float volumeMod) - { - this.originalSound = originalSound; - this.volumeMod = volumeMod; - } - - @Override - public ResourceLocation getLocation() - { - return originalSound.getLocation(); - } - - @Nullable - @Override - public WeighedSoundEvents resolve(SoundManager handler) - { - return originalSound.resolve(handler); - } - - @Override - public Sound getSound() - { - return originalSound.getSound(); - } - - @Override - public SoundSource getSource() - { - return originalSound.getSource(); - } - - @Override - public boolean isLooping() - { - return originalSound.isLooping(); - } - - @Override - public boolean isRelative() - { - return originalSound.isRelative(); - } - - @Override - public int getDelay() - { - return originalSound.getDelay(); - } - - @Override - public float getVolume() - { - return originalSound.getVolume()*volumeMod; - } - - @Override - public float getPitch() - { - return originalSound.getPitch(); - } - - @Override - public double getX() - { - return originalSound.getX(); - } - - @Override - public double getY() - { - return originalSound.getY(); - } - - @Override - public double getZ() - { - return originalSound.getZ(); - } - - @Override - public Attenuation getAttenuation() - { - return originalSound.getAttenuation(); - } -} \ No newline at end of file diff --git a/src/main/java/blusunrize/immersiveengineering/common/util/sound/IEMuffledTickableSound.java b/src/main/java/blusunrize/immersiveengineering/common/util/sound/IEMuffledTickableSound.java deleted file mode 100644 index fa1f33d27c..0000000000 --- a/src/main/java/blusunrize/immersiveengineering/common/util/sound/IEMuffledTickableSound.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * BluSunrize - * Copyright (c) 2017 - * - * This code is licensed under "Blu's License of Common Sense" - * Details can be found in the license file in the root folder of this project - */ - -package blusunrize.immersiveengineering.common.util.sound; - -import net.minecraft.client.resources.sounds.TickableSoundInstance; - -public class IEMuffledTickableSound extends IEMuffledSound implements TickableSoundInstance -{ - final TickableSoundInstance originalSoundTickable; - - public IEMuffledTickableSound(TickableSoundInstance originalSound, float volumeMod) - { - super(originalSound, volumeMod); - originalSoundTickable = originalSound; - } - - @Override - public boolean isStopped() - { - return originalSoundTickable.isStopped(); - } - - @Override - public void tick() - { - originalSoundTickable.tick(); - } -} \ No newline at end of file diff --git a/src/main/java/blusunrize/immersiveengineering/mixin/coremods/client/SoundEngineMixin.java b/src/main/java/blusunrize/immersiveengineering/mixin/coremods/client/SoundEngineMixin.java new file mode 100644 index 0000000000..851bf4156a --- /dev/null +++ b/src/main/java/blusunrize/immersiveengineering/mixin/coremods/client/SoundEngineMixin.java @@ -0,0 +1,35 @@ +/* + * BluSunrize + * Copyright (c) 2024 + * + * This code is licensed under "Blu's License of Common Sense" + * Details can be found in the license file in the root folder of this project + */ + +package blusunrize.immersiveengineering.mixin.coremods.client; + +import blusunrize.immersiveengineering.client.EarmuffHandler; +import com.llamalad7.mixinextras.injector.ModifyExpressionValue; +import com.llamalad7.mixinextras.injector.ModifyReturnValue; +import net.minecraft.client.resources.sounds.SoundInstance; +import net.minecraft.client.sounds.SoundEngine; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; + +@Mixin(SoundEngine.class) +public class SoundEngineMixin +{ + @ModifyExpressionValue( + method = "play", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/sounds/SoundEngine;calculateVolume(FLnet/minecraft/sounds/SoundSource;)F") + ) + public float adjustVolumeAtStart(float original, SoundInstance sound) + { + return original*EarmuffHandler.getVolumeMultiplier(sound); + } + + @ModifyReturnValue(method = "calculateVolume(Lnet/minecraft/client/resources/sounds/SoundInstance;)F", at = @At("TAIL")) + public float adjustVolumeForEarmuffs(float original, SoundInstance sound) + { + return original*EarmuffHandler.getVolumeMultiplier(sound); + } +} diff --git a/src/main/resources/immersiveengineering.mixins.json b/src/main/resources/immersiveengineering.mixins.json index 6cec564679..90fd29085d 100644 --- a/src/main/resources/immersiveengineering.mixins.json +++ b/src/main/resources/immersiveengineering.mixins.json @@ -45,7 +45,8 @@ "accessors.client.WorldRendererAccess", "coremods.client.BipedModelMixin", "coremods.client.LevelRendererMixin", - "coremods.client.RebuildTaskMixin" + "coremods.client.RebuildTaskMixin", + "coremods.client.SoundEngineMixin" ], "injectors": { "defaultRequire": 1