diff --git a/src/main/java/org/embeddedt/modernfix/common/mixin/perf/object_holder_cleanup/GameDataMixin.java b/src/main/java/org/embeddedt/modernfix/common/mixin/perf/object_holder_cleanup/GameDataMixin.java new file mode 100644 index 00000000..aa9207a1 --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/common/mixin/perf/object_holder_cleanup/GameDataMixin.java @@ -0,0 +1,16 @@ +package org.embeddedt.modernfix.common.mixin.perf.object_holder_cleanup; + +import net.minecraftforge.registries.GameData; +import org.embeddedt.modernfix.forge.registry.ObjectHolderClearer; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(value = GameData.class, remap = false) +public class GameDataMixin { + @Inject(method = "postRegisterEvents", at = @At("RETURN")) + private static void clearRedundantHolders(CallbackInfo ci) { + ObjectHolderClearer.removeRedundantHolders(); + } +} diff --git a/src/main/java/org/embeddedt/modernfix/forge/init/ModernFixForge.java b/src/main/java/org/embeddedt/modernfix/forge/init/ModernFixForge.java index a95cbdd2..365c0757 100644 --- a/src/main/java/org/embeddedt/modernfix/forge/init/ModernFixForge.java +++ b/src/main/java/org/embeddedt/modernfix/forge/init/ModernFixForge.java @@ -125,6 +125,7 @@ public class ModernFixForge { }); } ObjectHolderClearer.clearThrowables(); + event.enqueueWork(ObjectHolderClearer::removeRedundantHolders); } @SubscribeEvent(priority = EventPriority.LOWEST) public void onServerDead(ServerStoppedEvent event) { diff --git a/src/main/java/org/embeddedt/modernfix/forge/registry/ObjectHolderClearer.java b/src/main/java/org/embeddedt/modernfix/forge/registry/ObjectHolderClearer.java index 4f2a9059..c8c4ac24 100644 --- a/src/main/java/org/embeddedt/modernfix/forge/registry/ObjectHolderClearer.java +++ b/src/main/java/org/embeddedt/modernfix/forge/registry/ObjectHolderClearer.java @@ -2,11 +2,14 @@ package org.embeddedt.modernfix.forge.registry; import net.minecraft.resources.ResourceLocation; import net.minecraftforge.fml.util.ObfuscationReflectionHelper; +import net.minecraftforge.registries.ForgeRegistry; import net.minecraftforge.registries.ObjectHolderRegistry; import org.embeddedt.modernfix.ModernFix; import java.lang.reflect.Field; +import java.lang.reflect.Method; import java.util.HashMap; +import java.util.Map; import java.util.Set; import java.util.function.Consumer; import java.util.function.Predicate; @@ -43,4 +46,47 @@ public class ObjectHolderClearer { ModernFix.LOGGER.debug("Cleared " + numCleared + " object holder stacktrace references"); } } + + public static void removeRedundantHolders() { + try { + Field holdersField = ObjectHolderRegistry.class.getDeclaredField("objectHolders"); + holdersField.setAccessible(true); + Set>> holders = (Set>>)holdersField.get(null); + + Class refClass = Class.forName("net.minecraftforge.registries.ObjectHolderRef"); + Field registryField = refClass.getDeclaredField("registry"); + registryField.setAccessible(true); + Field injectedObjectField = refClass.getDeclaredField("injectedObject"); + injectedObjectField.setAccessible(true); + + Method getOverrideOwnersMethod = ForgeRegistry.class.getDeclaredMethod("getOverrideOwners"); + getOverrideOwnersMethod.setAccessible(true); + + HashMap, Map> overrideCache = new HashMap<>(); + int removed = 0; + + var it = holders.iterator(); + while (it.hasNext()) { + var holder = it.next(); + if (!refClass.isInstance(holder)) + continue; + ForgeRegistry registry = (ForgeRegistry)registryField.get(holder); + ResourceLocation injectedObject = (ResourceLocation)injectedObjectField.get(holder); + Map overrides = overrideCache.computeIfAbsent(registry, r -> { + try { + return (Map)getOverrideOwnersMethod.invoke(r); + } catch (ReflectiveOperationException e) { + throw new RuntimeException(e); + } + }); + if (!overrides.containsKey(injectedObject)) { + it.remove(); + removed++; + } + } + ModernFix.LOGGER.debug("Removed {} redundant object holders", removed); + } catch (Exception e) { + ModernFix.LOGGER.error("Failed to remove object holders", e); + } + } }