diff --git a/src/main/java/appeng/client/render/model/UVLModelLoader.java b/src/main/java/appeng/client/render/model/UVLModelLoader.java index d5fbe3e4e..7873fc500 100644 --- a/src/main/java/appeng/client/render/model/UVLModelLoader.java +++ b/src/main/java/appeng/client/render/model/UVLModelLoader.java @@ -32,6 +32,7 @@ import net.minecraft.client.resources.IResourceManager; import net.minecraft.util.EnumFacing; import net.minecraft.util.JsonUtils; import net.minecraft.util.ResourceLocation; +import net.minecraftforge.client.EnumHelperClient; import net.minecraftforge.client.model.ICustomModelLoader; import net.minecraftforge.client.model.IModel; import net.minecraftforge.client.model.ModelLoader; @@ -54,7 +55,6 @@ import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.reflect.Constructor; import java.lang.reflect.Field; -import java.lang.reflect.Modifier; import java.lang.reflect.Type; import java.util.Collection; import java.util.HashMap; @@ -74,11 +74,7 @@ public enum UVLModelLoader implements ICustomModelLoader { static { try { - Field modifiers = Field.class.getDeclaredField("modifiers"); - modifiers.setAccessible(true); - faceBakery = ReflectionHelper.findField(ModelBakery.class, "faceBakery", "field_177607_l"); - modifiers.set(faceBakery, faceBakery.getModifiers() & (~Modifier.FINAL)); Class clas = Class.forName(ModelLoader.class.getName() + "$VanillaModelWrapper"); vanillaModelWrapper = clas.getDeclaredConstructor(ModelLoader.class, ResourceLocation.class, ModelBlock.class, boolean.class, @@ -118,7 +114,7 @@ public enum UVLModelLoader implements ICustomModelLoader { private static void setFaceBakery(ModelBakery modelBakery, FaceBakery faceBakery) { try { - UVLModelLoader.faceBakery.set(modelBakery, faceBakery); + EnumHelperClient.setFailsafeFieldValue(UVLModelLoader.faceBakery, modelBakery, faceBakery); } catch (Exception e) { throw Throwables.propagate(e); } diff --git a/src/main/java/appeng/core/api/ApiPart.java b/src/main/java/appeng/core/api/ApiPart.java index 5d3dacb08..34a6ad7b0 100644 --- a/src/main/java/appeng/core/api/ApiPart.java +++ b/src/main/java/appeng/core/api/ApiPart.java @@ -41,8 +41,8 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.commons.ClassRemapper; import org.objectweb.asm.commons.Remapper; -import org.objectweb.asm.commons.RemappingClassAdapter; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.MethodInsnNode; @@ -150,7 +150,7 @@ public class ApiPart implements IPartHelper { final DefaultPackageClassNameRemapper remapper = new DefaultPackageClassNameRemapper(); remapper.inputOutput.put("appeng/api/parts/LayerBase", n.superName); remapper.inputOutput.put(originalName, n.name); - n.accept(new RemappingClassAdapter(cw, remapper)); + n.accept(new ClassRemapper(cw, remapper)); // n.accept( cw ); // n.accept( new TraceClassVisitor( new PrintWriter( System.out ) ) ); diff --git a/src/main/java/appeng/core/transformer/AE2ELTransformer.java b/src/main/java/appeng/core/transformer/AE2ELTransformer.java index 33d86cd8c..10ee3b9bd 100644 --- a/src/main/java/appeng/core/transformer/AE2ELTransformer.java +++ b/src/main/java/appeng/core/transformer/AE2ELTransformer.java @@ -19,32 +19,53 @@ package appeng.core.transformer; +import appeng.core.AE2ELCore; +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; +import com.google.common.io.ByteStreams; import net.minecraft.launchwrapper.IClassTransformer; +import net.minecraftforge.fml.common.Loader; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.commons.ClassRemapper; +import org.objectweb.asm.commons.Remapper; +import org.objectweb.asm.tree.*; +import java.io.IOException; +import java.io.InputStream; +import java.util.List; +import java.util.ListIterator; +import java.util.Set; import java.util.function.Consumer; public class AE2ELTransformer implements IClassTransformer { @Override public byte[] transform(String name, String transformedName, byte[] basicClass) { + if (Loader.instance().getIndexedModList().get("stackup") != null) { + return 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); + } else if ("net.minecraft.network.PacketBuffer".equals(transformedName)) { + consumer = consumer.andThen((node) -> { + spliceClasses(node, "appeng.core.transformer.PacketBufferPatch", + "readItemStack", "func_150791_c", + "writeItemStack", "func_150788_a"); + }); } if (consumer != emptyConsumer) { return processNode(basicClass, consumer); } else { - return data; + return basicClass; } } @@ -58,4 +79,106 @@ public class AE2ELTransformer implements IClassTransformer { return writer.toByteArray(); } + public static void spliceClasses(final ClassNode data, final String className, final String... methods) { + try (InputStream stream = AE2ELCore.class.getClassLoader().getResourceAsStream(className.replace('.', '/') + ".class")) { + spliceClasses(data, ByteStreams.toByteArray(stream), className, methods); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + + public static void spliceClasses(final ClassNode nodeData, final byte[] dataSplice, final String className, final String... methods) { + // System.out.println("Splicing from " + className + " to " + targetClassName) + if (dataSplice == null) { + throw new RuntimeException("Class " + className + " not found! This is a AE2EL bug!"); + } + + final Set methodSet = Sets.newHashSet(methods); + final List methodList = Lists.newArrayList(methods); + + final ClassReader readerSplice = new ClassReader(dataSplice); + final String className2 = className.replace('.', '/'); + final String targetClassName2 = nodeData.name; + final String targetClassName = targetClassName2.replace('/', '.'); + final Remapper remapper = new Remapper() { + public String map(final String name) { + return className2.equals(name) ? targetClassName2 : name; + } + }; + + ClassNode nodeSplice = new ClassNode(); + readerSplice.accept(new ClassRemapper(nodeSplice, remapper), ClassReader.EXPAND_FRAMES); + for (String s : nodeSplice.interfaces) { + if (methodSet.contains(s)) { + nodeData.interfaces.add(s); + System.out.println("Added INTERFACE: " + s); + } + } + + for (int i = 0; i < nodeSplice.methods.size(); i++) { + if (methodSet.contains(nodeSplice.methods.get(i).name)) { + MethodNode mn = nodeSplice.methods.get(i); + boolean added = false; + + for (int j = 0; j < nodeData.methods.size(); j++) { + if (nodeData.methods.get(j).name.equals(mn.name) + && nodeData.methods.get(j).desc.equals(mn.desc)) { + MethodNode oldMn = nodeData.methods.get(j); + System.out.println("Spliced in METHOD: " + targetClassName + "." + mn.name); + nodeData.methods.set(j, mn); + if (nodeData.name.equals(nodeSplice.superName)) { + ListIterator nodeListIterator = mn.instructions.iterator(); + while (nodeListIterator.hasNext()) { + AbstractInsnNode node = nodeListIterator.next(); + if (node instanceof MethodInsnNode + && node.getOpcode() == Opcodes.INVOKESPECIAL) { + MethodInsnNode methodNode = (MethodInsnNode) node; + if (targetClassName2.equals(methodNode.owner)) { + methodNode.owner = nodeData.superName; + } + } + } + } + + oldMn.name = methodList.get((methodList.indexOf(oldMn.name)) & (~1)) + "_ae2el_old"; + nodeData.methods.add(oldMn); + added = true; + break; + } + } + + if (!added) { + System.out.println("Added METHOD: " + targetClassName + "." + mn.name); + nodeData.methods.add(mn); + added = true; + } + } + } + + for (int i = 0; i < nodeSplice.fields.size(); i++) { + if (methodSet.contains(nodeSplice.fields.get(i).name)) { + FieldNode mn = nodeSplice.fields.get(i); + boolean added = false; + + for (int j = 0; j < nodeData.fields.size(); j++) { + if (nodeData.fields.get(j).name.equals(mn.name) + && nodeData.fields.get(j).desc.equals(mn.desc)) { + System.out.println("Spliced in FIELD: " + targetClassName + "." + mn.name); + nodeData.fields.set(j, mn); + added = true; + break; + } + } + + if (!added) { + System.out.println("Added FIELD: " + targetClassName + "." + mn.name); + nodeData.fields.add(mn); + added = true; + } + } + } + + } + } diff --git a/src/main/java/appeng/core/transformer/ItemStackPatch.java b/src/main/java/appeng/core/transformer/ItemStackPatch.java index 80d5d3226..389058ee4 100644 --- a/src/main/java/appeng/core/transformer/ItemStackPatch.java +++ b/src/main/java/appeng/core/transformer/ItemStackPatch.java @@ -20,11 +20,7 @@ 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 org.objectweb.asm.tree.*; import java.util.ListIterator; diff --git a/src/main/java/appeng/core/transformer/PacketBufferPatch.java b/src/main/java/appeng/core/transformer/PacketBufferPatch.java new file mode 100644 index 000000000..ade67b57b --- /dev/null +++ b/src/main/java/appeng/core/transformer/PacketBufferPatch.java @@ -0,0 +1,78 @@ +package appeng.core.transformer; + +/* + * 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 . + */ + +import io.netty.buffer.ByteBuf; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.network.PacketBuffer; + +import java.io.IOException; + +public class PacketBufferPatch extends PacketBuffer { + + public PacketBufferPatch(ByteBuf wrapped) { + super(wrapped); + } + + @Override + public ItemStack readItemStack() throws IOException { + int id = this.readShort(); + + if (id < 0) { + return ItemStack.EMPTY; + } else { + int count = this.readByte(); + if (count == -42) { + count = this.readInt(); + } + int damage = this.readShort(); + ItemStack itemstack = new ItemStack(Item.getItemById(id), count, damage); + itemstack.getItem().readNBTShareTag(itemstack, this.readCompoundTag()); + return itemstack; + } + } + + @Override + public PacketBuffer writeItemStack(ItemStack stack) { + if (stack.isEmpty()) { + this.writeShort(-1); + } else { + this.writeShort(Item.getIdFromItem(stack.getItem())); + if (stack.getCount() >= 0 && stack.getCount() <= 64) { + this.writeByte(stack.getCount()); + } else { + this.writeByte(-42); + this.writeInt(stack.getCount()); + } + this.writeShort(stack.getMetadata()); + NBTTagCompound tag = null; + + if (stack.getItem().isDamageable() || stack.getItem().getShareTag()) { + tag = stack.getItem().getNBTShareTag(stack); + } + + this.writeCompoundTag(tag); + } + + return this; + } +}