Runs, dynamic resources still broken
This commit is contained in:
parent
a841d20f8a
commit
09ea5e1dc9
|
|
@ -1,22 +0,0 @@
|
|||
package org.embeddedt.modernfix.common.mixin.bugfix.chunk_deadlock;
|
||||
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
import net.minecraft.world.level.block.state.BlockBehaviour;
|
||||
import org.embeddedt.modernfix.chunk.SafeBlockGetter;
|
||||
import org.embeddedt.modernfix.duck.ISafeBlockGetter;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.ModifyVariable;
|
||||
|
||||
@Mixin(value = BlockBehaviour.BlockStateBase.class, priority = 100)
|
||||
public class BlockStateBaseMixin {
|
||||
@ModifyVariable(method = "getOffset", at = @At("HEAD"), argsOnly = true, index = 1)
|
||||
private BlockGetter useSafeGetter(BlockGetter g) {
|
||||
if(g instanceof ISafeBlockGetter) {
|
||||
SafeBlockGetter replacement = ((ISafeBlockGetter) g).mfix$getSafeBlockGetter();
|
||||
if(replacement.shouldUse())
|
||||
return replacement;
|
||||
}
|
||||
return g;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
package org.embeddedt.modernfix.common.mixin.perf.cache_model_materials;
|
||||
|
||||
import net.minecraft.client.renderer.block.model.multipart.MultiPart;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
||||
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.Collection;
|
||||
|
||||
@Mixin(MultiPart.class)
|
||||
@ClientOnlyMixin
|
||||
public class MultipartMixin {
|
||||
private Collection<ResourceLocation> dependencyCache = null;
|
||||
@Inject(method = "getDependencies", at = @At("HEAD"), cancellable = true)
|
||||
private void useDependencyCache(CallbackInfoReturnable<Collection<ResourceLocation>> cir) {
|
||||
if(dependencyCache != null)
|
||||
cir.setReturnValue(dependencyCache);
|
||||
}
|
||||
|
||||
@Inject(method = "getDependencies", at = @At("RETURN"))
|
||||
private void storeDependencyCache(CallbackInfoReturnable<Collection<ResourceLocation>> cir) {
|
||||
if(dependencyCache == null)
|
||||
dependencyCache = cir.getReturnValue();
|
||||
}
|
||||
}
|
||||
|
|
@ -17,7 +17,7 @@ public class CreateWorldScreenMixin {
|
|||
return ModernFix.resourceReloadExecutor();
|
||||
}
|
||||
|
||||
@ModifyArg(method = "openFresh", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/WorldLoader;load(Lnet/minecraft/server/WorldLoader$InitConfig;Lnet/minecraft/server/WorldLoader$WorldDataSupplier;Lnet/minecraft/server/WorldLoader$ResultFactory;Ljava/util/concurrent/Executor;Ljava/util/concurrent/Executor;)Ljava/util/concurrent/CompletableFuture;"), index = 3)
|
||||
@ModifyArg(method = "openCreateWorldScreen", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/WorldLoader;load(Lnet/minecraft/server/WorldLoader$InitConfig;Lnet/minecraft/server/WorldLoader$WorldDataSupplier;Lnet/minecraft/server/WorldLoader$ResultFactory;Ljava/util/concurrent/Executor;Ljava/util/concurrent/Executor;)Ljava/util/concurrent/CompletableFuture;"), index = 3)
|
||||
private static Executor getCreationExecutorService(Executor e) {
|
||||
return ModernFix.resourceReloadExecutor();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import java.util.concurrent.Executor;
|
|||
|
||||
@Mixin(MinecraftServer.class)
|
||||
public class MinecraftServerMixin {
|
||||
@ModifyArg(method = "*", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/ReloadableServerResources;loadResources(Lnet/minecraft/server/packs/resources/ResourceManager;Lnet/minecraft/core/LayeredRegistryAccess;Lnet/minecraft/world/flag/FeatureFlagSet;Lnet/minecraft/commands/Commands$CommandSelection;ILjava/util/concurrent/Executor;Ljava/util/concurrent/Executor;)Ljava/util/concurrent/CompletableFuture;"), index = 5)
|
||||
@ModifyArg(method = "*", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/ReloadableServerResources;loadResources(Lnet/minecraft/server/packs/resources/ResourceManager;Lnet/minecraft/core/LayeredRegistryAccess;Ljava/util/List;Lnet/minecraft/world/flag/FeatureFlagSet;Lnet/minecraft/commands/Commands$CommandSelection;ILjava/util/concurrent/Executor;Ljava/util/concurrent/Executor;)Ljava/util/concurrent/CompletableFuture;"), index = 6)
|
||||
private Executor getReloadExecutor(Executor asyncExecutor) {
|
||||
return ModernFix.resourceReloadExecutor();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,6 @@
|
|||
package org.embeddedt.modernfix.common.mixin.perf.mojang_registry_size;
|
||||
|
||||
import com.google.common.collect.ArrayTable;
|
||||
import com.google.common.collect.HashBasedTable;
|
||||
import com.google.common.collect.ImmutableTable;
|
||||
import com.google.common.collect.Table;
|
||||
import it.unimi.dsi.fastutil.objects.Reference2ObjectArrayMap;
|
||||
import net.minecraft.world.level.block.state.StateHolder;
|
||||
import net.minecraft.world.level.block.state.properties.Property;
|
||||
import org.embeddedt.modernfix.annotation.RequiresMod;
|
||||
|
|
@ -13,6 +10,8 @@ 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;
|
||||
|
||||
/**
|
||||
* Minor mixin to avoid duplicate empty neighbor tables, used when FerriteCore is not present. Won't be enabled in 99% of
|
||||
* modded environments but is useful for testing in dev without dragging in Fabric API.
|
||||
|
|
@ -20,12 +19,15 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|||
@Mixin(StateHolder.class)
|
||||
@RequiresMod("!ferritecore")
|
||||
public class StateHolderMixin {
|
||||
@Shadow private Table<Property<?>, Comparable<?>, ?> neighbours;
|
||||
private static final Reference2ObjectArrayMap<Property<?>, ?> EMPTY_NEIGHBOURS = new Reference2ObjectArrayMap<>();
|
||||
|
||||
@Shadow private Map<Property<?>, ?> neighbours;
|
||||
|
||||
/* optimize the case where block has no properties */
|
||||
@Inject(method = "populateNeighbours", at = @At("RETURN"), require = 0)
|
||||
private void replaceEmptyTable(CallbackInfo ci) {
|
||||
if((this.neighbours instanceof ArrayTable || this.neighbours instanceof HashBasedTable) && this.neighbours.isEmpty())
|
||||
this.neighbours = ImmutableTable.of();
|
||||
if (this.neighbours.isEmpty()) {
|
||||
this.neighbours = EMPTY_NEIGHBOURS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +0,0 @@
|
|||
package org.embeddedt.modernfix.common.mixin.perf.reduce_blockstate_cache_rebuilds;
|
||||
|
||||
import net.minecraft.world.level.block.state.BlockBehaviour;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.material.FluidState;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Invoker;
|
||||
|
||||
@Mixin(BlockBehaviour.class)
|
||||
public interface BlockBehaviourInvoker {
|
||||
@Invoker
|
||||
FluidState invokeGetFluidState(BlockState blockState);
|
||||
@Invoker
|
||||
boolean invokeIsRandomlyTicking(BlockState blockState);
|
||||
}
|
||||
|
|
@ -1,130 +0,0 @@
|
|||
package org.embeddedt.modernfix.common.mixin.perf.reduce_blockstate_cache_rebuilds;
|
||||
|
||||
import com.mojang.serialization.MapCodec;
|
||||
import it.unimi.dsi.fastutil.objects.Reference2ObjectArrayMap;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.state.BlockBehaviour;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.block.state.StateHolder;
|
||||
import net.minecraft.world.level.block.state.properties.Property;
|
||||
import net.minecraft.world.level.material.FluidState;
|
||||
import net.minecraft.world.level.material.Fluids;
|
||||
import org.embeddedt.modernfix.duck.IBlockState;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
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.Redirect;
|
||||
|
||||
|
||||
|
||||
@Mixin(BlockBehaviour.BlockStateBase.class)
|
||||
public abstract class BlockStateBaseMixin extends StateHolder<Block, BlockState> implements IBlockState {
|
||||
protected BlockStateBaseMixin(Block object, Reference2ObjectArrayMap<Property<?>, Comparable<?>> immutableMap, MapCodec<BlockState> mapCodec) {
|
||||
super(object, immutableMap, mapCodec);
|
||||
}
|
||||
|
||||
private static final FluidState MFIX$VANILLA_DEFAULT_FLUID = Fluids.EMPTY.defaultFluidState();
|
||||
|
||||
@Shadow public abstract void initCache();
|
||||
|
||||
@Shadow private BlockBehaviour.BlockStateBase.Cache cache;
|
||||
@Shadow private FluidState fluidState;
|
||||
@Shadow private boolean isRandomlyTicking;
|
||||
@Shadow @Deprecated private boolean legacySolid;
|
||||
|
||||
@Shadow protected abstract BlockState asState();
|
||||
|
||||
private volatile boolean cacheInvalid = false;
|
||||
private static boolean buildingCache = false;
|
||||
@Override
|
||||
public void clearCache() {
|
||||
cacheInvalid = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCacheInvalid() {
|
||||
return cacheInvalid;
|
||||
}
|
||||
|
||||
private void mfix$generateCache() {
|
||||
if(cacheInvalid) {
|
||||
// Ensure that only one block's cache is built at a time
|
||||
synchronized (BlockBehaviour.BlockStateBase.class) {
|
||||
if(cacheInvalid) {
|
||||
// Ensure that if we end up in here recursively, we just use the original cache
|
||||
if(!buildingCache) {
|
||||
buildingCache = true;
|
||||
try {
|
||||
this.initCache();
|
||||
cacheInvalid = false;
|
||||
} finally {
|
||||
buildingCache = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Redirect(method = "*", at = @At(
|
||||
value = "FIELD",
|
||||
opcode = Opcodes.GETFIELD,
|
||||
target = "Lnet/minecraft/world/level/block/state/BlockBehaviour$BlockStateBase;cache:Lnet/minecraft/world/level/block/state/BlockBehaviour$BlockStateBase$Cache;",
|
||||
ordinal = 0
|
||||
))
|
||||
private BlockBehaviour.BlockStateBase.Cache dynamicCacheGen(BlockBehaviour.BlockStateBase base) {
|
||||
mfix$generateCache();
|
||||
return this.cache;
|
||||
}
|
||||
|
||||
@Redirect(method = "*", at = @At(
|
||||
value = "FIELD",
|
||||
opcode = Opcodes.GETFIELD,
|
||||
target = "Lnet/minecraft/world/level/block/state/BlockBehaviour$BlockStateBase;fluidState:Lnet/minecraft/world/level/material/FluidState;",
|
||||
ordinal = 0
|
||||
), require = 0)
|
||||
private FluidState genCacheBeforeGettingFluid(BlockBehaviour.BlockStateBase base) {
|
||||
// don't generate the full cache here as mods will iterate for the fluid state a lot
|
||||
// assume blockstates will not change their contained fluidstate at runtime more than once
|
||||
// this is how Lithium's implementation used to work, so it should be fine
|
||||
if(this.cacheInvalid && this.fluidState == MFIX$VANILLA_DEFAULT_FLUID) {
|
||||
synchronized (BlockBehaviour.BlockStateBase.class) {
|
||||
if(!buildingCache) {
|
||||
buildingCache = true;
|
||||
try {
|
||||
this.fluidState = ((BlockBehaviourInvoker)this.owner).invokeGetFluidState(this.asState());
|
||||
} finally {
|
||||
buildingCache = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return this.fluidState;
|
||||
}
|
||||
|
||||
@Redirect(method = "*", at = @At(
|
||||
value = "FIELD",
|
||||
opcode = Opcodes.GETFIELD,
|
||||
target = "Lnet/minecraft/world/level/block/state/BlockBehaviour$BlockStateBase;isRandomlyTicking:Z",
|
||||
ordinal = 0
|
||||
))
|
||||
private boolean genCacheBeforeGettingTicking(BlockBehaviour.BlockStateBase base) {
|
||||
if(this.cacheInvalid)
|
||||
return ((BlockBehaviourInvoker)this.owner).invokeIsRandomlyTicking(this.asState());
|
||||
return this.isRandomlyTicking;
|
||||
}
|
||||
|
||||
@Redirect(method = "*", at = @At(
|
||||
value = "FIELD",
|
||||
opcode = Opcodes.GETFIELD,
|
||||
target = "Lnet/minecraft/world/level/block/state/BlockBehaviour$BlockStateBase;legacySolid:Z",
|
||||
ordinal = 0
|
||||
))
|
||||
private boolean genCacheBeforeCheckingSolid(BlockBehaviour.BlockStateBase base) {
|
||||
mfix$generateCache();
|
||||
return this.legacySolid;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
package org.embeddedt.modernfix.common.mixin.perf.reduce_blockstate_cache_rebuilds;
|
||||
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import org.embeddedt.modernfix.blockstate.BlockStateCacheHandler;
|
||||
import org.embeddedt.modernfix.duck.IBlockState;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.ModifyArg;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@Mixin(value = Blocks.class, priority = 1100)
|
||||
public class BlocksMixin {
|
||||
@ModifyArg(method = "rebuildCache", at = @At(value = "INVOKE", target = "Lnet/minecraft/core/IdMapper;forEach(Ljava/util/function/Consumer;)V"), index = 0)
|
||||
private static Consumer getEmptyConsumer(Consumer original) {
|
||||
BlockStateCacheHandler.rebuildParallel(true);
|
||||
return o -> {};
|
||||
}
|
||||
|
||||
// require = 0 due to Forge removing the BLOCK_STATE_REGISTRY init here
|
||||
@Redirect(method = "<clinit>", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/state/BlockState;initCache()V"), require = 0)
|
||||
private static void skipCacheInit(BlockState state) {
|
||||
// Mark the cache as invalid
|
||||
((IBlockState)state).clearCache();
|
||||
}
|
||||
}
|
||||
|
|
@ -9,7 +9,7 @@ import org.spongepowered.asm.mixin.Shadow;
|
|||
/* Idea from Lithium for 1.19.3 */
|
||||
@Mixin(Biome.class)
|
||||
public abstract class BiomeMixin {
|
||||
@Shadow protected abstract float getHeightAdjustedTemperature(BlockPos pos);
|
||||
@Shadow protected abstract float getHeightAdjustedTemperature(BlockPos pos, int i);
|
||||
|
||||
/**
|
||||
* @author 2No2Name
|
||||
|
|
@ -18,7 +18,7 @@ public abstract class BiomeMixin {
|
|||
* @return
|
||||
*/
|
||||
@Overwrite
|
||||
private float getTemperature(BlockPos pos) {
|
||||
return this.getHeightAdjustedTemperature(pos);
|
||||
private float getTemperature(BlockPos pos, int i) {
|
||||
return this.getHeightAdjustedTemperature(pos, i);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,18 +1,14 @@
|
|||
package org.embeddedt.modernfix.core;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.embeddedt.modernfix.core.config.ModernFixEarlyConfig;
|
||||
import org.embeddedt.modernfix.core.config.Option;
|
||||
import org.embeddedt.modernfix.platform.ModernFixPlatformHooks;
|
||||
import org.embeddedt.modernfix.world.ThreadDumper;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.tree.*;
|
||||
import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin;
|
||||
import org.spongepowered.asm.mixin.extensibility.IMixinInfo;
|
||||
import org.spongepowered.asm.mixin.transformer.meta.MixinMerged;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
|
|
@ -150,138 +146,6 @@ public class ModernFixMixinPlugin implements IMixinConfigPlugin {
|
|||
|
||||
@Override
|
||||
public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) {
|
||||
if(mixinClassName.equals("org.embeddedt.modernfix.common.mixin.perf.reduce_blockstate_cache_rebuilds.BlockStateBaseMixin")) {
|
||||
try {
|
||||
applyBlockStateCacheScan(targetClass);
|
||||
} catch(RuntimeException e) {
|
||||
ModernFixMixinPlugin.instance.logger.error("Applying blockstate cache ASM patch failed", e);
|
||||
}
|
||||
}
|
||||
ModernFixPlatformHooks.INSTANCE.applyASMTransformers(mixinClassName, targetClass);
|
||||
}
|
||||
|
||||
private void applyBlockStateCacheScan(ClassNode targetClass) {
|
||||
Set<String> initCacheMethodNames = ImmutableSet.of("m_60611_", "func_215692_c", "method_26200", "initCache");
|
||||
Set<String> whitelistedInjections = ImmutableSet.of(
|
||||
"getFluidState", "method_26227", "m_60819_", "func_204520_s"
|
||||
);
|
||||
Map<String, MethodNode> injectorMethodNames = new HashMap<>();
|
||||
Map<String, MethodNode> allMethods = new HashMap<>();
|
||||
Map<String, String> injectorMixinSource = new HashMap<>();
|
||||
String descriptor = Type.getDescriptor(MixinMerged.class);
|
||||
for(MethodNode m : targetClass.methods) {
|
||||
if((m.access & Opcodes.ACC_STATIC) != 0)
|
||||
continue;
|
||||
allMethods.put(m.name, m);
|
||||
Set<AnnotationNode> seenNodes = new HashSet<>();
|
||||
if(m.invisibleAnnotations != null) {
|
||||
for(AnnotationNode ann : m.invisibleAnnotations) {
|
||||
if(ann.desc.equals(descriptor)) {
|
||||
seenNodes.add(ann);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(m.visibleAnnotations != null) {
|
||||
for(AnnotationNode ann : m.visibleAnnotations) {
|
||||
if(ann.desc.equals(descriptor)) {
|
||||
seenNodes.add(ann);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(seenNodes.size() > 0) {
|
||||
injectorMethodNames.put(m.name, m);
|
||||
for(AnnotationNode node : seenNodes) {
|
||||
for(int i = 0; i < node.values.size(); i += 2) {
|
||||
if(Objects.equals(node.values.get(i), "mixin")) {
|
||||
injectorMixinSource.put(m.name, (String)node.values.get(i + 1));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Set<String> cacheCalledInjectors = new HashSet<>();
|
||||
// Search for initCache in the class
|
||||
for(MethodNode m : targetClass.methods) {
|
||||
if((m.access & Opcodes.ACC_STATIC) != 0)
|
||||
continue;
|
||||
if(initCacheMethodNames.contains(m.name)) {
|
||||
// This is it. Check for any injectors it calls
|
||||
for(AbstractInsnNode n : m.instructions) {
|
||||
if(n instanceof MethodInsnNode) {
|
||||
MethodInsnNode invoke = (MethodInsnNode)n;
|
||||
if(((MethodInsnNode)n).owner.equals(targetClass.name) && injectorMethodNames.containsKey(((MethodInsnNode)n).name)) {
|
||||
cacheCalledInjectors.add(invoke.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
Set<String> accessedFieldNames = new HashSet<>();
|
||||
|
||||
// Make a map of all injected methods called by initCache
|
||||
Map<String, MethodNode> writingMethods = new HashMap<>(injectorMethodNames);
|
||||
writingMethods.keySet().retainAll(cacheCalledInjectors);
|
||||
|
||||
// Recursively check the injected methods for any methods they may call
|
||||
int previousSize = 0;
|
||||
Set<String> checkedCalls = new HashSet<>();
|
||||
while(writingMethods.size() > previousSize) {
|
||||
previousSize = writingMethods.size();
|
||||
List<String> keysToCheck = new ArrayList<>(writingMethods.keySet());
|
||||
for(String name : keysToCheck) {
|
||||
if(!checkedCalls.add(name))
|
||||
continue;
|
||||
for(AbstractInsnNode n : writingMethods.get(name).instructions) {
|
||||
if(n instanceof MethodInsnNode) {
|
||||
MethodInsnNode invokeNode = (MethodInsnNode)n;
|
||||
if(invokeNode.owner.equals(targetClass.name)) {
|
||||
MethodNode theMethod = allMethods.get(invokeNode.name);
|
||||
if(theMethod != null)
|
||||
writingMethods.put(invokeNode.name, theMethod);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We now know all methods that have been injected into initCache, and their callers. See what fields they write to
|
||||
writingMethods.forEach((name, method) -> {
|
||||
for(AbstractInsnNode n : method.instructions) {
|
||||
if(n instanceof FieldInsnNode) {
|
||||
FieldInsnNode fieldAcc = (FieldInsnNode)n;
|
||||
if(fieldAcc.getOpcode() == Opcodes.PUTFIELD && fieldAcc.owner.equals(targetClass.name)) {
|
||||
accessedFieldNames.add(fieldAcc.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
// Lastly, scan all injected methods and see if they retrieve from the field. If so, inject a generateCache
|
||||
// call at the start.
|
||||
injectorMethodNames.forEach((name, method) -> {
|
||||
// skip whitelisted injectors, and injectors called by initCache itself (to prevent recursion)
|
||||
if(whitelistedInjections.contains(name) || cacheCalledInjectors.contains(name))
|
||||
return;
|
||||
boolean needInjection = false;
|
||||
for(AbstractInsnNode n : method.instructions) {
|
||||
if(n instanceof FieldInsnNode) {
|
||||
FieldInsnNode fieldAcc = (FieldInsnNode)n;
|
||||
if(fieldAcc.getOpcode() == Opcodes.GETFIELD && accessedFieldNames.contains(fieldAcc.name)) {
|
||||
needInjection = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(needInjection) {
|
||||
ModernFixMixinPlugin.instance.logger.info("Injecting BlockStateBase cache population hook into {} from {}",
|
||||
name, injectorMixinSource.getOrDefault(name, "[unknown mixin]"));
|
||||
// inject this.mfix$generateCache() at method head
|
||||
InsnList injection = new InsnList();
|
||||
injection.add(new VarInsnNode(Opcodes.ALOAD, 0));
|
||||
injection.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, targetClass.name, "mfix$generateCache", "()V"));
|
||||
method.instructions.insert(injection);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user