diff --git a/src/main/java/cpw/mods/modlauncher/ModernFixCachingClassTransformer.java b/src/main/java/cpw/mods/modlauncher/ModernFixCachingClassTransformer.java deleted file mode 100644 index 1e09c60b..00000000 --- a/src/main/java/cpw/mods/modlauncher/ModernFixCachingClassTransformer.java +++ /dev/null @@ -1,213 +0,0 @@ -package cpw.mods.modlauncher; - -import java.io.*; -import java.lang.reflect.Array; -import java.lang.reflect.Field; -import java.nio.charset.StandardCharsets; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.*; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ForkJoinPool; - -import cpw.mods.modlauncher.api.ITransformer; -import cpw.mods.modlauncher.api.ITransformerActivity; -import cpw.mods.modlauncher.serviceapi.ILaunchPluginService; -import net.minecraftforge.coremod.transformer.CoreModBaseTransformer; -import net.minecraftforge.fml.loading.FMLPaths; -import net.minecraftforge.fml.loading.LoadingModList; -import org.apache.commons.io.FileUtils; -import org.apache.commons.lang3.StringUtils; -import org.apache.commons.lang3.tuple.Pair; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.embeddedt.modernfix.ModernFix; -import org.embeddedt.modernfix.classloading.api.IHashableTransformer; -import org.embeddedt.modernfix.classloading.hashers.CoreModTransformerHasher; -import org.embeddedt.modernfix.classloading.hashers.MixinTransformerHasher; -import org.embeddedt.modernfix.util.FileUtil; -import org.objectweb.asm.Type; -import org.spongepowered.asm.launch.MixinLaunchPluginLegacy; - -import javax.lang.model.SourceVersion; - -public class ModernFixCachingClassTransformer extends ClassTransformer { - public static final Logger LOGGER = LogManager.getLogger("ModernFixCachingTransformer"); - - public static File CLASS_CACHE_FOLDER = null; - private final LaunchPluginHandler pluginHandler; - private final Map plugins; - private final TransformStore transformStore; - private final TransformerAuditTrail auditTrail; - private final TransformingClassLoader transformingClassLoader; - private final HashMap>> transformersByClass; - - private ConcurrentHashMap, byte[]>> transformationCache; - private ForkJoinPool classSaverPool = ForkJoinPool.commonPool(); - - public static final byte[] EMPTY_BYTE_ARRAY = new byte[0]; - - public static ThreadLocal systemHasher = ThreadLocal.withInitial(() -> { - try { - return MessageDigest.getInstance("SHA-256"); - } catch(NoSuchAlgorithmException e) { - throw new RuntimeException(e); - } - }); - - public ModernFixCachingClassTransformer(TransformStore transformStore, LaunchPluginHandler pluginHandler, TransformingClassLoader transformingClassLoader, TransformerAuditTrail trail) { - super(transformStore, pluginHandler, transformingClassLoader, trail); - CLASS_CACHE_FOLDER = FileUtil.childFile(FMLPaths.GAMEDIR.get().resolve("modernfix").resolve("classCacheV1").toFile()); - this.transformStore = transformStore; - this.pluginHandler = pluginHandler; - this.transformingClassLoader = transformingClassLoader; - this.auditTrail = trail; - /* Build a lookup table of all transformers for a given class */ - this.transformersByClass = new HashMap<>(); - try { - Field pluginsField = LaunchPluginHandler.class.getDeclaredField("plugins"); - pluginsField.setAccessible(true); - this.plugins = (Map)pluginsField.get(this.pluginHandler); - Field transformersByTypeField = TransformStore.class.getDeclaredField("transformers"); - transformersByTypeField.setAccessible(true); - Field transformersMapField = TransformList.class.getDeclaredField("transformers"); - transformersMapField.setAccessible(true); - EnumMap> transformersByType = (EnumMap>)transformersByTypeField.get(this.transformStore); - for(TransformList transformList : transformersByType.values()) { - Map>> transformers = (Map>>)transformersMapField.get(transformList); - for(Map.Entry>> entry : transformers.entrySet()) { - String className = entry.getKey().getClassName().getClassName(); - List> transformerList = this.transformersByClass.computeIfAbsent(className, k -> new ArrayList<>()); - transformerList.addAll(entry.getValue()); - } - } - for(List> transformerList : this.transformersByClass.values()) { - transformerList.sort((t1, t2) -> Comparator.naturalOrder().compare(StringUtils.join(t1.labels(), " "), StringUtils.join(t2.labels(), " "))); - } - } catch(ReflectiveOperationException e) { - throw new RuntimeException(e); - } - } - - private ArrayList computeHash(String className, byte[] inputClass, String reason) { - final String internalName = className.replace('.', '/'); - final Type classDesc = Type.getObjectType(internalName); - ArrayList pluginList = new ArrayList<>(); - for(ILaunchPluginService plugin : plugins.values()) { - if(!plugin.handlesClass(classDesc, inputClass.length == 0, reason).isEmpty()) { - pluginList.add(plugin); - } - } - final boolean needsTransforming = transformStore.needsTransforming(internalName); - if (!needsTransforming && pluginList.isEmpty()) { - return null; - } - /* Now compute the hash list for the required transformers */ - ArrayList hashList = new ArrayList<>(); - pluginList.sort((service1, service2) -> Comparator.naturalOrder().compare(service1.name(), service2.name())); - for(ILaunchPluginService service : pluginList) { - byte[] hash = obtainHash(service, className); - if(hash == null) { - return null; - } - hashList.add(hash); - } - if(needsTransforming) { - List> transformers = this.transformersByClass.get(internalName); - if(transformers != null) { - for(ITransformer transformer : transformers) { - byte[] hash = obtainHash(transformer, className); - if(hash == null) { - return null; - } - hashList.add(hash); - } - } - } - /* Hash the class itself last, so that we bail out early if plugins can't hash */ - MessageDigest hasher = systemHasher.get(); - hasher.reset(); - hashList.add(hasher.digest(inputClass)); - return hashList; - } - - /** - * Check the hashed list of transformers and use a cached version of the class if possible. This code needs - * to be very fast as the entire point is to spend very little time doing transformation work that was done before. - * @param inputClass The bytecode to be transformed - * @param className Name of the class - * @param reason Reason for the class being loaded - * @return The transformed version of the class - */ - @Override - public byte[] transform(byte[] inputClass, String className, String reason) { - /* We only want to cache actual transformations */ - if(ITransformerActivity.CLASSLOADING_REASON.equals(reason) || "mixin".equals(reason)) { - final byte[] classToHash = inputClass; - ArrayList hashList = computeHash(className, classToHash, reason); - if(hashList == null) - return super.transform(inputClass, className, reason); - /* Check if the cache contains a transformed class matching these hashes */ - /* TODO maybe sanitize the class name? */ - File cacheLocation = new File(CLASS_CACHE_FOLDER, className.replace('.', '/') + "." + reason); - boolean hashesMatch = true; - try(ObjectInputStream stream = new ObjectInputStream(new FileInputStream(cacheLocation))) { - ArrayList savedHash = (ArrayList)stream.readObject(); - byte[] savedInputClass = (byte[])stream.readObject(); - if(hashList != null) { - for(int i = 0; i < savedHash.size(); i++) { - if(!Arrays.equals(savedHash.get(i), hashList.get(i))) { - hashesMatch = false; - break; - } - } - } else - hashesMatch = false; - if(hashesMatch) - inputClass = savedInputClass; - } catch(IOException | ClassNotFoundException | ClassCastException e) { - if(!(e instanceof FileNotFoundException)) - e.printStackTrace(); - hashesMatch = false; - } - if(!hashesMatch) { - inputClass = super.transform(inputClass, className, reason); - if(hashList != null) { - final byte[] classToSave = inputClass; - final ArrayList hashListToSave = hashList; - classSaverPool.submit(() -> { - cacheLocation.getParentFile().mkdirs(); - try(ObjectOutputStream stream = new ObjectOutputStream(new FileOutputStream(cacheLocation))) { - stream.writeObject(hashListToSave); - stream.writeObject(classToSave); - } catch(IOException e) { - e.printStackTrace(); - } - }); - } - - } - return inputClass; - } - return super.transform(inputClass, className, reason); - } - - private final byte[] FORGE_HASH = LoadingModList.get().getModFileById("forge").getMods().get(0).getVersion().toString().getBytes(StandardCharsets.UTF_8); - - private byte[] obtainHash(Object o, String className) { - if(o instanceof CoreModBaseTransformer) { - return CoreModTransformerHasher.obtainHash((CoreModBaseTransformer)o); - } else if(o instanceof MixinLaunchPluginLegacy) { - return MixinTransformerHasher.obtainHash((MixinLaunchPluginLegacy)o, className); - } else if(o instanceof IHashableTransformer) { - return ((IHashableTransformer)o).getHashForClass(className); - } else if(o.getClass().getName().startsWith("net.minecraftforge.")) { - return FORGE_HASH; - } else { - LOGGER.warn("No hash implementation found for: " + o.getClass().getName()); - return null; - } - } -} diff --git a/src/main/java/org/embeddedt/modernfix/ModernFixClient.java b/src/main/java/org/embeddedt/modernfix/ModernFixClient.java index a81291e2..f1ab4ff8 100644 --- a/src/main/java/org/embeddedt/modernfix/ModernFixClient.java +++ b/src/main/java/org/embeddedt/modernfix/ModernFixClient.java @@ -20,19 +20,15 @@ import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.ModContainer; import net.minecraftforge.fml.ModList; import net.minecraftforge.fml.common.ObfuscationReflectionHelper; -import net.minecraftforge.fml.event.server.FMLServerStartedEvent; import net.minecraftforge.fml.event.server.FMLServerStartingEvent; import net.minecraftforge.fml.network.NetworkEvent; import org.embeddedt.modernfix.core.ModernFixMixinPlugin; import org.embeddedt.modernfix.core.config.ModernFixConfig; -import org.embeddedt.modernfix.load.LoadEvents; import org.embeddedt.modernfix.packet.EntityIDSyncPacket; -import org.embeddedt.modernfix.screen.DeferredLevelLoadingScreen; import org.embeddedt.modernfix.world.IntegratedWatchdog; import java.lang.management.ManagementFactory; import java.lang.reflect.Field; -import java.sql.Ref; import java.util.*; import java.util.function.Supplier; @@ -49,9 +45,6 @@ public class ModernFixClient { public ModernFixClient() { // clear reserve as it's not needed ObfuscationReflectionHelper.setPrivateValue(Minecraft.class, null, new byte[0], "field_71444_a"); - if(ModernFixMixinPlugin.instance.isOptionEnabled("perf.faster_singleplayer_load.ClientEvents")) { - MinecraftForge.EVENT_BUS.register(new LoadEvents()); - } if(ModernFixMixinPlugin.instance.isOptionEnabled("feature.branding.F3Screen")) { Optional mfContainer = ModList.get().getModContainerById("modernfix"); if(mfContainer.isPresent()) @@ -91,7 +84,6 @@ public class ModernFixClient { if(event.phase == TickEvent.Phase.END && recipesUpdated && tagsUpdated - && !(Minecraft.getInstance().screen instanceof DeferredLevelLoadingScreen) && worldLoadStartTime != -1 && Minecraft.getInstance().player != null && numRenderTicks++ >= 10) { diff --git a/src/main/java/org/embeddedt/modernfix/agent/Agent.java b/src/main/java/org/embeddedt/modernfix/agent/Agent.java deleted file mode 100644 index 5cf5298d..00000000 --- a/src/main/java/org/embeddedt/modernfix/agent/Agent.java +++ /dev/null @@ -1,59 +0,0 @@ -package org.embeddedt.modernfix.agent; - -import com.google.common.collect.ImmutableMap; -import org.objectweb.asm.ClassReader; -import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.tree.*; - -import java.lang.instrument.ClassFileTransformer; -import java.lang.instrument.IllegalClassFormatException; -import java.lang.instrument.Instrumentation; -import java.security.ProtectionDomain; -import java.util.function.Function; - -public class Agent { - public static void agentmain(String args, Instrumentation instrumentation) { - instrumentation.addTransformer(new EarlyTransformer()); - } - - private static class EarlyTransformer implements ClassFileTransformer { - - private static final ImmutableMap> TRANSFORMERS = ImmutableMap.>builder() - .put("net/minecraftforge/fml/loading/moddiscovery/Scanner", EarlyTransformer::transformScanner) - .build(); - - private static ClassNode transformScanner(ClassNode input) { - for(MethodNode method : input.methods) { - if(method.name.equals("fileVisitor")) { - for(int i = 0; i < method.instructions.size(); i++) { - AbstractInsnNode ainsn = method.instructions.get(i); - if(ainsn.getOpcode() == Opcodes.INVOKEVIRTUAL) { - MethodInsnNode minsn = (MethodInsnNode)ainsn; - if(minsn.name.equals("accept") && minsn.owner.equals("org/objectweb/asm/ClassReader")) { - method.instructions.set(minsn.getPrevious(), new LdcInsnNode(ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES)); - return input; - } - } - } - } - } - return input; - } - - @Override - public byte[] transform(ClassLoader classLoader, String s, Class aClass, ProtectionDomain protectionDomain, byte[] bytes) throws IllegalClassFormatException { - Function func = TRANSFORMERS.get(s); - if(func != null) { - ClassReader reader = new ClassReader(bytes); - ClassNode node = new ClassNode(Opcodes.ASM9); - reader.accept(node, 0); - node = func.apply(node); - ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); - node.accept(writer); - return writer.toByteArray(); - } else - return bytes; - } - } -} diff --git a/src/main/java/org/embeddedt/modernfix/classloading/api/IHashableTransformer.java b/src/main/java/org/embeddedt/modernfix/classloading/api/IHashableTransformer.java deleted file mode 100644 index f867a16e..00000000 --- a/src/main/java/org/embeddedt/modernfix/classloading/api/IHashableTransformer.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.embeddedt.modernfix.classloading.api; - -public interface IHashableTransformer { - /** - * Called on an ILaunchPluginService or ITransformer to obtain a unique hash of the transformations that will be applied. - * Used to invalidate the transformation cache when needed. - * @param className Name of class being transformed - * @return A unique hash of the transformations that will be applied - */ - byte[] getHashForClass(String className); -} diff --git a/src/main/java/org/embeddedt/modernfix/classloading/hashers/CoreModTransformerHasher.java b/src/main/java/org/embeddedt/modernfix/classloading/hashers/CoreModTransformerHasher.java deleted file mode 100644 index fa4f602e..00000000 --- a/src/main/java/org/embeddedt/modernfix/classloading/hashers/CoreModTransformerHasher.java +++ /dev/null @@ -1,49 +0,0 @@ -package org.embeddedt.modernfix.classloading.hashers; - -import cpw.mods.modlauncher.ModernFixCachingClassTransformer; -import net.minecraftforge.coremod.CoreMod; -import net.minecraftforge.coremod.transformer.CoreModBaseTransformer; - -import java.io.IOException; -import java.lang.reflect.Field; -import java.nio.file.Files; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.concurrent.ConcurrentHashMap; - -public class CoreModTransformerHasher { - private static final ConcurrentHashMap hashForCoremod; - private static Field coremodField; - - static { - hashForCoremod = new ConcurrentHashMap<>(); - try { - coremodField = CoreModBaseTransformer.class.getDeclaredField("coreMod"); - coremodField.setAccessible(true); - } catch(ReflectiveOperationException e) { - throw new RuntimeException(e); - } - } - - private static byte[] hashCoreMod(CoreMod coreMod) { - byte[] coreModContents; - try { - coreModContents = Files.readAllBytes(coreMod.getPath()); - } catch(IOException e) { - throw new RuntimeException(e); - } - MessageDigest hasher = ModernFixCachingClassTransformer.systemHasher.get(); - hasher.reset(); - return hasher.digest(coreModContents); - } - - public static byte[] obtainHash(CoreModBaseTransformer transformer) { - CoreMod coremod; - try { - coremod = (CoreMod)coremodField.get(transformer); - } catch(ReflectiveOperationException e) { - throw new RuntimeException(e); - } - return hashForCoremod.computeIfAbsent(coremod, CoreModTransformerHasher::hashCoreMod); - } -} diff --git a/src/main/java/org/embeddedt/modernfix/classloading/hashers/MixinTransformerHasher.java b/src/main/java/org/embeddedt/modernfix/classloading/hashers/MixinTransformerHasher.java deleted file mode 100644 index 1716dcd3..00000000 --- a/src/main/java/org/embeddedt/modernfix/classloading/hashers/MixinTransformerHasher.java +++ /dev/null @@ -1,154 +0,0 @@ -package org.embeddedt.modernfix.classloading.hashers; - -import com.google.common.io.Resources; -import cpw.mods.modlauncher.ModernFixCachingClassTransformer; -import org.spongepowered.asm.launch.IClassProcessor; -import org.spongepowered.asm.launch.MixinLaunchPluginLegacy; -import org.spongepowered.asm.mixin.MixinEnvironment; -import org.spongepowered.asm.mixin.extensibility.IMixinInfo; -import org.spongepowered.asm.mixin.injection.invoke.arg.ArgsClassGenerator; -import org.spongepowered.asm.mixin.transformer.ext.Extensions; - -import java.io.IOException; -import java.lang.reflect.Field; -import java.net.URL; -import java.nio.file.Files; -import java.nio.file.Path; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.*; -import java.util.stream.Stream; - -public class MixinTransformerHasher { - private static HashMap hashesByClass = null; - private final static MessageDigest hasher; - - private static Field processorsListField, transformerField, processorField, environmentField; - - private static boolean fixedArgsClassCount = false; - - private static final byte[] NO_MIXINS = new byte[] {(byte)0xde, (byte)0xad, (byte)0xbe, (byte)0xef}; - - static { - try { - hasher = MessageDigest.getInstance("SHA-256"); - } catch (NoSuchAlgorithmException e) { - throw new RuntimeException(e); - } - } - - public static byte[] obtainHash(MixinLaunchPluginLegacy plugin, String className) { - /* FIXME runs too early right now, and therefore doesn't pick up the list of mixins correctly */ - synchronized (MixinTransformerHasher.class) { - if(hashesByClass == null) { - try { - if(processorsListField == null) { - processorsListField = MixinLaunchPluginLegacy.class.getDeclaredField("processors"); - processorsListField.setAccessible(true); - } - List processors = (List) processorsListField.get(plugin); - Object transformHandler = null; - for(IClassProcessor processor : processors) { - if(processor.getClass().getName().equals("org.spongepowered.asm.service.modlauncher.MixinTransformationHandler")) { - transformHandler = processor; - break; - } - } - if(transformHandler == null) - throw new IllegalStateException("Mixin transform handler not found"); - if(transformerField == null) { - transformerField = transformHandler.getClass().getDeclaredField("transformer"); - transformerField.setAccessible(true); - } - Object transformer = transformerField.get(transformHandler); - if(!fixedArgsClassCount) { - Path syntheticFolderPath = ModernFixCachingClassTransformer.CLASS_CACHE_FOLDER.toPath().resolve("org").resolve("spongepowered").resolve("asm").resolve("synthetic"); - if(Files.exists(syntheticFolderPath)) { - Field extensionsField = transformer.getClass().getDeclaredField("extensions"); - extensionsField.setAccessible(true); - Extensions extensions = (Extensions)extensionsField.get(transformer); - ArgsClassGenerator argsGen = extensions.getGenerator(ArgsClassGenerator.class); - Field nextIndexField = ArgsClassGenerator.class.getDeclaredField("nextIndex"); - try(Stream argsStream = Files.find(syntheticFolderPath, 1, (path, attr) -> path.getFileName().toString().startsWith("Args$"))) { - int[] startIndex = new int[1]; - startIndex[0] = 1; - argsStream.forEach(path -> { - String fileName = path.getFileName().toString(); - try { - int idx = Integer.parseInt(fileName.replace("Args$", "")); - startIndex[0] = Math.max(startIndex[0], idx + 1); - } catch(NumberFormatException e) { - ModernFixCachingClassTransformer.LOGGER.warn("Unexpected classname: " + fileName); - } - }); - nextIndexField.setAccessible(true); - nextIndexField.set(argsGen, startIndex[0]); - ModernFixCachingClassTransformer.LOGGER.debug("Patched ArgsClassGenerator to start at index " + startIndex[0]); - } catch(IOException e) { - ModernFixCachingClassTransformer.LOGGER.error("Failed to adjust Mixin synthetic args"); - } - } - - fixedArgsClassCount = true; - } - if(processorField == null) { - processorField = transformer.getClass().getDeclaredField("processor"); - processorField.setAccessible(true); - } - Object processor = processorField.get(transformer); - if(environmentField == null) { - environmentField = processor.getClass().getDeclaredField("currentEnvironment"); - environmentField.setAccessible(true); - } - MixinEnvironment currentEnv = (MixinEnvironment)environmentField.get(processor); - if(currentEnv == null || currentEnv.getPhase() != MixinEnvironment.Phase.DEFAULT) { - return null; /* no hash obtained until mixin is ready */ - } - Field configsField = processor.getClass().getDeclaredField("configs"); - configsField.setAccessible(true); - List configs = (List)configsField.get(processor); - Field mixinsField = Class.forName("org.spongepowered.asm.mixin.transformer.MixinConfig").getDeclaredField("mixins"); - mixinsField.setAccessible(true); - /* getTargetClasses can't be used because it's package-private */ - Field classNamesField = Class.forName("org.spongepowered.asm.mixin.transformer.MixinInfo").getDeclaredField("targetClassNames"); - classNamesField.setAccessible(true); - HashMap> mixinsByClass = new HashMap<>(); - for(Object config : configs) { - List mixins = (List)mixinsField.get(config); - for(IMixinInfo mixin : mixins) { - List targetClassNames = (List)classNamesField.get(mixin); - for(String s : targetClassNames) { - mixinsByClass.computeIfAbsent(s, k -> new ArrayList<>()).add(mixin); - } - } - } - for(ArrayList infos : mixinsByClass.values()) { - infos.sort((info1, info2) -> Comparator.naturalOrder().compare(info1.getClassName(), info2.getClassName())); - } - /* Now go through each class name and hash it */ - HashMap hashesByClassInit = new HashMap<>(); - for(Map.Entry> mixinsForClass : mixinsByClass.entrySet()) { - hasher.reset(); - for(IMixinInfo mixin : mixinsForClass.getValue()) { - URL url = Thread.currentThread().getContextClassLoader().getResource(mixin.getClassName().replace('.', '/') + ".class"); - if(url == null) - throw new IllegalStateException("Can't find " + mixin.getClassName()); - byte[] bytecode; - try { - bytecode = Resources.asByteSource(url).read(); - } catch(IOException e) { - throw new RuntimeException(e); - } - hasher.update(bytecode); - } - hashesByClassInit.put(mixinsForClass.getKey().replace('/', '.'), hasher.digest()); - } - hashesByClass = hashesByClassInit; - } catch(ReflectiveOperationException e) { - throw new RuntimeException(e); - } - } - } - return hashesByClass.getOrDefault(className, NO_MIXINS); - } -} diff --git a/src/main/java/org/embeddedt/modernfix/core/ModernFixMixinPlugin.java b/src/main/java/org/embeddedt/modernfix/core/ModernFixMixinPlugin.java index 1c696258..df6e7933 100644 --- a/src/main/java/org/embeddedt/modernfix/core/ModernFixMixinPlugin.java +++ b/src/main/java/org/embeddedt/modernfix/core/ModernFixMixinPlugin.java @@ -134,29 +134,7 @@ public class ModernFixMixinPlugin implements IMixinConfigPlugin { @Override public void onLoad(String mixinPackage) { - try { - if(isOptionEnabled("launch.transformer_cache.ModernFixClassTransformer")) { - ClassLoader loader = Thread.currentThread().getContextClassLoader(); - Field classTransformerField = TransformingClassLoader.class.getDeclaredField("classTransformer"); - classTransformerField.setAccessible(true); - ClassTransformer t = (ClassTransformer)classTransformerField.get(loader); - TransformStore store = ObfuscationReflectionHelper.getPrivateValue(ClassTransformer.class, t, "transformers"); - LaunchPluginHandler pluginHandler = ObfuscationReflectionHelper.getPrivateValue(ClassTransformer.class, t, "pluginHandler"); - TransformerAuditTrail trail = ObfuscationReflectionHelper.getPrivateValue(ClassTransformer.class, t, "auditTrail"); - injectClassIntoSystemLoader("org.embeddedt.modernfix.util.FileUtil"); - injectClassIntoSystemLoader("org.embeddedt.modernfix.classloading.api.IHashableTransformer"); - injectClassIntoSystemLoader("org.embeddedt.modernfix.classloading.hashers.CoreModTransformerHasher"); - injectClassIntoSystemLoader("org.embeddedt.modernfix.classloading.hashers.MixinTransformerHasher"); - Class newTransformerClass = injectClassIntoSystemLoader("cpw.mods.modlauncher.ModernFixCachingClassTransformer"); - Constructor constructor = newTransformerClass.getConstructor(TransformStore.class, LaunchPluginHandler.class, TransformingClassLoader.class, TransformerAuditTrail.class); - ClassTransformer newTransformer = (ClassTransformer)constructor.newInstance(store, pluginHandler, loader, trail); - classTransformerField.set(loader, newTransformer); - logger.info("Successfully injected caching transformer"); - } - } catch(RuntimeException | ReflectiveOperationException | IOException e) { - logger.error("Failed to make classloading changes", e); - } } @Override 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 23ed4ede..2096da80 100644 --- a/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java +++ b/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java @@ -76,7 +76,6 @@ public class ModernFixEarlyConfig { /* Keep this off if JEI isn't installed to prevent breaking vanilla gameplay */ this.addMixinRule("perf.blast_search_trees", modPresent("jei")); this.addMixinRule("safety", true); - this.addMixinRule("launch.transformer_cache", false); this.addMixinRule("launch.class_search_cache", true); boolean isDevEnv = !FMLLoader.isProduction() && FMLLoader.getLoadingModList().getModFileById("modernfix").getFile().getLocator() instanceof ExplodedDirectoryLocator; this.addMixinRule("devenv", isDevEnv); diff --git a/src/main/java/org/embeddedt/modernfix/load/LoadEvents.java b/src/main/java/org/embeddedt/modernfix/load/LoadEvents.java deleted file mode 100644 index a7f6e158..00000000 --- a/src/main/java/org/embeddedt/modernfix/load/LoadEvents.java +++ /dev/null @@ -1,113 +0,0 @@ -package org.embeddedt.modernfix.load; - -import it.unimi.dsi.fastutil.longs.LongIterator; -import net.minecraft.Util; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.screens.LevelLoadingScreen; -import net.minecraft.client.gui.screens.ProgressScreen; -import net.minecraft.client.server.IntegratedServer; -import net.minecraft.network.chat.TranslatableComponent; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ServerChunkCache; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.TicketType; -import net.minecraft.server.level.progress.ChunkProgressListener; -import net.minecraft.util.Unit; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.ForcedChunksSavedData; -import net.minecraftforge.client.event.GuiOpenEvent; -import net.minecraftforge.common.world.ForgeChunkManager; -import net.minecraftforge.event.entity.player.PlayerEvent; -import net.minecraftforge.eventbus.api.EventPriority; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.event.server.FMLServerAboutToStartEvent; -import net.minecraftforge.fml.server.ServerLifecycleHooks; -import org.embeddedt.modernfix.core.ModernFixMixinPlugin; -import org.embeddedt.modernfix.screen.DeferredLevelLoadingScreen; - -import java.util.concurrent.locks.LockSupport; -import java.util.function.BooleanSupplier; - -/** - * Handles deferring the world load screen. - *

- * TODO: The vanilla check that at least 441 chunks have been loaded does not check whether they are spawn chunks - * or chunks loaded by the player. Consequently it is possible for loading to finish before every spawn chunk has - * been loaded. However the chunk system has at least been warmed up by this point so the remaining chunks load - * reasonably quickly. - */ -public class LoadEvents { - private boolean hasFirstPlayerJoined = false; - - @SubscribeEvent - public void serverWillStart(FMLServerAboutToStartEvent event) { - hasFirstPlayerJoined = false; - } - - @SubscribeEvent(priority = EventPriority.LOWEST) - public void onPlayerLogin(PlayerEvent.PlayerLoggedInEvent event) { - if(!hasFirstPlayerJoined && ModernFixMixinPlugin.instance.isOptionEnabled("perf.faster_singleplayer_load.ClientEvents")) { - hasFirstPlayerJoined = true; - MinecraftServer server = ServerLifecycleHooks.getCurrentServer(); - if(server instanceof IntegratedServer) { - handleInitialChunkLoad(); - } - } - } - - @SubscribeEvent(priority = EventPriority.LOWEST) - public void onWorldShow(GuiOpenEvent event) { - if(ServerLifecycleHooks.getCurrentServer() instanceof IntegratedServer) { - if(event.getGui() == null && Minecraft.getInstance().level != null && integratedWorldLoadListener != null) { - /* this means the world is about to be displayed, check if 441 initialized */ - ServerChunkCache provider = ServerLifecycleHooks.getCurrentServer().overworld().getChunkSource(); - BooleanSupplier worldLoadDone = () -> provider.getTickingGenerated() >= 441; - if(!worldLoadDone.getAsBoolean()) { - DeferredLevelLoadingScreen newScreen = new DeferredLevelLoadingScreen(Minecraft.getInstance().progressListener.get(), worldLoadDone); - event.setGui(newScreen); - } - } else if(event.getGui() instanceof LevelLoadingScreen && Minecraft.getInstance().level == null && ModernFixMixinPlugin.instance.isOptionEnabled("perf.faster_singleplayer_load.ClientEvents")) { - ProgressScreen loadscreen = new ProgressScreen(); - loadscreen.progressStartNoAbort(new TranslatableComponent("connect.joining")); - event.setGui(loadscreen); - } - } - } - - public static ChunkProgressListener integratedWorldLoadListener; - - private void handleInitialChunkLoad() { - MinecraftServer server = ServerLifecycleHooks.getCurrentServer(); - ServerLevel overworld = server.overworld(); - ServerChunkCache provider = overworld.getChunkSource(); - provider.getLightEngine().setTaskPerBatch(500); - provider.addRegionTicket(TicketType.START, new ChunkPos(overworld.getSharedSpawnPos()), 11, Unit.INSTANCE); - while(provider.getTickingGenerated() < 441) { - server.runAllTasks(); - Thread.yield(); - LockSupport.parkNanos("waiting for world load", 100000L); - server.nextTickTime = Util.getMillis() + 10; - } - for(ServerLevel serverworld1 : server.getAllLevels()) { - ForcedChunksSavedData forcedchunkssavedata = serverworld1.getDataStorage().get(ForcedChunksSavedData::new, "chunks"); - if (forcedchunkssavedata != null) { - LongIterator longiterator = forcedchunkssavedata.getChunks().iterator(); - - while(longiterator.hasNext()) { - long i = longiterator.nextLong(); - ChunkPos chunkpos = new ChunkPos(i); - serverworld1.getChunkSource().updateChunkForced(chunkpos, true); - } - - ForgeChunkManager.reinstatePersistentChunks(serverworld1, forcedchunkssavedata); - } - } - server.runAllTasks(); - server.nextTickTime = Util.getMillis() + 10; - provider.getLightEngine().setTaskPerBatch(5); - if(integratedWorldLoadListener != null) { - integratedWorldLoadListener.stop(); - integratedWorldLoadListener = null; - } - } -} diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/faster_singleplayer_load/MinecraftServerMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/faster_singleplayer_load/MinecraftServerMixin.java deleted file mode 100644 index ad0b11a0..00000000 --- a/src/main/java/org/embeddedt/modernfix/mixin/perf/faster_singleplayer_load/MinecraftServerMixin.java +++ /dev/null @@ -1,41 +0,0 @@ -package org.embeddedt.modernfix.mixin.perf.faster_singleplayer_load; - -import net.minecraft.Util; -import net.minecraft.client.server.IntegratedServer; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ServerChunkCache; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.progress.ChunkProgressListener; -import org.embeddedt.modernfix.ModernFixClient; -import org.embeddedt.modernfix.load.LoadEvents; -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; - -@Mixin(MinecraftServer.class) -public abstract class MinecraftServerMixin { - @Shadow protected long nextTickTime; - - @Shadow public abstract ServerLevel overworld(); - - @Shadow protected abstract void updateMobSpawningFlags(); - - /** - * @author embeddedt - * @reason defer the 441 chunk load until *after* join game packets are sent to the client, in order to allow - * mods that process advancements, etc. to work on that at the same time - */ - @Inject(method = "prepareLevels", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerLevel;getChunkSource()Lnet/minecraft/server/level/ServerChunkCache;", ordinal = 0), cancellable = true) - private void skipInitialChunkLoad(ChunkProgressListener arg, CallbackInfo ci) { - if(((Object)this) instanceof IntegratedServer) { - ci.cancel(); - LoadEvents.integratedWorldLoadListener = arg; - this.nextTickTime = Util.getMillis(); - this.overworld().getChunkSource().getLightEngine().setTaskPerBatch(5); - this.updateMobSpawningFlags(); - } - } -} diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/flatten_model_predicates/AndConditionMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/flatten_model_predicates/AndConditionMixin.java deleted file mode 100644 index 94283f0a..00000000 --- a/src/main/java/org/embeddedt/modernfix/mixin/perf/flatten_model_predicates/AndConditionMixin.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.embeddedt.modernfix.mixin.perf.flatten_model_predicates; - -import com.google.common.collect.Streams; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.client.renderer.block.model.multipart.AndCondition; -import net.minecraft.client.renderer.block.model.multipart.Condition; -import net.minecraft.world.level.block.state.StateDefinition; -import org.embeddedt.modernfix.predicate.StatePropertyPredicateHelper; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; -import org.spongepowered.asm.mixin.Shadow; - -import java.util.function.Predicate; -import java.util.stream.Collectors; - -@Mixin(AndCondition.class) -public class AndConditionMixin { - @Shadow @Final private Iterable conditions; - - /** - * @author JellySquid - * @reason Flatten predicates - */ - @Overwrite - public Predicate getPredicate(StateDefinition stateManager) { - return StatePropertyPredicateHelper.allMatch(Streams.stream(this.conditions).map((multipartModelSelector) -> { - return multipartModelSelector.getPredicate(stateManager); - }).collect(Collectors.toList())); - } -} diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/flatten_model_predicates/OrConditionMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/flatten_model_predicates/OrConditionMixin.java deleted file mode 100644 index f336a997..00000000 --- a/src/main/java/org/embeddedt/modernfix/mixin/perf/flatten_model_predicates/OrConditionMixin.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.embeddedt.modernfix.mixin.perf.flatten_model_predicates; - -import com.google.common.collect.Streams; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.client.renderer.block.model.multipart.Condition; -import net.minecraft.client.renderer.block.model.multipart.OrCondition; -import net.minecraft.world.level.block.state.StateDefinition; -import org.embeddedt.modernfix.predicate.StatePropertyPredicateHelper; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; -import org.spongepowered.asm.mixin.Shadow; - -import java.util.function.Predicate; -import java.util.stream.Collectors; - -@Mixin(OrCondition.class) -public class OrConditionMixin { - @Shadow @Final private Iterable conditions; - - /** - * @author JellySquid - * @reason Flatten predicates - */ - @Overwrite - public Predicate getPredicate(StateDefinition stateManager) { - return StatePropertyPredicateHelper.anyMatch(Streams.stream(this.conditions).map((multipartModelSelector) -> { - return multipartModelSelector.getPredicate(stateManager); - }).collect(Collectors.toList())); - } -} diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/flatten_model_predicates/PropertyValueConditionMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/flatten_model_predicates/PropertyValueConditionMixin.java deleted file mode 100644 index 80c8991d..00000000 --- a/src/main/java/org/embeddedt/modernfix/mixin/perf/flatten_model_predicates/PropertyValueConditionMixin.java +++ /dev/null @@ -1,77 +0,0 @@ -package org.embeddedt.modernfix.mixin.perf.flatten_model_predicates; - -import com.google.common.base.Splitter; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.client.renderer.block.model.multipart.KeyValueCondition; -import net.minecraft.world.level.block.state.properties.Property; -import net.minecraft.world.level.block.state.StateDefinition; -import org.embeddedt.modernfix.predicate.single.SingleMatchAny; -import org.embeddedt.modernfix.predicate.single.SingleMatchOne; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; -import org.spongepowered.asm.mixin.Shadow; - -import java.util.List; -import java.util.function.Predicate; -import java.util.stream.Collectors; - -@Mixin(KeyValueCondition.class) -public class PropertyValueConditionMixin { - @Shadow @Final private String key; - - @Shadow @Final private String value; - - @Shadow @Final private static Splitter PIPE_SPLITTER; - - /** - * @author JellySquid - * @reason De-duplication - */ - @Overwrite - public Predicate getPredicate(StateDefinition stateManager) { - Property property = stateManager.getProperty(this.key); - - if (property == null) { - throw new RuntimeException(String.format("Unknown property '%s' on '%s'", this.key, stateManager.getOwner().toString())); - } - - String valueString = this.value; - boolean negate = !valueString.isEmpty() && valueString.charAt(0) == '!'; - - if (negate) { - valueString = valueString.substring(1); - } - - List split = PIPE_SPLITTER.splitToList(valueString); - - if (split.isEmpty()) { - throw new RuntimeException(String.format("Empty value '%s' for property '%s' on '%s'", this.value, this.key, stateManager.getOwner().toString())); - } - - Predicate predicate; - - if (split.size() == 1) { - predicate = new SingleMatchOne(property, this.getPropertyValue(stateManager, property, valueString)); - } else { - predicate = SingleMatchAny.create(property, split.stream() - .map(str -> this.getPropertyValue(stateManager, property, str)) - .collect(Collectors.toList())); - } - - return negate ? predicate.negate() : predicate; - } - - private Object getPropertyValue(StateDefinition stateFactory, Property property, String valueString) { - Object value = property.getValue(valueString) - .orElse(null); - - if (value == null) { - throw new RuntimeException(String.format("Unknown value '%s' for property '%s' on '%s' in '%s'", - valueString, this.key, stateFactory.getOwner().toString(), this.value)); - } - - return value; - } -} diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/preload_block_classes/GameDataMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/preload_block_classes/GameDataMixin.java deleted file mode 100644 index 5f519ffc..00000000 --- a/src/main/java/org/embeddedt/modernfix/mixin/perf/preload_block_classes/GameDataMixin.java +++ /dev/null @@ -1,20 +0,0 @@ -package org.embeddedt.modernfix.mixin.perf.preload_block_classes; - -import net.minecraftforge.fml.ModLoadingStage; -import net.minecraftforge.registries.GameData; -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.CallbackInfoReturnable; - -import java.util.stream.Stream; - -import org.embeddedt.modernfix.util.BlockClassPreloader; - -@Mixin(GameData.class) -public class GameDataMixin { - @Inject(method = "generateRegistryEvents", at = @At("RETURN"), remap = false) - private static void preloadBlockClasses(CallbackInfoReturnable>> cir) { - BlockClassPreloader.preloadClasses(); - } -} diff --git a/src/main/java/org/embeddedt/modernfix/predicate/AllPredicate.java b/src/main/java/org/embeddedt/modernfix/predicate/AllPredicate.java deleted file mode 100644 index e741e58a..00000000 --- a/src/main/java/org/embeddedt/modernfix/predicate/AllPredicate.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.embeddedt.modernfix.predicate; - -import java.util.function.Predicate; - -public class AllPredicate implements Predicate { - private final Predicate[] predicates; - - public AllPredicate(Predicate[] predicates) { - this.predicates = predicates; - } - - @Override - public boolean test(T t) { - for (Predicate predicate : this.predicates) { - if (!predicate.test(t)) { - return false; - } - } - - return true; - } -} diff --git a/src/main/java/org/embeddedt/modernfix/predicate/AnyPredicate.java b/src/main/java/org/embeddedt/modernfix/predicate/AnyPredicate.java deleted file mode 100644 index 7c04f5fb..00000000 --- a/src/main/java/org/embeddedt/modernfix/predicate/AnyPredicate.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.embeddedt.modernfix.predicate; - -import java.util.function.Predicate; - -public class AnyPredicate implements Predicate { - private final Predicate[] predicates; - - public AnyPredicate(Predicate[] predicates) { - this.predicates = predicates; - } - - @Override - public boolean test(T t) { - for (Predicate predicate : this.predicates) { - if (predicate.test(t)) { - return true; - } - } - - return false; - } -} diff --git a/src/main/java/org/embeddedt/modernfix/predicate/CachedModelPredicate.java b/src/main/java/org/embeddedt/modernfix/predicate/CachedModelPredicate.java deleted file mode 100644 index 8c5a4566..00000000 --- a/src/main/java/org/embeddedt/modernfix/predicate/CachedModelPredicate.java +++ /dev/null @@ -1,7 +0,0 @@ -package org.embeddedt.modernfix.predicate; - -/** - * Calculates the - */ -public class CachedModelPredicate { -} diff --git a/src/main/java/org/embeddedt/modernfix/predicate/StatePropertyPredicateHelper.java b/src/main/java/org/embeddedt/modernfix/predicate/StatePropertyPredicateHelper.java deleted file mode 100644 index 8125e307..00000000 --- a/src/main/java/org/embeddedt/modernfix/predicate/StatePropertyPredicateHelper.java +++ /dev/null @@ -1,33 +0,0 @@ -package org.embeddedt.modernfix.predicate; - -import net.minecraft.world.level.block.state.BlockState; -import org.embeddedt.modernfix.predicate.all.AllMatchOneBoolean; -import org.embeddedt.modernfix.predicate.all.AllMatchOneObject; -import org.embeddedt.modernfix.predicate.any.AllMatchAnyObject; -import org.embeddedt.modernfix.predicate.single.SingleMatchAny; -import org.embeddedt.modernfix.predicate.single.SingleMatchOne; - -import java.util.List; -import java.util.function.Predicate; - -public class StatePropertyPredicateHelper { - @SuppressWarnings("unchecked") - public static Predicate allMatch(List> predicates) { - if (SingleMatchOne.areOfType(predicates)) { - if (SingleMatchOne.valuesMatchType(predicates, Boolean.class)) { - return new AllMatchOneBoolean(predicates); - } - - return new AllMatchOneObject(predicates); - } else if (SingleMatchAny.areOfType(predicates)) { - return new AllMatchAnyObject(predicates); - } - - return new AllPredicate<>(predicates.toArray(new Predicate[0])); - } - - @SuppressWarnings("unchecked") - public static Predicate anyMatch(List> predicates) { - return new AnyPredicate<>(predicates.toArray(new Predicate[0])); - } -} diff --git a/src/main/java/org/embeddedt/modernfix/predicate/all/AllMatchOneBoolean.java b/src/main/java/org/embeddedt/modernfix/predicate/all/AllMatchOneBoolean.java deleted file mode 100644 index 06984eb1..00000000 --- a/src/main/java/org/embeddedt/modernfix/predicate/all/AllMatchOneBoolean.java +++ /dev/null @@ -1,47 +0,0 @@ -package org.embeddedt.modernfix.predicate.all; - -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.Property; -import org.embeddedt.modernfix.predicate.single.SingleMatchOne; - -import java.util.List; -import java.util.function.Predicate; - -public class AllMatchOneBoolean implements Predicate { - private final Property[] properties; - private final boolean[] values; - - public AllMatchOneBoolean(List> list) { - int size = list.size(); - - this.properties = new Property[size]; - this.values = new boolean[size]; - - for (int i = 0; i < size; i++) { - SingleMatchOne predicate = (SingleMatchOne) list.get(i); - - this.properties[i] = predicate.property; - this.values[i] = (boolean) predicate.value; - } - } - - public static boolean canReplace(List> list) { - return list.stream() - .allMatch(p -> { - return p instanceof SingleMatchOne && ((SingleMatchOne) p).value instanceof Boolean; - }); - } - - @Override - public boolean test(BlockState blockState) { - for (int i = 0; i < this.properties.length; i++) { - Boolean value = (Boolean) blockState.getValue(this.properties[i]); - - if (value != this.values[i]) { - return false; - } - } - - return true; - } -} diff --git a/src/main/java/org/embeddedt/modernfix/predicate/all/AllMatchOneObject.java b/src/main/java/org/embeddedt/modernfix/predicate/all/AllMatchOneObject.java deleted file mode 100644 index 5a90591b..00000000 --- a/src/main/java/org/embeddedt/modernfix/predicate/all/AllMatchOneObject.java +++ /dev/null @@ -1,38 +0,0 @@ -package org.embeddedt.modernfix.predicate.all; - -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.Property; -import org.embeddedt.modernfix.predicate.single.SingleMatchOne; - -import java.util.List; -import java.util.function.Predicate; - -public class AllMatchOneObject implements Predicate { - private final Property[] properties; - private final Object[] values; - - public AllMatchOneObject(List> list) { - int size = list.size(); - - this.properties = new Property[size]; - this.values = new Object[size]; - - for (int i = 0; i < size; i++) { - SingleMatchOne predicate = (SingleMatchOne) list.get(i); - - this.properties[i] = predicate.property; - this.values[i] = predicate.value; - } - } - - @Override - public boolean test(BlockState blockState) { - for (int i = 0; i < this.properties.length; i++) { - if (blockState.getValue(this.properties[i]) != this.values[i]) { - return false; - } - } - - return true; - } -} diff --git a/src/main/java/org/embeddedt/modernfix/predicate/any/AllMatchAnyObject.java b/src/main/java/org/embeddedt/modernfix/predicate/any/AllMatchAnyObject.java deleted file mode 100644 index f9585376..00000000 --- a/src/main/java/org/embeddedt/modernfix/predicate/any/AllMatchAnyObject.java +++ /dev/null @@ -1,39 +0,0 @@ -package org.embeddedt.modernfix.predicate.any; - -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.Property; -import org.apache.commons.lang3.ArrayUtils; -import org.embeddedt.modernfix.predicate.single.SingleMatchAny; - -import java.util.List; -import java.util.function.Predicate; - -public class AllMatchAnyObject implements Predicate { - private final Property[] properties; - private final Object[][] values; - - public AllMatchAnyObject(List> list) { - int size = list.size(); - - this.properties = new Property[size]; - this.values = new Object[size][]; - - for (int i = 0; i < size; i++) { - SingleMatchAny predicate = (SingleMatchAny) list.get(i); - - this.properties[i] = predicate.property; - this.values[i] = predicate.values; - } - } - - @Override - public boolean test(BlockState blockState) { - for (int i = 0; i < this.properties.length; i++) { - if (!ArrayUtils.contains(this.values[i], blockState.getValue(this.properties[i]))) { - return false; - } - } - - return true; - } -} diff --git a/src/main/java/org/embeddedt/modernfix/predicate/single/SingleMatchAny.java b/src/main/java/org/embeddedt/modernfix/predicate/single/SingleMatchAny.java deleted file mode 100644 index 1c7906e9..00000000 --- a/src/main/java/org/embeddedt/modernfix/predicate/single/SingleMatchAny.java +++ /dev/null @@ -1,63 +0,0 @@ -package org.embeddedt.modernfix.predicate.single; - -import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.Property; -import org.apache.commons.lang3.ArrayUtils; - -import java.util.Arrays; -import java.util.List; -import java.util.Objects; -import java.util.function.Predicate; - -public class SingleMatchAny implements Predicate { - public static final ObjectOpenHashSet PREDICATES = new ObjectOpenHashSet<>(); - - public final Property property; - public final Object[] values; - - private SingleMatchAny(Property property, List values) { - this.property = property; - this.values = values.toArray(); - } - - public static SingleMatchAny create(Property property, List values) { - return PREDICATES.addOrGet(new SingleMatchAny(property, values)); - } - - public static boolean areOfType(List> predicates) { - return predicates.stream() - .allMatch(p -> { - return p instanceof SingleMatchAny; - }); - } - - public static boolean valuesMatchType(List> predicates, Class type) { - return predicates.stream() - .allMatch(p -> { - return p instanceof SingleMatchAny && - Arrays.stream(((SingleMatchAny) p).values).allMatch(t -> type.isInstance(p)); - }); - } - - @Override - public boolean test(BlockState blockState) { - return ArrayUtils.contains(this.values, blockState.getValue(this.property)); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - SingleMatchAny that = (SingleMatchAny) o; - return Objects.equals(property, that.property) && - Arrays.equals(values, that.values); - } - - @Override - public int hashCode() { - int result = Objects.hash(property); - result = 31 * result + Arrays.hashCode(values); - return result; - } -} diff --git a/src/main/java/org/embeddedt/modernfix/predicate/single/SingleMatchOne.java b/src/main/java/org/embeddedt/modernfix/predicate/single/SingleMatchOne.java deleted file mode 100644 index e44e0515..00000000 --- a/src/main/java/org/embeddedt/modernfix/predicate/single/SingleMatchOne.java +++ /dev/null @@ -1,36 +0,0 @@ -package org.embeddedt.modernfix.predicate.single; - -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.Property; - -import java.util.List; -import java.util.function.Predicate; - -public class SingleMatchOne implements Predicate { - public final Property property; - public final Object value; - - public SingleMatchOne(Property property, Object value) { - this.property = property; - this.value = value; - } - - public static boolean areOfType(List> predicates) { - return predicates.stream() - .allMatch(p -> { - return p instanceof SingleMatchOne; - }); - } - - public static boolean valuesMatchType(List> predicates, Class type) { - return predicates.stream() - .allMatch(p -> { - return p instanceof SingleMatchOne && type.isInstance(((SingleMatchOne) p).value); - }); - } - - @Override - public boolean test(BlockState blockState) { - return blockState.getValue(this.property) == this.value; - } -} diff --git a/src/main/java/org/embeddedt/modernfix/registry/DeferredRegisterBaker.java b/src/main/java/org/embeddedt/modernfix/registry/DeferredRegisterBaker.java deleted file mode 100644 index be78ace2..00000000 --- a/src/main/java/org/embeddedt/modernfix/registry/DeferredRegisterBaker.java +++ /dev/null @@ -1,59 +0,0 @@ -package org.embeddedt.modernfix.registry; - -import com.google.common.base.Stopwatch; -import net.minecraft.resources.ResourceLocation; -import net.minecraftforge.fml.ModWorkManager; -import org.embeddedt.modernfix.ModernFix; -import org.embeddedt.modernfix.util.AsyncStopwatch; -import org.embeddedt.modernfix.util.CachedSupplier; -import org.embeddedt.modernfix.util.OrderedParallelModDispatcher; - -import java.util.*; -import java.util.concurrent.TimeUnit; -import java.util.function.Supplier; - -public class DeferredRegisterBaker { - private static final HashMap>>> supplierMap = new HashMap<>(); - public static Supplier cacheForComputationLater(ResourceLocation registry, String modid, Supplier supplier) { - synchronized (supplierMap) { - HashMap>> registrySupplierMap = supplierMap.computeIfAbsent(registry, reg -> new HashMap<>()); - List> modSupplierList = registrySupplierMap.computeIfAbsent(modid, id -> new ArrayList<>()); - CachedSupplier cacher = new CachedSupplier<>(supplier); - modSupplierList.add(cacher); - return cacher; - } - } - - public static void bakeSuppliers(ResourceLocation registry) { - synchronized (supplierMap) { - Set modErrors = Collections.synchronizedSet(new HashSet<>()); - HashMap>> registrySupplierMap = supplierMap.get(registry); - if(registrySupplierMap == null) - return; - ModernFix.LOGGER.info("Caching suppliers for " + registry); - Stopwatch realtimeStopwatch = Stopwatch.createStarted(); - AsyncStopwatch cpuStopwatch = new AsyncStopwatch(); - OrderedParallelModDispatcher.dispatchBlocking(ModWorkManager.parallelExecutor(), modId -> { - List> suppliersToCompute = registrySupplierMap.get(modId); - if (suppliersToCompute == null || suppliersToCompute.size() == 0) { - return; - } - cpuStopwatch.startMeasuringAsync(); - for (CachedSupplier supplier : suppliersToCompute) { - try { - supplier.compute(); - } catch(RuntimeException e) { - ModernFix.LOGGER.debug("Exception encountered while caching supplier", e); - modErrors.add(modId); - } - } - cpuStopwatch.stopMeasuringAsync(); - }); - realtimeStopwatch.stop(); - if(modErrors.size() > 0) - ModernFix.LOGGER.warn("The following mods had errors while caching " + registry + " suppliers (this is likely safe): [" + String.join(", ", modErrors) + "]"); - ModernFix.LOGGER.info("CPU time spent constructing " + registry + " suppliers: " + cpuStopwatch.getCpuTime()/1000f + " seconds"); - ModernFix.LOGGER.info("Real time spent constructing " + registry + " suppliers: " + realtimeStopwatch.elapsed(TimeUnit.MILLISECONDS)/1000f + " seconds"); - } - } -} diff --git a/src/main/java/org/embeddedt/modernfix/screen/DeferredLevelLoadingScreen.java b/src/main/java/org/embeddedt/modernfix/screen/DeferredLevelLoadingScreen.java deleted file mode 100644 index cd49687a..00000000 --- a/src/main/java/org/embeddedt/modernfix/screen/DeferredLevelLoadingScreen.java +++ /dev/null @@ -1,27 +0,0 @@ -package org.embeddedt.modernfix.screen; - -import com.mojang.blaze3d.vertex.PoseStack; -import net.minecraft.client.gui.screens.LevelLoadingScreen; -import net.minecraft.server.level.progress.StoringChunkProgressListener; - -import java.util.function.BooleanSupplier; - -public class DeferredLevelLoadingScreen extends LevelLoadingScreen { - private final BooleanSupplier worldLoadFinished; - public DeferredLevelLoadingScreen(StoringChunkProgressListener arg, BooleanSupplier worldLoadFinished) { - super(arg); - this.worldLoadFinished = worldLoadFinished; - } - - @Override - public void tick() { - super.tick(); - if(this.worldLoadFinished.getAsBoolean()) - this.onClose(); - } - - @Override - public void renderBackground(PoseStack matrixStack, int vOffset) { - renderDirtBackground(vOffset); - } -} diff --git a/src/main/java/org/embeddedt/modernfix/util/AsyncStopwatch.java b/src/main/java/org/embeddedt/modernfix/util/AsyncStopwatch.java deleted file mode 100644 index a45db852..00000000 --- a/src/main/java/org/embeddedt/modernfix/util/AsyncStopwatch.java +++ /dev/null @@ -1,45 +0,0 @@ -package org.embeddedt.modernfix.util; - -import com.google.common.base.Stopwatch; -import org.embeddedt.modernfix.ModernFix; - -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicLong; - -public class AsyncStopwatch { - private final AtomicLong cpuTimeMs = new AtomicLong(0); - private final ThreadLocal threadStopwatch = ThreadLocal.withInitial(Stopwatch::createUnstarted); - - public void startMeasuringAsync() { - threadStopwatch.get().start(); - } - - public void stopMeasuringAsync() { - Stopwatch watch = threadStopwatch.get(); - watch.stop(); - long elapsed = watch.elapsed(TimeUnit.MILLISECONDS); - cpuTimeMs.addAndGet(elapsed); - watch.reset(); - } - - public void ensureStoppedAsync() { - Stopwatch watch = threadStopwatch.get(); - if(watch.isRunning()) - stopMeasuringAsync(); - } - - public long getCpuTime() { - return cpuTimeMs.get(); - } - - public static void measureAndLogSerialRunningTime(String label, Runnable runnable) { - ModernFix.LOGGER.info(label + "..."); - Stopwatch stopwatch = Stopwatch.createStarted(); - try { - runnable.run(); - ModernFix.LOGGER.info(label + " took " + stopwatch.elapsed(TimeUnit.MILLISECONDS)/1000f + " seconds"); - } finally { - stopwatch.stop(); - } - } -} diff --git a/src/main/java/org/embeddedt/modernfix/util/BlockClassPreloader.java b/src/main/java/org/embeddedt/modernfix/util/BlockClassPreloader.java deleted file mode 100644 index 140de108..00000000 --- a/src/main/java/org/embeddedt/modernfix/util/BlockClassPreloader.java +++ /dev/null @@ -1,90 +0,0 @@ -package org.embeddedt.modernfix.util; - -import com.google.common.base.Stopwatch; -import net.minecraft.world.level.block.state.BlockBehaviour; -import net.minecraft.world.level.block.Block; -import net.minecraftforge.fml.ModList; -import net.minecraftforge.fml.ModWorkManager; -import net.minecraftforge.fml.loading.moddiscovery.ModFile; -import net.minecraftforge.fml.loading.moddiscovery.ModFileInfo; -import net.minecraftforge.forgespi.language.ModFileScanData; -import org.embeddedt.modernfix.ModernFix; -import org.objectweb.asm.Type; - -import java.lang.reflect.Field; -import java.util.*; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; - -public class BlockClassPreloader { - public static void preloadClasses() { - Stopwatch stopwatch = Stopwatch.createStarted(); - ModernFix.LOGGER.warn("Preparing to preload classes..."); - HashMap isABlockClass = new HashMap<>(); - isABlockClass.put(Type.getType(BlockBehaviour.class), true); - isABlockClass.put(Type.getType(Block.class), true); - Field selfField, parentField; - List futures = new ArrayList<>(); - try { - selfField = ModFileScanData.ClassData.class.getDeclaredField("clazz"); - selfField.setAccessible(true); - parentField = ModFileScanData.ClassData.class.getDeclaredField("parent"); - parentField.setAccessible(true); - List currentCandidates = ModList.get().getModFiles().stream() - .map(ModFileInfo::getFile) - .map(ModFile::getScanResult) - .flatMap(data -> data.getClasses().stream()) - .collect(Collectors.toList()); - HashSet blockClasses = new HashSet<>(); - blockClasses.add(Type.getType(BlockBehaviour.class)); - HashSet nonBlockClasses = new HashSet<>(); - int previousSize = -1; - nonBlockClasses.add(Type.getType(Object.class)); - currentCandidates.removeIf(clz -> { - Type self; - try { - self = (Type)selfField.get(clz); - } catch(ReflectiveOperationException e) { - throw new RuntimeException(e); - } - return (nonBlockClasses.contains(self) || blockClasses.contains(self)); - }); - while(blockClasses.size() > previousSize && currentCandidates.size() > 0) { - previousSize = blockClasses.size(); - currentCandidates.removeIf(clz -> { - Type parent, self; - try { - parent = (Type)parentField.get(clz); - self = (Type)selfField.get(clz); - } catch(ReflectiveOperationException e) { - throw new RuntimeException(e); - } - if(nonBlockClasses.contains(parent)) { - nonBlockClasses.add(self); - return true; - } else if(blockClasses.contains(parent)) { - blockClasses.add(self); - futures.add(CompletableFuture.runAsync(() -> { - if(self.getClassName().toLowerCase(Locale.ROOT).contains("mixin")) - return; - try { - Class.forName(self.getClassName()); - } catch(Throwable e) { - ModernFix.LOGGER.warn("Couldn't load " + self.getClassName(), e); - } - }, ModWorkManager.parallelExecutor())); - return true; - } else - return false; - }); - } - futures.forEach(CompletableFuture::join); - } catch(ReflectiveOperationException e) { - throw new RuntimeException(e); - } finally { - ModernFix.LOGGER.warn("Preloading classes took " + stopwatch.elapsed(TimeUnit.MILLISECONDS)/1000f + " seconds"); - stopwatch.stop(); - } - } -} diff --git a/src/main/java/org/embeddedt/modernfix/util/CachedSupplier.java b/src/main/java/org/embeddedt/modernfix/util/CachedSupplier.java deleted file mode 100644 index 50b2303d..00000000 --- a/src/main/java/org/embeddedt/modernfix/util/CachedSupplier.java +++ /dev/null @@ -1,33 +0,0 @@ -package org.embeddedt.modernfix.util; - -import java.util.function.Supplier; - -/** - * An implementation of Supplier that allows separating the time at which the value is computed from when it is - * retrieved. - */ -public class CachedSupplier implements Supplier { - private T value = null; - - private boolean hasBeenComputed; - private final Supplier delegate; - - public CachedSupplier(Supplier delegate) { - this.delegate = delegate; - } - - public synchronized void compute() { - this.value = this.delegate.get(); - this.hasBeenComputed = true; - } - - @Override - public synchronized T get() { - if(this.hasBeenComputed) { - this.hasBeenComputed = false; - return this.value; - } else { - return this.delegate.get(); - } - } -} diff --git a/src/main/java/org/embeddedt/modernfix/util/JEIUtil.java b/src/main/java/org/embeddedt/modernfix/util/JEIUtil.java index 59e6b244..ac90c3d2 100644 --- a/src/main/java/org/embeddedt/modernfix/util/JEIUtil.java +++ b/src/main/java/org/embeddedt/modernfix/util/JEIUtil.java @@ -10,7 +10,6 @@ import net.minecraft.network.chat.TranslatableComponent; import net.minecraftforge.client.event.GuiScreenEvent; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.eventbus.api.SubscribeEvent; -import org.embeddedt.modernfix.screen.DeferredLevelLoadingScreen; import java.util.function.Supplier; @@ -25,7 +24,7 @@ public class JEIUtil { @SubscribeEvent public static void renderLoad(GuiScreenEvent.DrawScreenEvent.Post event) { /* Don't show the JEI indicator on the level loading screen, that looks weird */ - if(isLoading.get() && !(event.getGui() instanceof DeferredLevelLoadingScreen)) { + if(isLoading.get()) { Gui.drawString(new PoseStack(), Minecraft.getInstance().font, new TranslatableComponent("modernfix.jei_load"), 0, 0, 0xffffff); } } diff --git a/src/main/java/org/embeddedt/modernfix/util/OrderedParallelModDispatcher.java b/src/main/java/org/embeddedt/modernfix/util/OrderedParallelModDispatcher.java deleted file mode 100644 index a08754fe..00000000 --- a/src/main/java/org/embeddedt/modernfix/util/OrderedParallelModDispatcher.java +++ /dev/null @@ -1,97 +0,0 @@ -package org.embeddedt.modernfix.util; - -import com.google.common.base.Preconditions; -import com.google.common.base.Stopwatch; -import net.minecraftforge.fml.ModContainer; -import net.minecraftforge.fml.ModList; -import net.minecraftforge.fml.ModLoadingContext; -import net.minecraftforge.fml.ModWorkManager; -import net.minecraftforge.fml.common.ObfuscationReflectionHelper; -import net.minecraftforge.fml.loading.moddiscovery.ModInfo; -import net.minecraftforge.forgespi.language.IModInfo; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.apache.logging.log4j.Marker; -import org.apache.logging.log4j.MarkerManager; -import org.embeddedt.modernfix.ModernFix; - -import java.util.*; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Executor; -import java.util.concurrent.Semaphore; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicLong; -import java.util.function.Consumer; -import java.util.function.Supplier; -import java.util.stream.Collectors; - -/** - * Iterates over all mods in the game, parallelizing where possible while preserving dependency ordering. - * - * Can also be given a list of mods to skip. - */ -public class OrderedParallelModDispatcher { - private static final Marker DISPATCHER = MarkerManager.getMarker("OrderedParallelModDispatcher"); - public static void dispatchBlocking(Executor executor, Consumer task, Collection modIDsToFilter) { - Set finishedMods = Collections.synchronizedSet(new HashSet<>(modIDsToFilter)); - HashMap> submittedFutures = new HashMap<>(); - Semaphore jobWaitingSemaphore = new Semaphore(0); - ArrayList remainingModList = new ArrayList<>(ModList.get().getMods()); - while(remainingModList.size() > 0) { - remainingModList.removeIf(modInfo -> { - if(finishedMods.contains(modInfo.getModId())) - return true; - List missingDependencies = modInfo.getDependencies().stream() - .filter(IModInfo.ModVersion::isMandatory) - .map(IModInfo.ModVersion::getModId) - .filter(modId -> !finishedMods.contains(modId)) - .collect(Collectors.toList()); - if(missingDependencies.size() > 0) { - ModernFix.LOGGER.debug(DISPATCHER, "Cannot process " + modInfo.getModId() + ", as it is waiting on mods: [" + String.join(", ", missingDependencies) + "]"); - return false; - } - Optional modContainerOpt = ModList.get().getModContainerById(modInfo.getModId()); - if(!modContainerOpt.isPresent()) - throw new IllegalStateException("Can't find mod container"); - ModContainer container = modContainerOpt.get(); - ModernFix.LOGGER.debug(DISPATCHER, "Submitting job for " + modInfo.getModId()); - submittedFutures.put(modInfo.getModId(), CompletableFuture.runAsync(() -> { - Supplier contextExtension = ObfuscationReflectionHelper.getPrivateValue(ModContainer.class, container, "contextExtension"); - ModLoadingContext.get().setActiveContainer(container, contextExtension.get()); - try { - task.accept(modInfo.getModId()); - } catch(RuntimeException e) { - e.printStackTrace(); - } - /* - * We cannot rely on the main thread to correctly mark us as done, as it might start running - * before the future is marked as complete. So we add the mod to the finished set ourselves. - */ - finishedMods.add(modInfo.getModId()); - jobWaitingSemaphore.release(); - //ModLoadingContext.get().setActiveContainer(null, null); - }, executor)); - return true; - }); - Preconditions.checkState(submittedFutures.size() > 0, "The semaphore will block forever!"); - ModernFix.LOGGER.debug(DISPATCHER, "Waiting for one of [" + String.join(", ", submittedFutures.keySet()) + "] to finish..."); - try { - jobWaitingSemaphore.acquire(); - } catch(InterruptedException e) { - throw new RuntimeException("Unexpected interruption", e); - } - submittedFutures.entrySet().removeIf(entry -> { - if(entry.getValue().isDone()) { - ModernFix.LOGGER.debug(DISPATCHER, "Job finished for " + entry.getKey()); - return true; - } - return false; - }); - } - submittedFutures.values().forEach(CompletableFuture::join); - } - - public static void dispatchBlocking(Executor executor, Consumer task) { - dispatchBlocking(executor, task, Collections.emptyList()); - } -} diff --git a/src/main/resources/modernfix.mixins.json b/src/main/resources/modernfix.mixins.json index 776cbbbf..5be112b9 100644 --- a/src/main/resources/modernfix.mixins.json +++ b/src/main/resources/modernfix.mixins.json @@ -27,7 +27,6 @@ "perf.skip_first_datapack_reload.SaveFormatAccessor", "perf.boost_worker_count.UtilMixin", "perf.thread_priorities.UtilMixin", - "perf.preload_block_classes.GameDataMixin", "perf.reduce_blockstate_cache_rebuilds.GameDataMixin", "perf.reduce_blockstate_cache_rebuilds.BlockCallbacksMixin", "perf.reduce_blockstate_cache_rebuilds.BlocksMixin", @@ -104,9 +103,6 @@ "perf.thread_priorities.IntegratedServerMixin", "safety.BlockColorsMixin", "safety.ItemColorsMixin", - "perf.flatten_model_predicates.AndConditionMixin", - "perf.flatten_model_predicates.OrConditionMixin", - "perf.flatten_model_predicates.PropertyValueConditionMixin", "perf.blast_search_trees.MinecraftMixin", "perf.blast_search_trees.IngredientFilterInvoker", "perf.cache_model_materials.VanillaModelMixin", @@ -121,7 +117,6 @@ "perf.use_integrated_resources.jepb.PiglinBarteringRecipeBuilderMixin", "perf.jeresources_startup.VillagerEntryMixin", "bugfix.mc218112.SynchedEntityDataMixin_Client", - "perf.faster_singleplayer_load.MinecraftServerMixin", "devenv.MinecraftMixin", "devenv.NarratorMixin" ],