diff --git a/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/dynamic_sounds/SoundBufferLibraryMixin.java b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/dynamic_sounds/SoundBufferLibraryMixin.java new file mode 100644 index 000000000..695065bcb --- /dev/null +++ b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/dynamic_sounds/SoundBufferLibraryMixin.java @@ -0,0 +1,44 @@ +package org.embeddedt.modernfix.common.mixin.perf.dynamic_sounds; + +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.RemovalNotification; +import com.mojang.blaze3d.audio.SoundBuffer; +import net.minecraft.client.sounds.SoundBufferLibrary; +import net.minecraft.resources.ResourceLocation; +import org.embeddedt.modernfix.annotation.ClientOnlyMixin; +import org.embeddedt.modernfix.dynamicresources.DynamicSoundHelpers; +import org.embeddedt.modernfix.ModernFix; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Mutable; +import org.spongepowered.asm.mixin.Shadow; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; +import java.util.Map; + +@Mixin(SoundBufferLibrary.class) +@ClientOnlyMixin +public abstract class SoundBufferLibraryMixin { + + private static final boolean debugDynamicSoundLoading = Boolean.getBoolean("modernfix.debugDynamicSoundLoading"); + + @Shadow @Final @Mutable + private Map> cache = + CacheBuilder.newBuilder() + .expireAfterAccess(DynamicSoundHelpers.MAX_SOUND_LIFETIME_SECS, TimeUnit.SECONDS) + // Excessive use of type hinting due to it assuming Object as the broadest correct type + .>removalListener(this::onSoundRemoval) + .>build() + .asMap(); + + private > void onSoundRemoval(RemovalNotification notification) { + notification.getValue().thenAccept(SoundBuffer::discardAlBuffer); + if(debugDynamicSoundLoading) { + K k = notification.getKey(); + if(k == null) + return; + ModernFix.LOGGER.warn("Evicted sound {}", k); + } + } +} diff --git a/common/src/main/java/org/embeddedt/modernfix/dynamicresources/DynamicSoundHelpers.java b/common/src/main/java/org/embeddedt/modernfix/dynamicresources/DynamicSoundHelpers.java new file mode 100644 index 000000000..fba50c802 --- /dev/null +++ b/common/src/main/java/org/embeddedt/modernfix/dynamicresources/DynamicSoundHelpers.java @@ -0,0 +1,8 @@ +package org.embeddedt.modernfix.dynamicresources; + +public class DynamicSoundHelpers { + /** + * The duration until a sound is eligible for eviction if unused. + */ + public static final int MAX_SOUND_LIFETIME_SECS = 120; +} diff --git a/common/src/main/resources/assets/modernfix/lang/en_us.json b/common/src/main/resources/assets/modernfix/lang/en_us.json index ec27bf0fb..98bc5ba1f 100644 --- a/common/src/main/resources/assets/modernfix/lang/en_us.json +++ b/common/src/main/resources/assets/modernfix/lang/en_us.json @@ -42,6 +42,7 @@ "modernfix.option.mixin.perf.deduplicate_location": "All versions, but disabled by default due to load time impact. Deduplicates resource location namespaces and paths. This saves RAM but also increases the cost of constructing a new `ResourceLocation` by quite a bit.", "modernfix.option.mixin.perf.dynamic_dfu": "All versions. Modifies DFU initialization to happen the first time something needs to be upgraded. This sounds similar to LazyDFU but is distinctly implemented, as it avoids loading *any* DFU classes/data structures, while LazyDFU only disables rule optimization. Essentially, this option is a safer version of DataFixerSlayer as it will still load DFU when needed.\n\nYou should typically continue to use LazyDFU even with this option enabled, as otherwise DFU rule optimization will cause lag.", "modernfix.option.mixin.perf.dynamic_resources": "All versions. See https://github.com/embeddedt/ModernFix/wiki/Dynamic-Resources-FAQ.", + "modernfix.option.mixin.perf.dynamic_sounds": "All versions. Allows the game to unload sounds, instead of sounds indefinitely persisting after being loaded.", "modernfix.option.mixin.perf.dynamic_structure_manager": "All versions. Allows the game to unload structure files after generation concludes instead of keeping them loaded forever.", "modernfix.option.mixin.perf.fast_registry_validation": "All versions. Forge needlessly looks up a method via reflection every single time a registry is validated. This patch simply caches the returned value since it will be the same every time.", "modernfix.option.mixin.perf.faster_font_loading": "All versions. Optimizes the font renderer to load fonts faster, speeding up resource reload.",