From 803aaba20497e938f2263ff5823db08f2a9db9d1 Mon Sep 17 00:00:00 2001 From: Phoenix-Starlight <64714532+Phoenix-Starlight@users.noreply.github.com> Date: Sat, 7 Oct 2023 15:41:52 -0700 Subject: [PATCH] Dynamic sound unloading (#234) --- .../SoundBufferLibraryMixin.java | 44 +++++++++++++++++++ .../dynamicresources/DynamicSoundHelpers.java | 8 ++++ .../assets/modernfix/lang/en_us.json | 1 + 3 files changed, 53 insertions(+) create mode 100644 common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/dynamic_sounds/SoundBufferLibraryMixin.java create mode 100644 common/src/main/java/org/embeddedt/modernfix/dynamicresources/DynamicSoundHelpers.java 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 00000000..695065bc --- /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 00000000..fba50c80 --- /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 ec27bf0f..98bc5ba1 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.",