From 201c2f3b51bc3d164a6265aac2963f51929a7135 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Tue, 18 Apr 2023 22:02:06 -0400 Subject: [PATCH 01/13] Add off-by-default option to disable the DFU maps for flattening --- .../core/config/ModernFixEarlyConfig.java | 1 + .../BlockStateDataMixin.java | 21 +++++++++++++ .../ChunkPalettedStorageFixMixin.java | 31 +++++++++++++++++++ src/main/resources/modernfix.mixins.json | 2 ++ 4 files changed, 55 insertions(+) create mode 100644 src/main/java/org/embeddedt/modernfix/mixin/perf/dedup_blockstate_flattening_map/BlockStateDataMixin.java create mode 100644 src/main/java/org/embeddedt/modernfix/mixin/perf/dedup_blockstate_flattening_map/ChunkPalettedStorageFixMixin.java diff --git a/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java b/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java index 99654b7d..1cb8f773 100644 --- a/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java +++ b/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java @@ -41,6 +41,7 @@ public class ModernFixEarlyConfig { /* Use a simpler ArrayMap if FerriteCore is using the map intelligently anyway */ this.addMixinRule("perf.state_definition_construct", modPresent("ferritecore")); this.addMixinRule("perf.cache_strongholds", true); + this.addMixinRule("perf.dedup_blockstate_flattening_map", false); this.addMixinRule("perf.cache_upgraded_structures", true); this.addMixinRule("perf.biome_zoomer", true); this.addMixinRule("perf.compress_blockstate", false); diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/dedup_blockstate_flattening_map/BlockStateDataMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/dedup_blockstate_flattening_map/BlockStateDataMixin.java new file mode 100644 index 00000000..63da3acc --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/dedup_blockstate_flattening_map/BlockStateDataMixin.java @@ -0,0 +1,21 @@ +package org.embeddedt.modernfix.mixin.perf.dedup_blockstate_flattening_map; + +import net.minecraft.util.datafix.fixes.BlockStateData; +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; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(BlockStateData.class) +public class BlockStateDataMixin { + @Inject(method = {"register", "finalizeMaps"}, at = @At("HEAD"), cancellable = true) + private static void noFlattening(CallbackInfo ci) { + ci.cancel(); + } + + @Inject(method = {"upgradeBlockStateTag", "upgradeBlock(I)Ljava/lang/String;", "upgradeBlock(Ljava/lang/String;)Ljava/lang/String;", "getTag"}, at = @At("HEAD"), require = 4) + private static void preventCorruption(CallbackInfoReturnable cir) { + throw new UnsupportedOperationException("Performing the Flattening is currently disabled in the ModernFix config."); + } +} diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/dedup_blockstate_flattening_map/ChunkPalettedStorageFixMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/dedup_blockstate_flattening_map/ChunkPalettedStorageFixMixin.java new file mode 100644 index 00000000..962a7fee --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/dedup_blockstate_flattening_map/ChunkPalettedStorageFixMixin.java @@ -0,0 +1,31 @@ +package org.embeddedt.modernfix.mixin.perf.dedup_blockstate_flattening_map; + +import com.mojang.serialization.Dynamic; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtOps; +import net.minecraft.util.datafix.fixes.ChunkPalettedStorageFix; +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.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import java.util.function.Consumer; + +@Mixin(ChunkPalettedStorageFix.class) +public class ChunkPalettedStorageFixMixin { + @Redirect(method = "", at = @At(value = "INVOKE", target = "Lcom/mojang/datafixers/DataFixUtils;make(Ljava/lang/Object;Ljava/util/function/Consumer;)Ljava/lang/Object;")) + private static Object skipMakingMap(Object o, Consumer consumer) { + return o; + } + + @Redirect(method = "", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/datafix/fixes/BlockStateData;getTag(I)Lcom/mojang/serialization/Dynamic;")) + private static Dynamic getFakeAirTag(int id) { + return new Dynamic<>(NbtOps.INSTANCE, new CompoundTag()); + } + + @Inject(method = "fix", at = @At("HEAD")) + private void skipFix(CallbackInfoReturnable> cir) { + throw new UnsupportedOperationException("No Flattening for you."); + } +} diff --git a/src/main/resources/modernfix.mixins.json b/src/main/resources/modernfix.mixins.json index 3615fb6b..38a48888 100644 --- a/src/main/resources/modernfix.mixins.json +++ b/src/main/resources/modernfix.mixins.json @@ -66,6 +66,8 @@ "perf.biome_zoomer.FuzzyOffsetBiomeZoomerMixin", "perf.compress_blockstate.BlockStateBaseMixin", "perf.compress_blockstate.BlockBehaviourMixin", + "perf.dedup_blockstate_flattening_map.BlockStateDataMixin", + "perf.dedup_blockstate_flattening_map.ChunkPalettedStorageFixMixin", "devenv.MinecraftServerMixin" ], "client": [ From e5028535e9e7f0a861b6ed0bab30e15cacd6b5be Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Tue, 18 Apr 2023 22:15:56 -0400 Subject: [PATCH 02/13] Clear mixin ClassInfo cache when load finishes --- .../org/embeddedt/modernfix/ModernFix.java | 9 +++++++ .../modernfix/util/ClassInfoManager.java | 24 +++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 src/main/java/org/embeddedt/modernfix/util/ClassInfoManager.java diff --git a/src/main/java/org/embeddedt/modernfix/ModernFix.java b/src/main/java/org/embeddedt/modernfix/ModernFix.java index f1106e64..05c48f8c 100644 --- a/src/main/java/org/embeddedt/modernfix/ModernFix.java +++ b/src/main/java/org/embeddedt/modernfix/ModernFix.java @@ -2,11 +2,13 @@ package org.embeddedt.modernfix; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.eventbus.api.EventPriority; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.*; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.config.ModConfig; import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; +import net.minecraftforge.fml.event.lifecycle.FMLLoadCompleteEvent; import net.minecraftforge.fml.event.server.FMLServerStartedEvent; import net.minecraftforge.fml.event.server.FMLServerStartingEvent; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; @@ -20,6 +22,7 @@ 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.ClassInfoManager; import org.embeddedt.modernfix.util.KubeUtil; import java.lang.management.ManagementFactory; @@ -68,6 +71,7 @@ public class ModernFix { // Register ourselves for server and other game events we are interested in MinecraftForge.EVENT_BUS.register(this); FMLJavaModLoadingContext.get().getModEventBus().addListener(this::commonSetup); + FMLJavaModLoadingContext.get().getModEventBus().addListener(this::onLoadComplete); DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> MinecraftForge.EVENT_BUS.register(new ModernFixClient())); ModLoadingContext.get().registerExtensionPoint(ExtensionPoint.DISPLAYTEST, () -> Pair.of(() -> FMLNetworkConstants.IGNORESERVERONLY, (a, b) -> true)); ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, ModernFixConfig.COMMON_CONFIG); @@ -102,4 +106,9 @@ public class ModernFix { ModernFix.LOGGER.warn("Dedicated server took " + gameStartTime + " seconds to load"); } } + + @SubscribeEvent(priority = EventPriority.LOWEST) + public void onLoadComplete(FMLLoadCompleteEvent event) { + ClassInfoManager.clear(); + } } diff --git a/src/main/java/org/embeddedt/modernfix/util/ClassInfoManager.java b/src/main/java/org/embeddedt/modernfix/util/ClassInfoManager.java new file mode 100644 index 00000000..3497c21d --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/util/ClassInfoManager.java @@ -0,0 +1,24 @@ +package org.embeddedt.modernfix.util; + +import org.spongepowered.asm.mixin.transformer.ClassInfo; + +import java.lang.reflect.Field; +import java.util.Iterator; +import java.util.Map; + +public class ClassInfoManager { + private static Map classInfoCache = null; + public static void clear() { + if(classInfoCache == null) { + try { + Field field = ClassInfo.class.getDeclaredField("cache"); + field.setAccessible(true); + classInfoCache = (Map)field.get(null); + } catch(ReflectiveOperationException | RuntimeException e) { + e.printStackTrace(); + return; + } + } + classInfoCache.entrySet().removeIf(entry -> !entry.getKey().equals("java/lang/Object")); + } +} From 74c3f0ff903c5bffe5fdb6a8d4fa37beb0e58e1a Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Tue, 18 Apr 2023 22:17:32 -0400 Subject: [PATCH 03/13] Also clear ClassInfo cache after server starts --- src/main/java/org/embeddedt/modernfix/ModernFix.java | 1 + .../java/org/embeddedt/modernfix/util/ClassInfoManager.java | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/embeddedt/modernfix/ModernFix.java b/src/main/java/org/embeddedt/modernfix/ModernFix.java index 05c48f8c..fb3095ba 100644 --- a/src/main/java/org/embeddedt/modernfix/ModernFix.java +++ b/src/main/java/org/embeddedt/modernfix/ModernFix.java @@ -105,6 +105,7 @@ public class ModernFix { float gameStartTime = ManagementFactory.getRuntimeMXBean().getUptime() / 1000f; ModernFix.LOGGER.warn("Dedicated server took " + gameStartTime + " seconds to load"); } + ClassInfoManager.clear(); } @SubscribeEvent(priority = EventPriority.LOWEST) diff --git a/src/main/java/org/embeddedt/modernfix/util/ClassInfoManager.java b/src/main/java/org/embeddedt/modernfix/util/ClassInfoManager.java index 3497c21d..9043c013 100644 --- a/src/main/java/org/embeddedt/modernfix/util/ClassInfoManager.java +++ b/src/main/java/org/embeddedt/modernfix/util/ClassInfoManager.java @@ -19,6 +19,10 @@ public class ClassInfoManager { return; } } - classInfoCache.entrySet().removeIf(entry -> !entry.getKey().equals("java/lang/Object")); + try { + classInfoCache.entrySet().removeIf(entry -> !entry.getKey().equals("java/lang/Object")); + } catch(RuntimeException e) { + e.printStackTrace(); + } } } From f27d94cf265189b19e40f8a93a42d3e82c442f62 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Tue, 18 Apr 2023 22:24:48 -0400 Subject: [PATCH 04/13] Disable class info clearing by default and only clear non-mixin entries --- .../modernfix/core/config/ModernFixEarlyConfig.java | 1 + .../java/org/embeddedt/modernfix/util/ClassInfoManager.java | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java b/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java index 1cb8f773..b92d790a 100644 --- a/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java +++ b/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java @@ -42,6 +42,7 @@ public class ModernFixEarlyConfig { this.addMixinRule("perf.state_definition_construct", modPresent("ferritecore")); this.addMixinRule("perf.cache_strongholds", true); this.addMixinRule("perf.dedup_blockstate_flattening_map", false); + this.addMixinRule("perf.clear_mixin_classinfo", false); this.addMixinRule("perf.cache_upgraded_structures", true); this.addMixinRule("perf.biome_zoomer", true); this.addMixinRule("perf.compress_blockstate", false); diff --git a/src/main/java/org/embeddedt/modernfix/util/ClassInfoManager.java b/src/main/java/org/embeddedt/modernfix/util/ClassInfoManager.java index 9043c013..34a6d53f 100644 --- a/src/main/java/org/embeddedt/modernfix/util/ClassInfoManager.java +++ b/src/main/java/org/embeddedt/modernfix/util/ClassInfoManager.java @@ -1,5 +1,6 @@ package org.embeddedt.modernfix.util; +import org.embeddedt.modernfix.core.ModernFixMixinPlugin; import org.spongepowered.asm.mixin.transformer.ClassInfo; import java.lang.reflect.Field; @@ -9,6 +10,8 @@ import java.util.Map; public class ClassInfoManager { private static Map classInfoCache = null; public static void clear() { + if(!ModernFixMixinPlugin.instance.isOptionEnabled("perf.clear_mixin_classinfo.ClassInfoManager")) + return; if(classInfoCache == null) { try { Field field = ClassInfo.class.getDeclaredField("cache"); @@ -20,7 +23,7 @@ public class ClassInfoManager { } } try { - classInfoCache.entrySet().removeIf(entry -> !entry.getKey().equals("java/lang/Object")); + classInfoCache.entrySet().removeIf(entry -> !entry.getKey().equals("java/lang/Object") && (entry.getValue() == null || !entry.getValue().isMixin())); } catch(RuntimeException e) { e.printStackTrace(); } From 856c3cbc117e8c270f26f0f6df84f9597df92f1c Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Wed, 19 Apr 2023 09:56:35 -0400 Subject: [PATCH 05/13] Deduplicate some ModFileScanData --- .../org/embeddedt/modernfix/ModernFix.java | 2 + .../ModFileScanDataDeduplicator.java | 86 +++++++++++++++++++ 2 files changed, 88 insertions(+) create mode 100644 src/main/java/org/embeddedt/modernfix/classloading/ModFileScanDataDeduplicator.java 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(); + } +} From a2d0984078aa69e45782ee123af73e57982d0b16 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Wed, 19 Apr 2023 16:09:40 -0400 Subject: [PATCH 06/13] Add ItemColors mixin as well Related: #59 --- .../mixin/safety/BlockColorsMixin.java | 4 ++-- .../mixin/safety/ItemColorsMixin.java | 23 +++++++++++++++++++ src/main/resources/modernfix.mixins.json | 1 + 3 files changed, 26 insertions(+), 2 deletions(-) create mode 100644 src/main/java/org/embeddedt/modernfix/mixin/safety/ItemColorsMixin.java diff --git a/src/main/java/org/embeddedt/modernfix/mixin/safety/BlockColorsMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/safety/BlockColorsMixin.java index fd5e407f..fb36013f 100644 --- a/src/main/java/org/embeddedt/modernfix/mixin/safety/BlockColorsMixin.java +++ b/src/main/java/org/embeddedt/modernfix/mixin/safety/BlockColorsMixin.java @@ -16,11 +16,11 @@ import java.util.concurrent.locks.ReentrantLock; public class BlockColorsMixin { private Lock mapLock = new ReentrantLock(); @Inject(method = "register", at = @At("HEAD")) - private void lockMapBeforeAccess(BlockColor pBlockColor, Block[] pBlocks, CallbackInfo ci) { + private void lockMapBeforeAccess(CallbackInfo ci) { mapLock.lock(); } @Inject(method = "register", at = @At("TAIL")) - private void unlockMap(BlockColor pBlockColor, Block[] pBlocks, CallbackInfo ci) { + private void unlockMap(CallbackInfo ci) { mapLock.unlock(); } } diff --git a/src/main/java/org/embeddedt/modernfix/mixin/safety/ItemColorsMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/safety/ItemColorsMixin.java new file mode 100644 index 00000000..628fb721 --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/mixin/safety/ItemColorsMixin.java @@ -0,0 +1,23 @@ +package org.embeddedt.modernfix.mixin.safety; + +import net.minecraft.client.color.item.ItemColors; +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; + +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +@Mixin(value = ItemColors.class, priority = 700) +public class ItemColorsMixin { + private Lock mapLock = new ReentrantLock(); + @Inject(method = "register", at = @At("HEAD")) + private void lockMapBeforeAccess(CallbackInfo ci) { + mapLock.lock(); + } + @Inject(method = "register", at = @At("TAIL")) + private void unlockMap(CallbackInfo ci) { + mapLock.unlock(); + } +} diff --git a/src/main/resources/modernfix.mixins.json b/src/main/resources/modernfix.mixins.json index 38a48888..979de7f3 100644 --- a/src/main/resources/modernfix.mixins.json +++ b/src/main/resources/modernfix.mixins.json @@ -98,6 +98,7 @@ "perf.async_jei.RecipeManagerInternalMixin", "perf.thread_priorities.IntegratedServerMixin", "safety.BlockColorsMixin", + "safety.ItemColorsMixin", "perf.flatten_model_predicates.AndConditionMixin", "perf.flatten_model_predicates.OrConditionMixin", "perf.flatten_model_predicates.PropertyValueConditionMixin", From 701def339fec9fd7a254eb4f3ac9f59627b50816 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Thu, 20 Apr 2023 19:20:15 -0400 Subject: [PATCH 07/13] Fix crash when null type references are interned --- .../classloading/ModFileScanDataDeduplicator.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/embeddedt/modernfix/classloading/ModFileScanDataDeduplicator.java b/src/main/java/org/embeddedt/modernfix/classloading/ModFileScanDataDeduplicator.java index a2347963..0604a4f1 100644 --- a/src/main/java/org/embeddedt/modernfix/classloading/ModFileScanDataDeduplicator.java +++ b/src/main/java/org/embeddedt/modernfix/classloading/ModFileScanDataDeduplicator.java @@ -9,11 +9,14 @@ import org.objectweb.asm.Type; import java.lang.reflect.Field; import java.util.Set; +import java.util.function.Function; import java.util.stream.Collectors; public class ModFileScanDataDeduplicator { private final Interner typeInterner = Interners.newStrongInterner(); + private final Function internerFn = type -> type != null ? typeInterner.intern(type) : null; + private static Field classClazzField, parentField, interfacesField, annotationClazzField, annotationTypeField; private static final boolean reflectionSuccessful; @@ -54,13 +57,13 @@ public class ModFileScanDataDeduplicator { private void deduplicateClass(ModFileScanData.ClassData data) { try { Type type = (Type)classClazzField.get(data); - type = typeInterner.intern(type); + type = internerFn.apply(type); classClazzField.set(data, type); type = (Type)parentField.get(data); - type = typeInterner.intern(type); + type = internerFn.apply(type); parentField.set(data, type); Set types = (Set)interfacesField.get(data); - types = types.stream().map(typeInterner::intern).collect(Collectors.toSet()); + types = types.stream().map(internerFn).collect(Collectors.toSet()); interfacesField.set(data, types); } catch(ReflectiveOperationException e) { } @@ -69,10 +72,10 @@ public class ModFileScanDataDeduplicator { private void deduplicateAnnotation(ModFileScanData.AnnotationData data) { try { Type type = (Type)annotationClazzField.get(data); - type = typeInterner.intern(type); + type = internerFn.apply(type); annotationClazzField.set(data, type); type = (Type)annotationTypeField.get(data); - type = typeInterner.intern(type); + type = internerFn.apply(type); annotationTypeField.set(data, type); } catch(ReflectiveOperationException e) { } From d10ff8a24e8743e052c338fc2a4a115161609a38 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Thu, 20 Apr 2023 19:55:41 -0400 Subject: [PATCH 08/13] Ensure cached resources are cleared when connecting to multiplayer --- .../mixin/perf/reuse_datapacks/MinecraftMixin.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/reuse_datapacks/MinecraftMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/reuse_datapacks/MinecraftMixin.java index 71c0f439..e1c5abec 100644 --- a/src/main/java/org/embeddedt/modernfix/mixin/perf/reuse_datapacks/MinecraftMixin.java +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/reuse_datapacks/MinecraftMixin.java @@ -12,8 +12,11 @@ import net.minecraft.world.level.DataPackConfig; import org.embeddedt.modernfix.ModernFix; import org.embeddedt.modernfix.duck.reuse_datapacks.ICachingResourceClient; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import java.util.Collection; import java.util.List; @@ -21,7 +24,9 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; @Mixin(Minecraft.class) -public class MinecraftMixin implements ICachingResourceClient { +public abstract class MinecraftMixin implements ICachingResourceClient { + @Shadow public abstract boolean isLocalServer(); + private ServerResources cachedResources; private List cachedDataPackConfig; @@ -67,4 +72,10 @@ public class MinecraftMixin implements ICachingResourceClient { public void setCachedDataPackConfig(Collection c) { cachedDataPackConfig = ImmutableList.copyOf(c); } + + @Inject(method = "setLevel", at = @At("HEAD")) + private void clearResourcesIfNotLocal(CallbackInfo ci) { + if(!this.isLocalServer()) + cachedResources = null; + } } From 21dcf9d3df47e8f4d12b4b3d566c3b1e24496d4f Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Thu, 20 Apr 2023 19:59:06 -0400 Subject: [PATCH 09/13] Make watchdog thread not hold on to server for 60 seconds --- .../modernfix/world/IntegratedWatchdog.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/embeddedt/modernfix/world/IntegratedWatchdog.java b/src/main/java/org/embeddedt/modernfix/world/IntegratedWatchdog.java index 643712ed..7a287c91 100644 --- a/src/main/java/org/embeddedt/modernfix/world/IntegratedWatchdog.java +++ b/src/main/java/org/embeddedt/modernfix/world/IntegratedWatchdog.java @@ -9,25 +9,29 @@ import org.apache.logging.log4j.Logger; import java.lang.management.ManagementFactory; import java.lang.management.ThreadInfo; import java.lang.management.ThreadMXBean; +import java.lang.ref.WeakReference; import java.util.concurrent.TimeUnit; public class IntegratedWatchdog extends Thread { private static final Logger LOGGER = LogManager.getLogger(); - private final MinecraftServer server; + private final WeakReference server; private static final long MAX_TICK_DELTA = 40*1000; public IntegratedWatchdog(MinecraftServer server) { - this.server = server; + this.server = new WeakReference<>(server); this.setDaemon(true); this.setUncaughtExceptionHandler(new DefaultUncaughtExceptionHandlerWithName(LOGGER)); this.setName("ModernFix integrated server watchdog"); } public void run() { - while(server.isRunning()) { - long nextTick = this.server.getNextTickTime(); + while(true) { + MinecraftServer server = this.server.get(); + if(server == null || !server.isRunning()) + return; + long nextTick = server.getNextTickTime(); long curTime = Util.getMillis(); long delta = curTime - nextTick; if(delta > MAX_TICK_DELTA) { From a0f0600184a97da8d528b11738666672de9f97e8 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Thu, 20 Apr 2023 20:02:32 -0400 Subject: [PATCH 10/13] Make sure GC can actually happen --- .../java/org/embeddedt/modernfix/world/IntegratedWatchdog.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/org/embeddedt/modernfix/world/IntegratedWatchdog.java b/src/main/java/org/embeddedt/modernfix/world/IntegratedWatchdog.java index 7a287c91..95c7e8ab 100644 --- a/src/main/java/org/embeddedt/modernfix/world/IntegratedWatchdog.java +++ b/src/main/java/org/embeddedt/modernfix/world/IntegratedWatchdog.java @@ -57,6 +57,7 @@ public class IntegratedWatchdog extends Thread { nextTick = 0; curTime = 0; } + server = null; /* allow GC */ try { Thread.sleep(nextTick + MAX_TICK_DELTA - curTime); } catch(InterruptedException ignored) { From 45225a580f0701ac22760b33b148f140b37f482b Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Thu, 20 Apr 2023 20:17:55 -0400 Subject: [PATCH 11/13] Clear chunk map from integrated server worlds after server stops --- .../org/embeddedt/modernfix/ModernFix.java | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/main/java/org/embeddedt/modernfix/ModernFix.java b/src/main/java/org/embeddedt/modernfix/ModernFix.java index 07b69036..dd9c572f 100644 --- a/src/main/java/org/embeddedt/modernfix/ModernFix.java +++ b/src/main/java/org/embeddedt/modernfix/ModernFix.java @@ -1,16 +1,22 @@ package org.embeddedt.modernfix; +import it.unimi.dsi.fastutil.longs.Long2ObjectMap; +import net.minecraft.server.level.ChunkHolder; +import net.minecraft.server.level.ChunkMap; +import net.minecraft.server.level.ServerLevel; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.eventbus.api.EventPriority; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.*; import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.ObfuscationReflectionHelper; import net.minecraftforge.fml.config.ModConfig; import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; import net.minecraftforge.fml.event.lifecycle.FMLLoadCompleteEvent; import net.minecraftforge.fml.event.server.FMLServerStartedEvent; import net.minecraftforge.fml.event.server.FMLServerStartingEvent; +import net.minecraftforge.fml.event.server.FMLServerStoppedEvent; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; import net.minecraftforge.fml.loading.FMLLoader; import net.minecraftforge.fml.network.FMLNetworkConstants; @@ -27,6 +33,7 @@ import org.embeddedt.modernfix.util.ClassInfoManager; import org.embeddedt.modernfix.util.KubeUtil; import java.lang.management.ManagementFactory; +import java.lang.reflect.Field; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; @@ -114,4 +121,25 @@ public class ModernFix { public void onLoadComplete(FMLLoadCompleteEvent event) { ClassInfoManager.clear(); } + + @SubscribeEvent(priority = EventPriority.LOWEST) + public void onServerDead(FMLServerStoppedEvent event) { + /* Clear as much data from the integrated server as possible, in case a mod holds on to it */ + try { + Field updatingMapField = ObfuscationReflectionHelper.findField(ChunkMap.class, "updatingChunkMap"); + Field visibleMapField = ObfuscationReflectionHelper.findField(ChunkMap.class, "visibleChunkMap"); + Field pendingUnloadsField = ObfuscationReflectionHelper.findField(ChunkMap.class, "pendingUnloads"); + for(ServerLevel level : event.getServer().getAllLevels()) { + ChunkMap chunkMap = level.getChunkSource().chunkMap; + Long2ObjectMap map = (Long2ObjectMap)updatingMapField.get(chunkMap); + map.clear(); + map = (Long2ObjectMap)visibleMapField.get(chunkMap); + map.clear(); + map = (Long2ObjectMap)pendingUnloadsField.get(chunkMap); + map.clear(); + } + } catch(RuntimeException | IllegalAccessException e) { + ModernFix.LOGGER.error("Couldn't clear chunk data", e); + } + } } From 33d3f0e537018b3f85641d5356c3be348ebeb480 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Thu, 20 Apr 2023 20:19:52 -0400 Subject: [PATCH 12/13] Use SRG names --- src/main/java/org/embeddedt/modernfix/ModernFix.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/embeddedt/modernfix/ModernFix.java b/src/main/java/org/embeddedt/modernfix/ModernFix.java index dd9c572f..5d91a669 100644 --- a/src/main/java/org/embeddedt/modernfix/ModernFix.java +++ b/src/main/java/org/embeddedt/modernfix/ModernFix.java @@ -126,9 +126,9 @@ public class ModernFix { public void onServerDead(FMLServerStoppedEvent event) { /* Clear as much data from the integrated server as possible, in case a mod holds on to it */ try { - Field updatingMapField = ObfuscationReflectionHelper.findField(ChunkMap.class, "updatingChunkMap"); - Field visibleMapField = ObfuscationReflectionHelper.findField(ChunkMap.class, "visibleChunkMap"); - Field pendingUnloadsField = ObfuscationReflectionHelper.findField(ChunkMap.class, "pendingUnloads"); + Field updatingMapField = ObfuscationReflectionHelper.findField(ChunkMap.class, "field_219251_e"); + Field visibleMapField = ObfuscationReflectionHelper.findField(ChunkMap.class, "field_219252_f"); + Field pendingUnloadsField = ObfuscationReflectionHelper.findField(ChunkMap.class, "field_219253_g"); for(ServerLevel level : event.getServer().getAllLevels()) { ChunkMap chunkMap = level.getChunkSource().chunkMap; Long2ObjectMap map = (Long2ObjectMap)updatingMapField.get(chunkMap); From 36664cb23a830035d41e894636ab5dc00bda3ea7 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Thu, 20 Apr 2023 20:45:21 -0400 Subject: [PATCH 13/13] Don't waste time parsing UVs when performing initial model load --- .../dynamicresources/UVController.java | 8 +++++++ .../BlockElementFaceDeserializerMixin.java | 21 +++++++++++++++++++ .../dynamic_resources/ModelBakeryMixin.java | 8 +++---- src/main/resources/modernfix.mixins.json | 1 + 4 files changed, 34 insertions(+), 4 deletions(-) create mode 100644 src/main/java/org/embeddedt/modernfix/dynamicresources/UVController.java create mode 100644 src/main/java/org/embeddedt/modernfix/mixin/perf/dynamic_resources/BlockElementFaceDeserializerMixin.java diff --git a/src/main/java/org/embeddedt/modernfix/dynamicresources/UVController.java b/src/main/java/org/embeddedt/modernfix/dynamicresources/UVController.java new file mode 100644 index 00000000..7b2efe7e --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/dynamicresources/UVController.java @@ -0,0 +1,8 @@ +package org.embeddedt.modernfix.dynamicresources; + +import net.minecraft.client.renderer.block.model.BlockFaceUV; + +public class UVController { + public static final ThreadLocal useDummyUv = ThreadLocal.withInitial(() -> Boolean.FALSE); + public static final BlockFaceUV dummyUv = new BlockFaceUV(new float[4], 0); +} diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/dynamic_resources/BlockElementFaceDeserializerMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/dynamic_resources/BlockElementFaceDeserializerMixin.java new file mode 100644 index 00000000..eb4b3ee5 --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/dynamic_resources/BlockElementFaceDeserializerMixin.java @@ -0,0 +1,21 @@ +package org.embeddedt.modernfix.mixin.perf.dynamic_resources; + +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonElement; +import net.minecraft.client.renderer.block.model.BlockElementFace; +import org.embeddedt.modernfix.dynamicresources.UVController; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +import java.lang.reflect.Type; + +@Mixin(BlockElementFace.Deserializer.class) +public class BlockElementFaceDeserializerMixin { + + @Redirect(method = "deserialize(Lcom/google/gson/JsonElement;Ljava/lang/reflect/Type;Lcom/google/gson/JsonDeserializationContext;)Lnet/minecraft/client/renderer/block/model/BlockElementFace;", + at = @At(value = "INVOKE", target = "Lcom/google/gson/JsonDeserializationContext;deserialize(Lcom/google/gson/JsonElement;Ljava/lang/reflect/Type;)Ljava/lang/Object;", ordinal = 0)) + private Object skipUvsForInitialLoad(JsonDeserializationContext context, JsonElement element, Type type) { + return UVController.useDummyUv.get() ? UVController.dummyUv : context.deserialize(element, type); + } +} diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/dynamic_resources/ModelBakeryMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/dynamic_resources/ModelBakeryMixin.java index 2eb96122..7cc79897 100644 --- a/src/main/java/org/embeddedt/modernfix/mixin/perf/dynamic_resources/ModelBakeryMixin.java +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/dynamic_resources/ModelBakeryMixin.java @@ -40,10 +40,7 @@ import org.apache.commons.lang3.tuple.Triple; import org.apache.logging.log4j.Logger; import org.embeddedt.modernfix.ModernFix; import org.embeddedt.modernfix.duck.IExtendedModelBakery; -import org.embeddedt.modernfix.dynamicresources.DynamicBakedModelProvider; -import org.embeddedt.modernfix.dynamicresources.DynamicModelBakeEvent; -import org.embeddedt.modernfix.dynamicresources.ModelLocationCache; -import org.embeddedt.modernfix.dynamicresources.ResourcePackHandler; +import org.embeddedt.modernfix.dynamicresources.*; import org.spongepowered.asm.mixin.*; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -286,10 +283,12 @@ public abstract class ModelBakeryMixin implements IExtendedModelBakery { } modelFiles.clear(); CompletableFuture.allOf(modelBytes.toArray(new CompletableFuture[0])).join(); + UVController.useDummyUv.set(Boolean.TRUE); for(CompletableFuture> future : modelBytes) { Pair pair = future.join(); try { if(pair.getSecond() != null) { + BlockModel model = ModelLoaderRegistry.ExpandedBlockModelDeserializer.INSTANCE.fromJson(pair.getSecond(), BlockModel.class); model.name = pair.getFirst().toString(); modelFiles.addAll(model.getDependencies()); @@ -301,6 +300,7 @@ public abstract class ModelBakeryMixin implements IExtendedModelBakery { } basicModels.put(pair.getFirst(), (BlockModel)missingModel); } + UVController.useDummyUv.set(Boolean.FALSE); } modelFiles = null; Function modelGetter = loc -> { diff --git a/src/main/resources/modernfix.mixins.json b/src/main/resources/modernfix.mixins.json index 979de7f3..814136ad 100644 --- a/src/main/resources/modernfix.mixins.json +++ b/src/main/resources/modernfix.mixins.json @@ -79,6 +79,7 @@ "bugfix.concurrency.RenderTypeMixin", "bugfix.concurrency.MinecraftMixin", "bugfix.concurrency.StaticTagHelperMixin", + "perf.dynamic_resources.BlockElementFaceDeserializerMixin", "perf.dynamic_resources.BlockModelShaperMixin", "perf.dynamic_resources.ItemModelShaperMixin", "perf.dynamic_resources.ModelBakeryMixin",