diff --git a/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/encoder_cache_leak/DataComponentsAccessor.java b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/encoder_cache_leak/DataComponentsAccessor.java new file mode 100644 index 00000000..d1c1b8bd --- /dev/null +++ b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/encoder_cache_leak/DataComponentsAccessor.java @@ -0,0 +1,14 @@ +package org.embeddedt.modernfix.common.mixin.perf.encoder_cache_leak; + +import net.minecraft.core.component.DataComponents; +import net.minecraft.util.EncoderCache; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(DataComponents.class) +public interface DataComponentsAccessor { + @Accessor("ENCODER_CACHE") + static EncoderCache mfix$getCache() { + throw new AssertionError(); + } +} diff --git a/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/encoder_cache_leak/EncoderCacheAccessor.java b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/encoder_cache_leak/EncoderCacheAccessor.java new file mode 100644 index 00000000..58cec350 --- /dev/null +++ b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/encoder_cache_leak/EncoderCacheAccessor.java @@ -0,0 +1,12 @@ +package org.embeddedt.modernfix.common.mixin.perf.encoder_cache_leak; + +import com.google.common.cache.LoadingCache; +import net.minecraft.util.EncoderCache; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(EncoderCache.class) +public interface EncoderCacheAccessor { + @Accessor("cache") + LoadingCache mfix$getCache(); +} diff --git a/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/encoder_cache_leak/ReloadableServerResourcesMixin.java b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/encoder_cache_leak/ReloadableServerResourcesMixin.java new file mode 100644 index 00000000..f880b67d --- /dev/null +++ b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/encoder_cache_leak/ReloadableServerResourcesMixin.java @@ -0,0 +1,27 @@ +package org.embeddedt.modernfix.common.mixin.perf.encoder_cache_leak; + +import com.llamalad7.mixinextras.injector.ModifyReturnValue; +import net.minecraft.core.component.DataComponents; +import net.minecraft.server.ReloadableServerResources; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; + +import java.util.concurrent.CompletableFuture; + +@Mixin(ReloadableServerResources.class) +public class ReloadableServerResourcesMixin { + /** + * @author embeddedt + * @reason Some mods (e.g. KubeJS) may provide a custom DynamicOps instance during resource reload. This instance + * can end up being strongly retained by an EncoderCache.Key entry even after the reload finishes. The simplest + * fix is to invalidate all entries of the encoder cache after a server-side resource reload, which should not break + * mods, as the cache is not guaranteed to persist entries for any length of time due to using both a maximum size + * & soft values. + */ + @ModifyReturnValue(method = "loadResources", at = @At("RETURN")) + private static CompletableFuture resetEncoderCache(CompletableFuture future) { + return future.whenComplete((r, t) -> { + ((EncoderCacheAccessor)DataComponentsAccessor.mfix$getCache()).mfix$getCache().invalidateAll(); + }); + } +}