Improve class transformer cache
This commit is contained in:
parent
95d7410722
commit
23b4652864
|
|
@ -4,8 +4,12 @@ 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;
|
||||
|
|
@ -44,6 +48,14 @@ public class ModernFixCachingClassTransformer extends ClassTransformer {
|
|||
|
||||
public static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
|
||||
|
||||
public static ThreadLocal<MessageDigest> systemHasher = ThreadLocal.withInitial(() -> {
|
||||
try {
|
||||
return MessageDigest.getInstance("SHA-256");
|
||||
} catch(NoSuchAlgorithmException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
|
||||
private static File childFile(File file) {
|
||||
file.getParentFile().mkdirs();
|
||||
return file;
|
||||
|
|
@ -82,12 +94,12 @@ public class ModernFixCachingClassTransformer extends ClassTransformer {
|
|||
}
|
||||
}
|
||||
|
||||
private ArrayList<byte[]> computeHash(String className, boolean isEmpty, String reason) {
|
||||
private ArrayList<byte[]> computeHash(String className, byte[] inputClass, String reason) {
|
||||
final String internalName = className.replace('.', '/');
|
||||
final Type classDesc = Type.getObjectType(internalName);
|
||||
ArrayList<ILaunchPluginService> pluginList = new ArrayList<>();
|
||||
for(ILaunchPluginService plugin : plugins.values()) {
|
||||
if(!plugin.handlesClass(classDesc, isEmpty, reason).isEmpty()) {
|
||||
if(!plugin.handlesClass(classDesc, inputClass.length == 0, reason).isEmpty()) {
|
||||
pluginList.add(plugin);
|
||||
}
|
||||
}
|
||||
|
|
@ -117,6 +129,10 @@ public class ModernFixCachingClassTransformer extends ClassTransformer {
|
|||
}
|
||||
}
|
||||
}
|
||||
/* 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;
|
||||
}
|
||||
|
||||
|
|
@ -132,42 +148,52 @@ public class ModernFixCachingClassTransformer extends ClassTransformer {
|
|||
public byte[] transform(byte[] inputClass, String className, String reason) {
|
||||
/* We only want to cache actual transformations */
|
||||
if(ITransformerActivity.CLASSLOADING_REASON.equals(reason)) {
|
||||
ArrayList<byte[]> hashList = computeHash(className, inputClass.length == 0, reason);
|
||||
if(hashList != null) {
|
||||
/* 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('.', '/'));
|
||||
boolean hashesMatch = true;
|
||||
try(ObjectInputStream stream = new ObjectInputStream(new FileInputStream(cacheLocation))) {
|
||||
ArrayList<byte[]> savedHash = (ArrayList<byte[]>)stream.readObject();
|
||||
final byte[] classToHash = inputClass;
|
||||
CompletableFuture<ArrayList<byte[]>> futureHashList = CompletableFuture.supplyAsync(() -> computeHash(className, classToHash, reason), ForkJoinPool.commonPool());
|
||||
ArrayList<byte[]> hashList = null;
|
||||
/* 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('.', '/'));
|
||||
boolean hashesMatch = true;
|
||||
try(ObjectInputStream stream = new ObjectInputStream(new FileInputStream(cacheLocation))) {
|
||||
ArrayList<byte[]> savedHash = (ArrayList<byte[]>)stream.readObject();
|
||||
byte[] savedInputClass = (byte[])stream.readObject();
|
||||
hashList = futureHashList.get();
|
||||
if(hashList != null) {
|
||||
for(int i = 0; i < savedHash.size(); i++) {
|
||||
if(!Arrays.equals(savedHash.get(i), hashList.get(i))) {
|
||||
hashesMatch = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(hashesMatch)
|
||||
inputClass = (byte[])stream.readObject();
|
||||
} catch(IOException | ClassNotFoundException | ClassCastException e) {
|
||||
if(!(e instanceof FileNotFoundException))
|
||||
e.printStackTrace();
|
||||
} else
|
||||
hashesMatch = false;
|
||||
}
|
||||
if(!hashesMatch) {
|
||||
inputClass = super.transform(inputClass, className, reason);
|
||||
if(hashesMatch)
|
||||
inputClass = savedInputClass;
|
||||
} catch(IOException | ClassNotFoundException | ClassCastException | InterruptedException |
|
||||
ExecutionException 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<byte[]> hashListToSave = hashList;
|
||||
classSaverPool.submit(() -> {
|
||||
cacheLocation.getParentFile().mkdirs();
|
||||
try(ObjectOutputStream stream = new ObjectOutputStream(new FileOutputStream(cacheLocation))) {
|
||||
stream.writeObject(hashList);
|
||||
stream.writeObject(hashListToSave);
|
||||
stream.writeObject(classToSave);
|
||||
} catch(IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
return inputClass;
|
||||
|
||||
}
|
||||
return inputClass;
|
||||
}
|
||||
return super.transform(inputClass, className, reason);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package org.embeddedt.modernfix.classloading.hashers;
|
||||
|
||||
import cpw.mods.modlauncher.ModernFixCachingClassTransformer;
|
||||
import net.minecraftforge.coremod.CoreMod;
|
||||
import net.minecraftforge.coremod.transformer.CoreModBaseTransformer;
|
||||
|
||||
|
|
@ -13,13 +14,6 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||
public class CoreModTransformerHasher {
|
||||
private static final ConcurrentHashMap<CoreMod, byte[]> hashForCoremod;
|
||||
private static Field coremodField;
|
||||
private static ThreadLocal<MessageDigest> coremodHasher = ThreadLocal.withInitial(() -> {
|
||||
try {
|
||||
return MessageDigest.getInstance("SHA-256");
|
||||
} catch(NoSuchAlgorithmException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
|
||||
static {
|
||||
hashForCoremod = new ConcurrentHashMap<>();
|
||||
|
|
@ -38,10 +32,9 @@ public class CoreModTransformerHasher {
|
|||
} catch(IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
MessageDigest hasher = coremodHasher.get();
|
||||
byte[] hash = hasher.digest(coreModContents);
|
||||
MessageDigest hasher = ModernFixCachingClassTransformer.systemHasher.get();
|
||||
hasher.reset();
|
||||
return hash;
|
||||
return hasher.digest(coreModContents);
|
||||
}
|
||||
|
||||
public static byte[] obtainHash(CoreModBaseTransformer<?> transformer) {
|
||||
|
|
|
|||
|
|
@ -1,12 +1,11 @@
|
|||
package org.embeddedt.modernfix.classloading.hashers;
|
||||
|
||||
import com.google.common.collect.HashMultimap;
|
||||
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.service.MixinService;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
|
|
@ -19,6 +18,10 @@ public class MixinTransformerHasher {
|
|||
private static HashMap<String, byte[]> hashesByClass = null;
|
||||
private final static MessageDigest hasher;
|
||||
|
||||
private static Field processorsListField, transformerField, processorField, environmentField;
|
||||
|
||||
private static final byte[] NO_MIXINS = new byte[] {(byte)0xde, (byte)0xad, (byte)0xbe, (byte)0xef};
|
||||
|
||||
static {
|
||||
try {
|
||||
hasher = MessageDigest.getInstance("SHA-256");
|
||||
|
|
@ -31,12 +34,12 @@ public class MixinTransformerHasher {
|
|||
/* FIXME runs too early right now, and therefore doesn't pick up the list of mixins correctly */
|
||||
synchronized (MixinTransformerHasher.class) {
|
||||
if(hashesByClass == null) {
|
||||
hashesByClass = new HashMap<>();
|
||||
HashMap<String, ArrayList<IMixinInfo>> mixinsByClass = new HashMap<>();
|
||||
try {
|
||||
Field processorsField = MixinLaunchPluginLegacy.class.getDeclaredField("processors");
|
||||
processorsField.setAccessible(true);
|
||||
List<IClassProcessor> processors = (List<IClassProcessor>)processorsField.get(plugin);
|
||||
if(processorsListField == null) {
|
||||
processorsListField = MixinLaunchPluginLegacy.class.getDeclaredField("processors");
|
||||
processorsListField.setAccessible(true);
|
||||
}
|
||||
List<IClassProcessor> processors = (List<IClassProcessor>) processorsListField.get(plugin);
|
||||
Object transformHandler = null;
|
||||
for(IClassProcessor processor : processors) {
|
||||
if(processor.getClass().getName().equals("org.spongepowered.asm.service.modlauncher.MixinTransformationHandler")) {
|
||||
|
|
@ -46,12 +49,24 @@ public class MixinTransformerHasher {
|
|||
}
|
||||
if(transformHandler == null)
|
||||
throw new IllegalStateException("Mixin transform handler not found");
|
||||
Field transformerField = transformHandler.getClass().getDeclaredField("transformer");
|
||||
transformerField.setAccessible(true);
|
||||
if(transformerField == null) {
|
||||
transformerField = transformHandler.getClass().getDeclaredField("transformer");
|
||||
transformerField.setAccessible(true);
|
||||
}
|
||||
Object transformer = transformerField.get(transformHandler);
|
||||
Field processorField = transformer.getClass().getDeclaredField("processor");
|
||||
processorField.setAccessible(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);
|
||||
|
|
@ -60,6 +75,7 @@ public class MixinTransformerHasher {
|
|||
/* 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<String, ArrayList<IMixinInfo>> mixinsByClass = new HashMap<>();
|
||||
for(Object config : configs) {
|
||||
List<? extends IMixinInfo> mixins = (List<? extends IMixinInfo>)mixinsField.get(config);
|
||||
for(IMixinInfo mixin : mixins) {
|
||||
|
|
@ -73,6 +89,7 @@ public class MixinTransformerHasher {
|
|||
infos.sort((info1, info2) -> Comparator.<String>naturalOrder().compare(info1.getClassName(), info2.getClassName()));
|
||||
}
|
||||
/* Now go through each class name and hash it */
|
||||
HashMap<String, byte[]> hashesByClassInit = new HashMap<>();
|
||||
for(Map.Entry<String, ArrayList<IMixinInfo>> mixinsForClass : mixinsByClass.entrySet()) {
|
||||
hasher.reset();
|
||||
for(IMixinInfo mixin : mixinsForClass.getValue()) {
|
||||
|
|
@ -87,13 +104,14 @@ public class MixinTransformerHasher {
|
|||
}
|
||||
hasher.update(bytecode);
|
||||
}
|
||||
hashesByClass.put(mixinsForClass.getKey().replace('/', '.'), hasher.digest());
|
||||
hashesByClassInit.put(mixinsForClass.getKey().replace('/', '.'), hasher.digest());
|
||||
}
|
||||
hashesByClass = hashesByClassInit;
|
||||
} catch(ReflectiveOperationException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return hashesByClass.getOrDefault(className, ModernFixCachingClassTransformer.EMPTY_BYTE_ARRAY);
|
||||
return hashesByClass.getOrDefault(className, NO_MIXINS);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,23 +59,6 @@ public class ModernFixMixinPlugin implements IMixinConfigPlugin {
|
|||
throw new IllegalStateException("Expected a TransformingClassLoader");
|
||||
}
|
||||
try {
|
||||
if(isOptionEnabled("launch.transformer_cache.ModernFixClassTransformer")) {
|
||||
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.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");
|
||||
}
|
||||
if(isOptionEnabled("launch.class_search_cache.ModernFixResourceFinder")) {
|
||||
Field resourceFinderField = TransformingClassLoader.class.getDeclaredField("resourceFinder");
|
||||
/* Construct a new list of resource finders, using similar logic to ML */
|
||||
|
|
@ -88,7 +71,7 @@ public class ModernFixMixinPlugin implements IMixinConfigPlugin {
|
|||
resourceFinder = EnumerationHelper.mergeFunctors(resourceFinder, LamdbaExceptionUtils.rethrowFunction(dcl::findResources));
|
||||
resourceFinderField.set(loader, resourceFinder);
|
||||
}
|
||||
} catch(RuntimeException | ReflectiveOperationException | IOException e) {
|
||||
} catch(RuntimeException | ReflectiveOperationException e) {
|
||||
logger.error("Failed to make classloading changes", e);
|
||||
}
|
||||
}
|
||||
|
|
@ -127,7 +110,28 @@ 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.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
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ public class ModernFixEarlyConfig {
|
|||
this.addMixinRule("perf.async_jei", true);
|
||||
this.addMixinRule("perf.thread_priorities", true);
|
||||
this.addMixinRule("perf.preload_block_classes", false);
|
||||
this.addMixinRule("perf.parallel_potentially_unsafe", false);
|
||||
this.addMixinRule("perf.defer_voxelshape_optimize", false);
|
||||
this.addMixinRule("perf.parallel_blockstate_cache_rebuild", true);
|
||||
this.addMixinRule("perf.deduplicate_location", true);
|
||||
this.addMixinRule("safety", true);
|
||||
|
|
|
|||
|
|
@ -1,27 +0,0 @@
|
|||
package org.embeddedt.modernfix.mixin.perf.parallel_potentially_unsafe.parallel_deferred_suppliers;
|
||||
|
||||
import net.minecraftforge.registries.DeferredRegister;
|
||||
import net.minecraftforge.registries.IForgeRegistry;
|
||||
import org.embeddedt.modernfix.registry.DeferredRegisterBaker;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
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.ModifyArg;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@Mixin(DeferredRegister.class)
|
||||
public class DeferredRegisterMixin {
|
||||
@Shadow(remap = false) private IForgeRegistry type;
|
||||
|
||||
@Shadow(remap = false) @Final private String modid;
|
||||
|
||||
@ModifyArg(method = "register(Ljava/lang/String;Ljava/util/function/Supplier;)Lnet/minecraftforge/fml/RegistryObject;", at = @At(value = "INVOKE", target = "Ljava/util/Map;putIfAbsent(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"), index = 1, remap = false)
|
||||
private Object swapForCachedSupplier(Object original) {
|
||||
if(this.type != null)
|
||||
return DeferredRegisterBaker.cacheForComputationLater(this.type.getRegistryName(), this.modid, (Supplier<?>)original);
|
||||
else
|
||||
return original;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
package org.embeddedt.modernfix.mixin.perf.parallel_potentially_unsafe.parallel_deferred_suppliers;
|
||||
|
||||
import net.minecraft.block.DispenserBlock;
|
||||
import net.minecraft.dispenser.IDispenseItemBehavior;
|
||||
import net.minecraft.item.Item;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
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.callback.CallbackInfo;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
@Mixin(DispenserBlock.class)
|
||||
public class DispenserBlockMixin {
|
||||
@Shadow private static Map<Item, IDispenseItemBehavior> DISPENSER_REGISTRY;
|
||||
|
||||
@Inject(method = "<clinit>", at = @At("TAIL"))
|
||||
private static void makeMapConcurrent(CallbackInfo ci) {
|
||||
DISPENSER_REGISTRY = new ConcurrentHashMap<>();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
package org.embeddedt.modernfix.mixin.perf.parallel_potentially_unsafe.parallel_deferred_suppliers;
|
||||
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.event.RegistryEvent;
|
||||
import net.minecraftforge.registries.DeferredRegister;
|
||||
import net.minecraftforge.registries.IForgeRegistry;
|
||||
import org.embeddedt.modernfix.registry.DeferredRegisterBaker;
|
||||
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.HashMap;
|
||||
|
||||
@Mixin(DeferredRegister.EventDispatcher.class)
|
||||
public class EventDispatcherMixin {
|
||||
private static HashMap<ResourceLocation, Boolean> hasRegistryBaked = new HashMap<>();
|
||||
@Inject(method = "handleEvent", at = @At("HEAD"), remap = false)
|
||||
private void bakeIfNeeded(RegistryEvent.Register<?> event, CallbackInfo ci) {
|
||||
IForgeRegistry<?> registry = event.getRegistry();
|
||||
if(registry == null)
|
||||
return;
|
||||
ResourceLocation location = registry.getRegistryName();
|
||||
if(location == null || !(location.getNamespace().equals("minecraft") && location.getPath().equals("block")))
|
||||
return;
|
||||
if(!hasRegistryBaked.getOrDefault(location, false)) {
|
||||
DeferredRegisterBaker.bakeSuppliers(location);
|
||||
hasRegistryBaked.put(location, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
public net.minecraft.client.Minecraft$WorldSelectionType
|
||||
public net.minecraft.client.renderer.RenderType$Type
|
||||
public net.minecraft.client.renderer.RenderType$Type <init>(Ljava/lang/String;Lnet/minecraft/client/renderer/vertex/VertexFormat;IIZZLnet/minecraft/client/renderer/RenderType$State;)V
|
||||
public net.minecraft.block.AbstractBlock$AbstractBlockState$Cache
|
||||
public net.minecraft.block.AbstractBlock$AbstractBlockState$Cache
|
||||
public net.minecraft.util.math.shapes.VoxelShape <init>(Lnet/minecraft/util/math/shapes/VoxelShapePart;)V # <init>
|
||||
|
|
@ -19,12 +19,9 @@
|
|||
"perf.boost_worker_count.UtilMixin",
|
||||
"perf.thread_priorities.UtilMixin",
|
||||
"perf.preload_block_classes.GameDataMixin",
|
||||
"perf.parallel_potentially_unsafe.parallel_deferred_suppliers.DeferredRegisterMixin",
|
||||
"perf.parallel_potentially_unsafe.parallel_deferred_suppliers.EventDispatcherMixin",
|
||||
"perf.parallel_blockstate_cache_rebuild.BlocksMixin",
|
||||
"perf.parallel_blockstate_cache_rebuild.BlockCallbacksMixin",
|
||||
"perf.parallel_blockstate_cache_rebuild.ShapeCacheMixin",
|
||||
"perf.parallel_potentially_unsafe.parallel_deferred_suppliers.DispenserBlockMixin",
|
||||
"perf.deduplicate_location.MixinResourceLocation"
|
||||
],
|
||||
"client": [
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user