diff --git a/src/main/java/org/embeddedt/modernfix/ModernFix.java b/src/main/java/org/embeddedt/modernfix/ModernFix.java index fb3095ba..07b69036 100644 --- a/src/main/java/org/embeddedt/modernfix/ModernFix.java +++ b/src/main/java/org/embeddedt/modernfix/ModernFix.java @@ -17,6 +17,7 @@ import net.minecraftforge.fml.network.FMLNetworkConstants; import org.apache.commons.lang3.tuple.Pair; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.embeddedt.modernfix.classloading.ModFileScanDataDeduplicator; import org.embeddedt.modernfix.core.config.ModernFixConfig; import org.embeddedt.modernfix.entity.EntityDataIDSyncHandler; import org.embeddedt.modernfix.packet.PacketHandler; @@ -79,6 +80,7 @@ public class ModernFix { MinecraftForge.EVENT_BUS.register(KubeUtil.class); MinecraftForge.EVENT_BUS.register(EntityDataIDSyncHandler.class); PacketHandler.register(); + ModFileScanDataDeduplicator.deduplicate(); } private static boolean dfuModPresent() { diff --git a/src/main/java/org/embeddedt/modernfix/classloading/ModFileScanDataDeduplicator.java b/src/main/java/org/embeddedt/modernfix/classloading/ModFileScanDataDeduplicator.java new file mode 100644 index 00000000..a2347963 --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/classloading/ModFileScanDataDeduplicator.java @@ -0,0 +1,86 @@ +package org.embeddedt.modernfix.classloading; + +import com.google.common.collect.Interner; +import com.google.common.collect.Interners; +import net.minecraftforge.fml.ModList; +import net.minecraftforge.fml.loading.moddiscovery.ModFile; +import net.minecraftforge.forgespi.language.ModFileScanData; +import org.objectweb.asm.Type; + +import java.lang.reflect.Field; +import java.util.Set; +import java.util.stream.Collectors; + +public class ModFileScanDataDeduplicator { + private final Interner typeInterner = Interners.newStrongInterner(); + + private static Field classClazzField, parentField, interfacesField, annotationClazzField, annotationTypeField; + private static final boolean reflectionSuccessful; + + static { + boolean success = false; + try { + classClazzField = ModFileScanData.ClassData.class.getDeclaredField("clazz"); + classClazzField.setAccessible(true); + parentField = ModFileScanData.ClassData.class.getDeclaredField("parent"); + parentField.setAccessible(true); + interfacesField = ModFileScanData.ClassData.class.getDeclaredField("interfaces"); + interfacesField.setAccessible(true); + annotationClazzField = ModFileScanData.AnnotationData.class.getDeclaredField("clazz"); + annotationClazzField.setAccessible(true); + annotationTypeField = ModFileScanData.AnnotationData.class.getDeclaredField("annotationType"); + annotationTypeField.setAccessible(true); + success = true; + } catch(ReflectiveOperationException | RuntimeException e) { + } + reflectionSuccessful = success; + } + + ModFileScanDataDeduplicator() { + } + + private void runDeduplication() { + ModList.get().forEachModFile(this::deduplicateFile); + } + + private void deduplicateFile(ModFile file) { + ModFileScanData data = file.getScanResult(); + if(data != null) { + data.getClasses().forEach(this::deduplicateClass); + data.getAnnotations().forEach(this::deduplicateAnnotation); + } + } + + private void deduplicateClass(ModFileScanData.ClassData data) { + try { + Type type = (Type)classClazzField.get(data); + type = typeInterner.intern(type); + classClazzField.set(data, type); + type = (Type)parentField.get(data); + type = typeInterner.intern(type); + parentField.set(data, type); + Set types = (Set)interfacesField.get(data); + types = types.stream().map(typeInterner::intern).collect(Collectors.toSet()); + interfacesField.set(data, types); + } catch(ReflectiveOperationException e) { + } + } + + private void deduplicateAnnotation(ModFileScanData.AnnotationData data) { + try { + Type type = (Type)annotationClazzField.get(data); + type = typeInterner.intern(type); + annotationClazzField.set(data, type); + type = (Type)annotationTypeField.get(data); + type = typeInterner.intern(type); + annotationTypeField.set(data, type); + } catch(ReflectiveOperationException e) { + } + } + + public static void deduplicate() { + if(!reflectionSuccessful) + return; + new ModFileScanDataDeduplicator().runDeduplication(); + } +}