diff --git a/build.gradle b/build.gradle
index 35fec2527..c327904ed 100644
--- a/build.gradle
+++ b/build.gradle
@@ -66,6 +66,8 @@ archivesBaseName = aebasename
jar {
manifest {
attributes 'FMLAT': 'appeng_at.cfg'
+ attributes "FMLCorePlugin": "appeng.core.AE2ELCore"
+ attributes "FMLCorePluginContainsFMLMod": "true"
}
from sourceSets.api.output
diff --git a/src/main/java/appeng/core/AE2ELCore.java b/src/main/java/appeng/core/AE2ELCore.java
new file mode 100644
index 000000000..69ca36681
--- /dev/null
+++ b/src/main/java/appeng/core/AE2ELCore.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2018, 2020 Adrian Siekierka
+ *
+ * This file is part of StackUp.
+ *
+ * StackUp is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * StackUp is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with StackUp. If not, see .
+ */
+
+package appeng.core;
+
+import net.minecraftforge.fml.relauncher.IFMLLoadingPlugin;
+
+import javax.annotation.Nullable;
+import java.util.Map;
+
+@IFMLLoadingPlugin.Name("AE2ELCore")
+@IFMLLoadingPlugin.MCVersion("1.12.2")
+@IFMLLoadingPlugin.SortingIndex(1001)
+@IFMLLoadingPlugin.TransformerExclusions("appeng.core.transformer")
+public class AE2ELCore implements IFMLLoadingPlugin {
+ @Override
+ public String[] getASMTransformerClass() {
+ return new String[]{
+ "appeng.core.transformer.AE2ELTransformer"
+ };
+ }
+
+ @Override
+ public String getModContainerClass() {
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public String getSetupClass() {
+ return null;
+ }
+
+ @Override
+ public void injectData(Map data) {
+ }
+
+ @Override
+ public String getAccessTransformerClass() {
+ return null;
+ }
+}
diff --git a/src/main/java/appeng/core/transformer/AE2ELTransformer.java b/src/main/java/appeng/core/transformer/AE2ELTransformer.java
new file mode 100644
index 000000000..33d86cd8c
--- /dev/null
+++ b/src/main/java/appeng/core/transformer/AE2ELTransformer.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2018, 2020 Adrian Siekierka
+ *
+ * This file is part of StackUp.
+ *
+ * StackUp is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * StackUp is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with StackUp. If not, see .
+ */
+
+package appeng.core.transformer;
+
+import net.minecraft.launchwrapper.IClassTransformer;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.tree.ClassNode;
+
+import java.util.function.Consumer;
+
+public class AE2ELTransformer implements IClassTransformer {
+
+ @Override
+ public byte[] transform(String name, String transformedName, byte[] basicClass) {
+ transformedName = transformedName.replace('/', '.');
+
+ byte[] data = basicClass;
+ Consumer consumer = (n) -> {
+ };
+ Consumer emptyConsumer = consumer;
+
+ if ("net.minecraft.item.ItemStack".equals(transformedName)) {
+ consumer = consumer.andThen(ItemStackPatch::patchCountGetSet);
+ }
+
+ if (consumer != emptyConsumer) {
+ return processNode(basicClass, consumer);
+ } else {
+ return data;
+ }
+ }
+
+ public static byte[] processNode(byte[] data, Consumer classNodeConsumer) {
+ ClassReader reader = new ClassReader(data);
+ ClassNode nodeOrig = new ClassNode();
+ reader.accept(nodeOrig, 0);
+ classNodeConsumer.accept(nodeOrig);
+ ClassWriter writer = new ClassWriter(0);
+ nodeOrig.accept(writer);
+ return writer.toByteArray();
+ }
+
+}
diff --git a/src/main/java/appeng/core/transformer/ItemStackPatch.java b/src/main/java/appeng/core/transformer/ItemStackPatch.java
new file mode 100644
index 000000000..80d5d3226
--- /dev/null
+++ b/src/main/java/appeng/core/transformer/ItemStackPatch.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2018, 2020 Adrian Siekierka
+ *
+ * This file is part of StackUp.
+ *
+ * StackUp is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * StackUp is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with StackUp. If not, see .
+ */
+
+package appeng.core.transformer;
+
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.tree.AbstractInsnNode;
+import org.objectweb.asm.tree.ClassNode;
+import org.objectweb.asm.tree.LdcInsnNode;
+import org.objectweb.asm.tree.MethodInsnNode;
+import org.objectweb.asm.tree.MethodNode;
+
+import java.util.ListIterator;
+
+public final class ItemStackPatch {
+ private ItemStackPatch() {
+ }
+
+ public static void patchCountGetSet(ClassNode node) {
+ for (MethodNode mn : node.methods) {
+ if ("".equals(mn.name)) {
+ ListIterator it = mn.instructions.iterator();
+ while (it.hasNext()) {
+ AbstractInsnNode in = it.next();
+ if (in instanceof LdcInsnNode && "Count".equals(((LdcInsnNode) in).cst)) {
+ AbstractInsnNode in2 = it.next();
+ if (in2.getOpcode() == Opcodes.INVOKEVIRTUAL) {
+ // :thinking:
+ boolean patched = false;
+ MethodInsnNode min2 = (MethodInsnNode) in2;
+ if (min2.name.equals("getByte")) {
+ min2.name = "getInteger";
+ patched = true;
+ } else if (min2.name.equals("func_74771_c")) {
+ min2.name = "func_74762_e";
+ patched = true;
+ }
+
+ if (patched) {
+ min2.desc = "(Ljava/lang/String;)I";
+ System.out.println("Patched ItemStack Count getter!");
+ }
+ }
+ }
+ }
+ } else if ("func_77955_b".equals(mn.name) || "writeToNBT".equals(mn.name)) {
+ ListIterator it = mn.instructions.iterator();
+ while (it.hasNext()) {
+ AbstractInsnNode in = it.next();
+ if (in instanceof LdcInsnNode && "Count".equals(((LdcInsnNode) in).cst)) {
+ it.next();
+ it.next();
+ it.next();
+ AbstractInsnNode in2 = it.next();
+ if (in2.getOpcode() == Opcodes.INVOKEVIRTUAL) {
+ // :thinking:
+ boolean patched = false;
+ MethodInsnNode min2 = (MethodInsnNode) in2;
+ if (min2.name.equals("setByte")) {
+ min2.name = "setInteger";
+ patched = true;
+ } else if (min2.name.equals("func_74774_a")) {
+ min2.name = "func_74768_a";
+ patched = true;
+ }
+
+ if (patched) {
+ min2.desc = "(Ljava/lang/String;I)V";
+ System.out.println("Patched ItemStack Count setter!");
+
+ // Remove I2B cast
+ it.previous();
+ it.previous();
+ it.remove();
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}