diff --git a/src/main/java/org/embeddedt/modernfix/ModernFix.java b/src/main/java/org/embeddedt/modernfix/ModernFix.java index bf73fc45..f1106e64 100644 --- a/src/main/java/org/embeddedt/modernfix/ModernFix.java +++ b/src/main/java/org/embeddedt/modernfix/ModernFix.java @@ -18,6 +18,7 @@ import org.apache.logging.log4j.Logger; import org.embeddedt.modernfix.core.config.ModernFixConfig; import org.embeddedt.modernfix.entity.EntityDataIDSyncHandler; import org.embeddedt.modernfix.packet.PacketHandler; +import org.embeddedt.modernfix.registry.ObjectHolderClearer; import org.embeddedt.modernfix.structure.AsyncLocator; import org.embeddedt.modernfix.util.KubeUtil; @@ -91,7 +92,7 @@ public class ModernFix { ModLoader.get().addWarning(new ModLoadingWarning(ModLoadingContext.get().getActiveContainer().getModInfo(), ModLoadingStage.COMMON_SETUP, "modernfix.no_lazydfu")); }); } - + ObjectHolderClearer.clearThrowables(); } @SubscribeEvent diff --git a/src/main/java/org/embeddedt/modernfix/registry/ObjectHolderClearer.java b/src/main/java/org/embeddedt/modernfix/registry/ObjectHolderClearer.java new file mode 100644 index 00000000..6ca0f948 --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/registry/ObjectHolderClearer.java @@ -0,0 +1,47 @@ +package org.embeddedt.modernfix.registry; + +import net.minecraft.resources.ResourceLocation; +import net.minecraftforge.fml.common.ObfuscationReflectionHelper; +import net.minecraftforge.registries.ObjectHolderRegistry; +import org.embeddedt.modernfix.ModernFix; + +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.List; +import java.util.Set; +import java.util.function.Consumer; +import java.util.function.Predicate; + +public class ObjectHolderClearer { + /** + * Many of the built-in Forge holders needlessly hold on to an exception. + */ + public static void clearThrowables() { + Set>> holders = ObfuscationReflectionHelper.getPrivateValue(ObjectHolderRegistry.class, null, "objectHolders"); + if(holders != null) { + int numCleared = 0; + HashMap, Field> throwableField = new HashMap<>(); + Throwable singletonThrowable = new Throwable("[This stacktrace was cleared to save memory]"); + try { + for(Consumer> holder : holders) { + Field target = throwableField.computeIfAbsent(holder.getClass(), clz -> { + Field[] clzFields = clz.getDeclaredFields(); + for(Field f : clzFields) { + if(Throwable.class.isAssignableFrom(f.getType())) { + f.setAccessible(true); + return f; + } + } + return null; + }); + if(target != null) { + target.set(holder, singletonThrowable); + numCleared++; + } + } + } catch(RuntimeException | ReflectiveOperationException | NoClassDefFoundError ignored) { + } + ModernFix.LOGGER.debug("Cleared " + numCleared + " object holder stacktrace references"); + } + } +}