From cb6559b7c6a541f8cb626de8c6d097ffabc4f134 Mon Sep 17 00:00:00 2001 From: Rongmario Date: Thu, 13 May 2021 15:02:50 +0100 Subject: [PATCH] Bump 2.4: Added new module `modFixes` + Fixes #9 - First mod fix: prevent `ArrayIndexOutOfBoundsException` from occurring in `BlockIEBase#getPushReaction` with special cases --- build.gradle | 8 ++- changelog.md | 7 ++- .../memory/mixins/ModCandidateMixin.java | 50 ------------------- .../modfixes/mixins/BlockIEBaseMixin.java | 29 +++++++++++ .../zone/rong/loliasm/config/LoliConfig.java | 12 +++-- .../zone/rong/loliasm/core/LoliHooks.java | 33 ++++++++++++ .../rong/loliasm/core/LoliLoadingPlugin.java | 2 +- .../rong/loliasm/core/LoliMixinLoader.java | 6 ++- .../rong/loliasm/core/LoliTransformer.java | 38 +++++++++++--- src/main/resources/mixins.memory.json | 3 +- src/main/resources/mixins.modfixes.json | 13 +++++ 11 files changed, 134 insertions(+), 67 deletions(-) delete mode 100644 src/main/java/zone/rong/loliasm/common/memory/mixins/ModCandidateMixin.java create mode 100644 src/main/java/zone/rong/loliasm/common/modfixes/mixins/BlockIEBaseMixin.java create mode 100644 src/main/java/zone/rong/loliasm/core/LoliHooks.java create mode 100644 src/main/resources/mixins.modfixes.json diff --git a/build.gradle b/build.gradle index d0c7123c..28fb0438 100644 --- a/build.gradle +++ b/build.gradle @@ -13,7 +13,7 @@ apply plugin: 'net.minecraftforge.gradle.forge' apply plugin: 'org.spongepowered.mixin' //Only edit below this line, the above code adds and enables the necessary things for Forge to be setup. -version = "2.3.1" +version = "2.4" group = "zone.rong.loliasm" // http://maven.apache.org/guides/mini/guide-naming-conventions.html archivesBaseName = "loliasm" @@ -55,6 +55,10 @@ repositories { url "http://chickenbones.net/maven" } + maven { + url "https://modmaven.k-4u.nl/" + } + // maven { // url = "http://maven.bluexin.be/repository/snapshots/" // } @@ -80,6 +84,8 @@ dependencies { compile 'codechicken:ChickenASM:1.12-1.0.2.9' + deobfCompile "blusunrize:ImmersiveEngineering:0.12-92-+" + // compile "com.teamwizardry.librarianlib:librarianlib-1.12:4.0-SNAPSHOT:deobf" } diff --git a/changelog.md b/changelog.md index 1cf94eea..c3935917 100644 --- a/changelog.md +++ b/changelog.md @@ -1,7 +1,12 @@ # LoliASM Changelog +## 2.4 +- Added new module `modFixes`. +- Prevent `ArrayIndexOutOfBoundsException` from occurring in `BlockIEBase#getPushReaction` with special cases. +- Fixes incompatibility with *Wings* because Wings' coremod loads some Forge classes too early for us to mixin into. + ## 2.3.1 -- Fixes `bakedQuadPatchClasses` not being properly targetted by mixins. This means, LoliASM now requires MixinBooter. It was going to some time down the line anyways. +- Fixes `bakedQuadPatchClasses` not being properly targeted by mixins. This means, LoliASM now requires MixinBooter. It was going to some time down the line anyways. - Added `miscOptimizations` => aims to optimize smaller areas of the game, nothing game-breaking will be introduced under this. - `FluidRegistryMixin` => first of `miscOptimizations`, quicker check @ `FluidRegistry::enableUniversalBucket` - Some more logging diff --git a/src/main/java/zone/rong/loliasm/common/memory/mixins/ModCandidateMixin.java b/src/main/java/zone/rong/loliasm/common/memory/mixins/ModCandidateMixin.java deleted file mode 100644 index 9deab1a5..00000000 --- a/src/main/java/zone/rong/loliasm/common/memory/mixins/ModCandidateMixin.java +++ /dev/null @@ -1,50 +0,0 @@ -package zone.rong.loliasm.common.memory.mixins; - -import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; -import net.minecraftforge.fml.common.discovery.ASMDataTable; -import net.minecraftforge.fml.common.discovery.ModCandidate; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.Unique; -import zone.rong.loliasm.api.StringPool; - -import java.util.ArrayList; -import java.util.List; -import java.util.Set; - -@Mixin(value = ModCandidate.class, remap = false) -public class ModCandidateMixin { - - @Shadow private Set foundClasses; - @Shadow private ASMDataTable table; - - @Unique private final Set packagesSet = new ObjectOpenHashSet<>(); - - /** - * @author Rongmario - * @reason Canonize package strings. This also helps canonize those that use getOwnedPackages() indirectly (e.g - LibrarianLib) - */ - @Overwrite - public void addClassEntry(String name) { - String className = name.substring(0, name.lastIndexOf('.')); // strip the .class - foundClasses.add(className); - className = className.replace('/','.'); - int pkgIdx = className.lastIndexOf('.'); - if (pkgIdx > -1) { - String pkg = StringPool.canonize(className.substring(0, pkgIdx)); - packagesSet.add(pkg); - this.table.registerPackage((ModCandidate) (Object) this, pkg); - } - } - - /** - * @author Rongmario - * @reason packagesSet => ArrayList - */ - @Overwrite - public List getContainedPackages() { - return new ArrayList<>(packagesSet); - } - -} diff --git a/src/main/java/zone/rong/loliasm/common/modfixes/mixins/BlockIEBaseMixin.java b/src/main/java/zone/rong/loliasm/common/modfixes/mixins/BlockIEBaseMixin.java new file mode 100644 index 00000000..0dec3cbf --- /dev/null +++ b/src/main/java/zone/rong/loliasm/common/modfixes/mixins/BlockIEBaseMixin.java @@ -0,0 +1,29 @@ +package zone.rong.loliasm.common.modfixes.mixins; + +import blusunrize.immersiveengineering.common.blocks.BlockIEBase; +import net.minecraft.block.material.EnumPushReaction; +import net.minecraft.block.state.IBlockState; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; + +@Mixin(BlockIEBase.class) +public abstract class BlockIEBaseMixin { + + @Shadow public abstract int getMetaFromState(IBlockState state); + @Shadow(remap = false) protected EnumPushReaction[] metaMobilityFlags; + + /** + * @author Rongmario + * @reason Fixes ArrayIndexOutOfBoundsException + */ + @Overwrite + public EnumPushReaction getPushReaction(IBlockState state) { + int meta = getMetaFromState(state); + if (metaMobilityFlags.length <= meta || metaMobilityFlags[meta] == null) { + return EnumPushReaction.NORMAL; + } + return metaMobilityFlags[meta]; + } + +} diff --git a/src/main/java/zone/rong/loliasm/config/LoliConfig.java b/src/main/java/zone/rong/loliasm/config/LoliConfig.java index 746170da..0f2e3b73 100644 --- a/src/main/java/zone/rong/loliasm/config/LoliConfig.java +++ b/src/main/java/zone/rong/loliasm/config/LoliConfig.java @@ -56,6 +56,9 @@ public static class Data { @Ignore final String miscOptimizationsComment = "Other optimization tweaks. Nothing that is experimental or has breaking changes would be classed under this."; @Since("2.3.1") public final boolean miscOptimizations; + @Ignore final String modFixesComment = "Various mod fixes and optimizations."; + @Since("2.4") public final boolean modFixes; + public Data(String version, boolean bakedQuadsSquasher, boolean logClassesThatNeedPatching, @@ -66,7 +69,8 @@ public Data(String version, boolean optimizeDataStructures, boolean optimizeFurnaceRecipes, boolean optimizeBitsOfRendering, - boolean miscOptimizations) { + boolean miscOptimizations, + boolean modFixes) { this.VERSION = version; this.bakedQuadsSquasher = bakedQuadsSquasher; this.logClassesThatNeedPatching = logClassesThatNeedPatching; @@ -78,6 +82,7 @@ public Data(String version, this.optimizeFurnaceRecipes = optimizeFurnaceRecipes; this.optimizeBitsOfRendering = optimizeBitsOfRendering; this.miscOptimizations = miscOptimizations; + this.modFixes = modFixes; } } @@ -104,7 +109,7 @@ public boolean shouldSkipClass(Class clazz) { try { configFile.createNewFile(); try (FileWriter writer = new FileWriter(configFile)) { - config = new Data(LoliLoadingPlugin.VERSION, true, true, new String[] { "net.minecraft.client.renderer.block.model.FaceBakery" }, true, true, true, true, true, true, true); + config = new Data(LoliLoadingPlugin.VERSION, true, true, new String[] { "net.minecraft.client.renderer.block.model.FaceBakery" }, true, true, true, true, true, true, true, true); gson.toJson(config, writer); } } catch (IOException e) { @@ -125,13 +130,14 @@ public boolean shouldSkipClass(Class clazz) { config.optimizeDataStructures, config.optimizeFurnaceRecipes, true, + true, true); try (FileWriter writer = new FileWriter(configFile)) { gson.toJson(config, writer); } } else if (isVersionOutdated(config.VERSION, LoliLoadingPlugin.VERSION)) { LoliLogger.instance.info("Config outdated, updating config from version {} to {}.", config.VERSION, LoliLoadingPlugin.VERSION); - MethodHandle dataCtor = LoliReflector.resolveCtor(Data.class, String.class, boolean.class, boolean.class, String[].class, boolean.class, boolean.class, boolean.class, boolean.class, boolean.class, boolean.class, boolean.class); + MethodHandle dataCtor = LoliReflector.resolveCtor(Data.class, String.class, boolean.class, boolean.class, String[].class, boolean.class, boolean.class, boolean.class, boolean.class, boolean.class, boolean.class, boolean.class, boolean.class); List args = new ArrayList<>(); args.add(LoliLoadingPlugin.VERSION); for (Field field : Data.class.getFields()) { diff --git a/src/main/java/zone/rong/loliasm/core/LoliHooks.java b/src/main/java/zone/rong/loliasm/core/LoliHooks.java new file mode 100644 index 00000000..9f4a4d1d --- /dev/null +++ b/src/main/java/zone/rong/loliasm/core/LoliHooks.java @@ -0,0 +1,33 @@ +package zone.rong.loliasm.core; + +import it.unimi.dsi.fastutil.objects.ObjectArraySet; +import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; +import net.minecraftforge.fml.common.discovery.ASMDataTable; +import net.minecraftforge.fml.common.discovery.ModCandidate; +import zone.rong.loliasm.api.StringPool; + +import java.util.Set; + +public class LoliHooks { + + public static ObjectArraySet createArraySet() { + return new ObjectArraySet<>(); + } + + public static ObjectOpenHashSet createHashSet() { + return new ObjectOpenHashSet<>(); + } + + public static void modCandidate$override$addClassEntry(ModCandidate modCandidate, String name, Set foundClasses, Set packages, ASMDataTable table) { + String className = name.substring(0, name.lastIndexOf('.')); + foundClasses.add(className); + className = className.replace('/','.'); + int pkgIdx = className.lastIndexOf('.'); + if (pkgIdx > -1) { + String pkg = StringPool.canonize(className.substring(0, pkgIdx)); + packages.add(pkg); + table.registerPackage(modCandidate, pkg); + } + } + +} diff --git a/src/main/java/zone/rong/loliasm/core/LoliLoadingPlugin.java b/src/main/java/zone/rong/loliasm/core/LoliLoadingPlugin.java index 449adb4b..51e08fed 100644 --- a/src/main/java/zone/rong/loliasm/core/LoliLoadingPlugin.java +++ b/src/main/java/zone/rong/loliasm/core/LoliLoadingPlugin.java @@ -17,7 +17,7 @@ @IFMLLoadingPlugin.MCVersion(ForgeVersion.mcVersion) public class LoliLoadingPlugin implements IFMLLoadingPlugin { - public static final String VERSION = "2.3.1"; + public static final String VERSION = "2.4"; public static final boolean isDeobf = FMLLaunchHandler.isDeobfuscatedEnvironment(); public static final boolean isOptifineInstalled = LoliReflector.doesClassExist("optifine.OptiFineForgeTweaker"); diff --git a/src/main/java/zone/rong/loliasm/core/LoliMixinLoader.java b/src/main/java/zone/rong/loliasm/core/LoliMixinLoader.java index 1cc36249..ceeb73b5 100644 --- a/src/main/java/zone/rong/loliasm/core/LoliMixinLoader.java +++ b/src/main/java/zone/rong/loliasm/core/LoliMixinLoader.java @@ -8,9 +8,13 @@ public class LoliMixinLoader { { - if (LoliConfig.getConfig().bakedQuadsSquasher) { + LoliConfig.Data data = LoliConfig.getConfig(); + if (data.bakedQuadsSquasher) { Mixins.addConfiguration("mixins.bakedquadsquasher.json"); } + if (data.modFixes) { + Mixins.addConfiguration("mixins.modfixes.json"); + } } } diff --git a/src/main/java/zone/rong/loliasm/core/LoliTransformer.java b/src/main/java/zone/rong/loliasm/core/LoliTransformer.java index 72592b6f..680fa237 100644 --- a/src/main/java/zone/rong/loliasm/core/LoliTransformer.java +++ b/src/main/java/zone/rong/loliasm/core/LoliTransformer.java @@ -391,7 +391,10 @@ private byte[] removePackageField(byte[] bytes) { ClassNode node = new ClassNode(); reader.accept(node, 0); - node.fields.removeIf(f -> f.name.equals("packages")); + node.fields.stream().filter(f -> f.name.equals("packages")).findFirst().ifPresent(f -> { + f.desc = "Ljava/util/Set;"; + f.signature = "Ljava/util/Set;"; + }); for (MethodNode method : node.methods) { if (method.name.equals("") && method.desc.equals("(Ljava/io/File;Ljava/io/File;Lnet/minecraftforge/fml/common/discovery/ContainerType;ZZ)V")) { @@ -401,18 +404,37 @@ private byte[] removePackageField(byte[] bytes) { if (instruction.getOpcode() == PUTFIELD) { FieldInsnNode fieldNode = (FieldInsnNode) instruction; if (fieldNode.name.equals("packages")) { - iter.remove(); // PUTFIELD + fieldNode.desc = "Ljava/util/Set;"; iter.previous(); - iter.remove(); // INVOKESTATIC iter.previous(); - iter.remove(); // ALOAD - iter.previous(); - iter.remove(); // LINENUMBER - iter.previous(); - iter.remove(); // LABEL + iter.set(new MethodInsnNode(INVOKESTATIC, "zone/rong/loliasm/core/LoliHooks", "createHashSet", "()Lit/unimi/dsi/fastutil/objects/ObjectOpenHashSet;", false)); + break; } } } + } else if (method.name.equals("addClassEntry")) { // see: LoliHooks::modCandidate$override$addClassEntry + method.instructions.clear(); + method.instructions.add(new VarInsnNode(ALOAD, 0)); + method.instructions.add(new VarInsnNode(ALOAD, 1)); + method.instructions.add(new VarInsnNode(ALOAD, 0)); + method.instructions.add(new FieldInsnNode(GETFIELD, "net/minecraftforge/fml/common/discovery/ModCandidate", "foundClasses", "Ljava/util/Set;")); + method.instructions.add(new VarInsnNode(ALOAD, 0)); + method.instructions.add(new FieldInsnNode(GETFIELD, "net/minecraftforge/fml/common/discovery/ModCandidate", "packages", "Ljava/util/Set;")); + method.instructions.add(new VarInsnNode(ALOAD, 0)); + method.instructions.add(new FieldInsnNode(GETFIELD, "net/minecraftforge/fml/common/discovery/ModCandidate", "table", "Lnet/minecraftforge/fml/common/discovery/ASMDataTable;")); + method.instructions.add(new MethodInsnNode(INVOKESTATIC, "zone/rong/loliasm/core/LoliHooks", "modCandidate$override$addClassEntry", "(Lnet/minecraftforge/fml/common/discovery/ModCandidate;Ljava/lang/String;Ljava/util/Set;Ljava/util/Set;Lnet/minecraftforge/fml/common/discovery/ASMDataTable;)V", false)); + method.instructions.add(new InsnNode(RETURN)); + } else if (method.name.equals("getContainedPackages")) { // Return ArrayList with Set elements + ListIterator iter = method.instructions.iterator(); + while (iter.hasNext()) { + AbstractInsnNode instruction = iter.next(); + if (instruction.getOpcode() == GETFIELD) { + FieldInsnNode fieldNode = (FieldInsnNode) instruction; + fieldNode.desc = "Ljava/util/Set;"; + iter.add(new MethodInsnNode(INVOKESTATIC, "com/google/common/collect/Lists", "newArrayList", "(Ljava/lang/Iterable;)Ljava/util/ArrayList;", false)); + break; + } + } } } diff --git a/src/main/resources/mixins.memory.json b/src/main/resources/mixins.memory.json index 374e7c72..6d1c156a 100644 --- a/src/main/resources/mixins.memory.json +++ b/src/main/resources/mixins.memory.json @@ -5,8 +5,7 @@ "minVersion": "0.8", "compatibilityLevel": "JAVA_8", "mixins": [ - "LockCodeMixin", - "ModCandidateMixin" + "LockCodeMixin" ], "injectors": { "defaultRequire": 1 diff --git a/src/main/resources/mixins.modfixes.json b/src/main/resources/mixins.modfixes.json new file mode 100644 index 00000000..748597c8 --- /dev/null +++ b/src/main/resources/mixins.modfixes.json @@ -0,0 +1,13 @@ +{ + "package": "zone.rong.loliasm.common.modfixes.mixins", + "refmap": "mixins.loliasm.refmap.json", + "target": "@env(DEFAULT)", + "minVersion": "0.8", + "compatibilityLevel": "JAVA_8", + "mixins": [ + "BlockIEBaseMixin" + ], + "injectors": { + "defaultRequire": 1 + } +} \ No newline at end of file