package net.fybertech.dynamicmappings.mappers; import java.util.*; import net.fybertech.dynamicmappings.*; import net.fybertech.dynamicmappings.MethodCallIterator.MethodCall; import net.fybertech.meddle.MeddleUtil; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.FieldInsnNode; import org.objectweb.asm.tree.FieldNode; import org.objectweb.asm.tree.IntInsnNode; import org.objectweb.asm.tree.LdcInsnNode; import org.objectweb.asm.tree.MethodInsnNode; import org.objectweb.asm.tree.MethodNode; import org.objectweb.asm.tree.TableSwitchInsnNode; import org.objectweb.asm.tree.TypeInsnNode; import org.objectweb.asm.tree.VarInsnNode; public class SharedMappings extends MappingsBase { // The starting point @Mapping(provides="net/minecraft/server/MinecraftServer") public boolean getMinecraftServerClass() { ClassNode cn = getClassNode("net/minecraft/server/MinecraftServer"); if (cn == null) return false; addClassMapping("net/minecraft/server/MinecraftServer", cn); return true; } @Mapping(provides="net/minecraft/world/World", depends="net/minecraft/server/MinecraftServer") public boolean getWorldClass() { ClassNode server = getClassNode(getClassMapping("net/minecraft/server/MinecraftServer")); if (server == null) return false; List<String> potentialClasses = new ArrayList<String>(); // Fetch all obfuscated classes used inside MinecraftServer's interfaces for (String interfaceClass : server.interfaces) { if (interfaceClass.contains("/")) continue; ClassNode node = getClassNode(interfaceClass); if (node == null) continue; for (MethodNode method : node.methods) { Type returnType = Type.getReturnType(method.desc); if (returnType.getSort() == Type.OBJECT) { if (!returnType.getClassName().contains(".")) potentialClasses.add(returnType.getClassName()); } } } String[] matchStrings = new String[] { "Getting biome", "chunkCheck", "Level name", "Chunk stats" }; // Search constant pools of potential classes for strings matching the list above for (String className : potentialClasses) { if (searchConstantPoolForStrings(className, matchStrings)) { ClassNode worldClass = getClassNode(className); addClassMapping("net/minecraft/world/World", worldClass); return true; } } return false; } @Mapping(provides={ "net/minecraft/world/WorldType", "net/minecraft/world/WorldServer" }, providesMethods={ "net/minecraft/server/MinecraftServer loadAllWorlds (Ljava/lang/String;Ljava/lang/String;JLnet/minecraft/world/WorldType;Ljava/lang/String;)V" }, depends={ "net/minecraft/server/MinecraftServer" }) public boolean getWorldServerClass() { ClassNode server = getClassNode("net/minecraft/server/MinecraftServer"); if (server == null) return false; // protected void loadAllWorlds(String p_71247_1_, String p_71247_2_, long seed, WorldType type, String p_71247_6_) List<MethodNode> methods = new ArrayList<>(); for (MethodNode method : server.methods) { if (method.desc.startsWith("(Ljava/lang/String;Ljava/lang/String;JL") && method.desc.endsWith(";Ljava/lang/String;)V")) { Type t = Type.getMethodType(method.desc); if (t.getArgumentTypes().length == 5) methods.add(method); } } // net/minecraft/world/WorldType // net/minecraft/world/WorldServer if (methods.size() == 1) { Type t = Type.getMethodType(methods.get(0).desc); Type[] args = t.getArgumentTypes(); String worldType = args[3].getClassName(); if (!searchConstantPoolForStrings(worldType, "default", "flat", "amplified")) return false; addClassMapping("net/minecraft/world/WorldType", worldType); addMethodMapping("net/minecraft/server/MinecraftServer loadAllWorlds (Ljava/lang/String;Ljava/lang/String;JLnet/minecraft/world/WorldType;Ljava/lang/String;)V", server.name + " " + methods.get(0).name + " " + methods.get(0).desc); List<String> worldServerNames = new ArrayList<>(); List<TypeInsnNode> list = getAllInsnNodesOfType(methods.get(0).instructions.getFirst(), TypeInsnNode.class); for (TypeInsnNode mn : list) { if (mn.getOpcode() != Opcodes.NEW) continue; if (searchConstantPoolForStrings(mn.desc, "doDaylightCycle", "playerCheckLight", "Saving level") && !worldServerNames.contains(mn.desc)) worldServerNames.add(mn.desc); } if (worldServerNames.size() == 1) { addClassMapping("net/minecraft/world/WorldServer", worldServerNames.get(0)); } } return true; } @Mapping(provides={ "net/minecraft/util/IThreadListener" }, depends={ "net/minecraft/world/WorldServer" }) public boolean processWorldServerClass() { ClassNode worldServer = getClassNodeFromMapping("net/minecraft/world/WorldServer"); if (worldServer == null) return false; List<String> ifaces = new ArrayList<>(); for (String iface : worldServer.interfaces) { ClassNode cn = getClassNode(iface); for (MethodNode method : cn.methods) { if (method.desc.equals("(Ljava/lang/Runnable;)Lcom/google/common/util/concurrent/ListenableFuture;") && !ifaces.contains(iface)) ifaces.add(iface); } } if (ifaces.size() == 1) { addClassMapping("net/minecraft/util/IThreadListener", ifaces.get(0)); } return true; } @Mapping(providesMethods={ "net/minecraft/util/IThreadListener addScheduledTask (Ljava/lang/Runnable;)Lcom/google/common/util/concurrent/ListenableFuture;", "net/minecraft/util/IThreadListener isCallingFromMinecraftThread ()Z" }, depends={ "net/minecraft/util/IThreadListener" }) public boolean processIThreadListenerClass() { ClassNode threadListener = getClassNodeFromMapping("net/minecraft/util/IThreadListener"); if (threadListener == null) return false; // ListenableFuture addScheduledTask(Runnable runnableToSchedule); List<MethodNode> methods = getMatchingMethods(threadListener, null, "(Ljava/lang/Runnable;)Lcom/google/common/util/concurrent/ListenableFuture;"); if (methods.size() == 1) { addMethodMapping("net/minecraft/util/IThreadListener addScheduledTask (Ljava/lang/Runnable;)Lcom/google/common/util/concurrent/ListenableFuture;", threadListener.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // boolean isCallingFromMinecraftThread(); methods = getMatchingMethods(threadListener, null, "()Z"); if (methods.size() == 1) { addMethodMapping("net/minecraft/util/IThreadListener isCallingFromMinecraftThread ()Z", threadListener.name + " " + methods.get(0).name + " " + methods.get(0).desc); } return true; } @Mapping(provides="net/minecraft/init/Blocks", depends="net/minecraft/world/World") public boolean getBlocksClass() { ClassNode worldClass = getClassNodeFromMapping("net/minecraft/world/World"); if (worldClass == null) return false; Set<String> potentialClasses = new HashSet<String>(); // Discover and filter all static fields accessed in World's methods for (MethodNode method : worldClass.methods) { for (AbstractInsnNode node = method.instructions.getFirst(); node != null; node = node.getNext()) { if (node.getOpcode() != Opcodes.GETSTATIC) continue; FieldInsnNode fieldNode = (FieldInsnNode)node; if (!fieldNode.desc.startsWith("L") || fieldNode.desc.contains("/")) continue; String descClass = Type.getType(fieldNode.desc).getClassName(); if (fieldNode.owner.equals(descClass)) continue; potentialClasses.add(fieldNode.owner); } } String[] matchStrings = new String[] { "Accessed Blocks before Bootstrap!", "air", "stone" }; // Find net.minecraft.init.Blocks from what's left for (String className : potentialClasses) { if (searchConstantPoolForStrings(className, matchStrings)) { ClassNode blocksClass = getClassNode(className); addClassMapping("net/minecraft/init/Blocks", blocksClass); return true; } } return false; } @Mapping(provides="net/minecraft/block/Block", depends="net/minecraft/init/Blocks") public boolean getBlockClass() { ClassNode blocksClass = getClassNode(getClassMapping("net/minecraft/init/Blocks")); if (blocksClass == null) return false; Map<String, Integer> classes = new HashMap<String, Integer>(); // Make a tally of how many times a class was used in the field descriptors for (FieldNode field : blocksClass.fields) { String descClass = Type.getType(field.desc).getClassName(); int val = (classes.containsKey(descClass) ? classes.get(descClass) : 0); val++; classes.put(descClass, val); } String mostClass = null; int mostCount = 0; // Find the one with the highest count for (String key : classes.keySet()) { if (classes.get(key) > mostCount) { mostClass = key; mostCount = classes.get(key); } } // The standard Block class is used far more than any other, so we've found it if (mostCount > 100) { ClassNode blockClass = getClassNode(mostClass); addClassMapping("net/minecraft/block/Block", blockClass); return true; } return false; } @Mapping(provides="net/minecraft/block/state/BlockState", depends="net/minecraft/block/Block") public boolean getBlockStateClass() { ClassNode block = getClassNode(getClassMapping("net/minecraft/block/Block")); if (block == null) return false; for (FieldNode fn : block.fields) { Type t = Type.getType(fn.desc); if (t.getSort() != Type.OBJECT) continue; if (searchConstantPoolForStrings(t.getClassName(), "block", "properties", "Block: ", " has invalidly named property: ")) { addClassMapping("net/minecraft/block/state/BlockState", t.getClassName()); return true; } } return false; } @Mapping(provides="net/minecraft/block/state/IBlockState", depends="net/minecraft/block/Block") public boolean getIBlockStateClass() { ClassNode block = getClassNode(getClassMapping("net/minecraft/block/Block")); if (block == null) return false; List<MethodNode> methods = getMatchingMethods(block, null, null); methods = removeMethodsWithoutFlags(methods, Opcodes.ACC_STATIC); // Identify method: IBlockState getStateById(int param0) for (Iterator<MethodNode> it = methods.iterator(); it.hasNext();) { MethodNode method = it.next(); if (method.desc.equals("(I)L" + block.name + ";")) {} else if (method.desc.startsWith("(I)L")) continue; it.remove(); } if (methods.size() == 1) { MethodNode method = methods.get(0); Type t = Type.getMethodType(method.desc).getReturnType(); // Make sure it's an interface ClassNode cn = getClassNode(t.getClassName()); if ((cn.access & Opcodes.ACC_INTERFACE) == 0) return false; // Not the best test, but see if the getBlock() method exists boolean check = false; for (MethodNode m : cn.methods) { if (m.desc.equals("()L" + block.name + ";")) check = true; } if (check) addClassMapping("net/minecraft/block/state/IBlockState", cn.name); else return false; } return true; } @Mapping(provides={ "net/minecraft/block/state/IBlockWrapper", "net/minecraft/block/state/IBlockEvents" }, providesMethods={ "net/minecraft/block/state/IBlockState getPropertyNames ()Ljava/util/Collection;", "net/minecraft/block/state/IBlockState getValue (Lnet/minecraft/block/properties/IProperty;)Ljava/lang/Comparable;", "net/minecraft/block/state/IBlockState withProperty (Lnet/minecraft/block/properties/IProperty;Ljava/lang/Comparable;)Lnet/minecraft/block/state/IBlockState;", "net/minecraft/block/state/IBlockState cycleProperty (Lnet/minecraft/block/properties/IProperty;)Lnet/minecraft/block/state/IBlockState;", "net/minecraft/block/state/IBlockState getProperties ()Lcom/google/common/collect/ImmutableMap;", "net/minecraft/block/state/IBlockState getBlock ()Lnet/minecraft/block/Block;" }, depends={ "net/minecraft/block/Block", "net/minecraft/block/state/IBlockState", "net/minecraft/block/properties/IProperty" }) public boolean processIBlockStateClass() { ClassNode block = getClassNode(getClassMapping("net/minecraft/block/Block")); ClassNode iBlockState = getClassNodeFromMapping("net/minecraft/block/state/IBlockState"); ClassNode iProperty = getClassNodeFromMapping("net/minecraft/block/properties/IProperty"); if (block == null || iBlockState == null || iProperty == null) return false; if (iBlockState.interfaces.size() == 2) { //addClassMapping("net/minecraft/block/state/IBlockWrapper", iBlockState.interfaces.get(0)); ClassNode cn1 = getClassNode(iBlockState.interfaces.get(0)); ClassNode cn2 = getClassNode(iBlockState.interfaces.get(1)); if (cn1 != null && cn2 != null) { String wrapperName = null; String eventsName = null; int cn1Size = cn1.methods.size(); int cn2Size = cn2.methods.size(); // Just do a simple method count check between the two interfaces if (cn1Size > 20 && cn2Size < cn1Size) { wrapperName = cn1.name; eventsName = cn2.name; } if (cn2Size > 20 && cn1Size < cn2Size) { wrapperName = cn2.name; eventsName = cn1.name; } if (wrapperName != null && eventsName != null) { addClassMapping("net/minecraft/block/state/IBlockWrapper", wrapperName); addClassMapping("net/minecraft/block/state/IBlockEvents", eventsName); } } } // Collection getPropertyNames(); List<MethodNode> methods = getMatchingMethods(iBlockState, null, "()Ljava/util/Collection;"); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/state/IBlockState getPropertyNames ()Ljava/util/Collection;", iBlockState.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // Comparable getValue(IProperty property); methods = getMatchingMethods(iBlockState, null, "(L" + iProperty.name + ";)Ljava/lang/Comparable;"); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/state/IBlockState getValue (Lnet/minecraft/block/properties/IProperty;)Ljava/lang/Comparable;", iBlockState.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // IBlockState withProperty(IProperty property, Comparable value); methods = getMatchingMethods(iBlockState, null, "(L" + iProperty.name + ";Ljava/lang/Comparable;)L" + iBlockState.name + ";"); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/state/IBlockState withProperty (Lnet/minecraft/block/properties/IProperty;Ljava/lang/Comparable;)Lnet/minecraft/block/state/IBlockState;", iBlockState.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // IBlockState cycleProperty(IProperty property); methods = getMatchingMethods(iBlockState, null, "(L" + iProperty.name + ";)L" + iBlockState.name + ";"); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/state/IBlockState cycleProperty (Lnet/minecraft/block/properties/IProperty;)Lnet/minecraft/block/state/IBlockState;", iBlockState.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // ImmutableMap getProperties(); methods = getMatchingMethods(iBlockState, null, "()Lcom/google/common/collect/ImmutableMap;"); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/state/IBlockState getProperties ()Lcom/google/common/collect/ImmutableMap;", iBlockState.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // Block getBlock(); methods = getMatchingMethods(iBlockState, null, "()L" + block.name + ";"); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/state/IBlockState getBlock ()Lnet/minecraft/block/Block;", iBlockState.name + " " + methods.get(0).name + " " + methods.get(0).desc); } return true; } @Mapping(providesMethods={ "net/minecraft/block/state/IBlockEvents onBlockEventReceived (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;II)Z", "net/minecraft/block/state/IBlockEvents onNeighborBlockChange (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;Lnet/minecraft/block/Block;Lnet/minecraft/util/BlockPos;)V" }, depends={ "net/minecraft/world/World", "net/minecraft/block/Block", "net/minecraft/util/BlockPos", "net/minecraft/block/state/IBlockState", "net/minecraft/block/state/IBlockEvents" }) public boolean processIBlockEvents() { ClassNode iBlockEvents = getClassNodeFromMapping("net/minecraft/block/state/IBlockEvents"); ClassNode world = getClassNodeFromMapping("net/minecraft/world/World"); ClassNode blockPos = getClassNodeFromMapping("net/minecraft/util/BlockPos"); ClassNode block = getClassNodeFromMapping("net/minecraft/block/Block"); ClassNode iBlockState = getClassNodeFromMapping("net/minecraft/block/state/IBlockState"); if (world == null || blockPos == null || iBlockState == null) return false; List<MethodNode> methods = getMatchingMethods(iBlockEvents, null, assembleDescriptor("(", world, blockPos, "II)Z")); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/state/IBlockEvents onBlockEventReceived (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;II)Z", iBlockEvents.name + " " + methods.get(0).name + " " + methods.get(0).desc); } methods = getMatchingMethods(iBlockEvents, null, assembleDescriptor("(", world, blockPos, block, blockPos, ")V")); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/state/IBlockEvents onNeighborBlockChange (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;Lnet/minecraft/block/Block;Lnet/minecraft/util/BlockPos;)V", iBlockEvents.name + " " + methods.get(0).name + " " + methods.get(0).desc); } return true; } @Mapping(provides="net/minecraft/world/IBlockAccess", depends="net/minecraft/world/World") public boolean getIBlockAccessClass() { ClassNode world = getClassNode(getClassMapping("net/minecraft/world/World")); if (world == null) return false; // We won't know for sure if they added more interfaces if (world.interfaces.size() != 1) return false; ClassNode classBlockAccess = getClassNode(world.interfaces.get(0)); addClassMapping("net/minecraft/world/IBlockAccess", classBlockAccess); return true; } @Mapping(providesMethods={ "net/minecraft/world/IBlockAccess getTileEntity (Lnet/minecraft/util/BlockPos;)Lnet/minecraft/tileentity/TileEntity;", "net/minecraft/world/IBlockAccess getBlockState (Lnet/minecraft/util/BlockPos;)Lnet/minecraft/block/state/IBlockState;", "net/minecraft/world/IBlockAccess isAirBlock (Lnet/minecraft/util/BlockPos;)Z", "net/minecraft/world/IBlockAccess getStrongPower (Lnet/minecraft/util/BlockPos;Lnet/minecraft/util/EnumFacing;)I" }, depends={ "net/minecraft/world/IBlockAccess", "net/minecraft/block/state/IBlockState", "net/minecraft/tileentity/TileEntity", "net/minecraft/util/BlockPos", "net/minecraft/util/EnumFacing" }) public boolean processIBlockAccessClass() { ClassNode iBlockAccess = getClassNodeFromMapping("net/minecraft/world/IBlockAccess"); ClassNode iBlockState = getClassNodeFromMapping("net/minecraft/block/state/IBlockState"); ClassNode tileEntity = getClassNodeFromMapping("net/minecraft/tileentity/TileEntity"); ClassNode blockPos = getClassNodeFromMapping("net/minecraft/util/BlockPos"); ClassNode enumFacing = getClassNodeFromMapping("net/minecraft/util/EnumFacing"); if (!MeddleUtil.notNull(iBlockAccess, iBlockState, tileEntity, blockPos, enumFacing)) return false; // TileEntity getTileEntity(BlockPos pos) List<MethodNode> methods = getMatchingMethods(iBlockAccess, null, assembleDescriptor("(", blockPos, ")", tileEntity)); if (methods.size() == 1) { addMethodMapping("net/minecraft/world/IBlockAccess getTileEntity (Lnet/minecraft/util/BlockPos;)Lnet/minecraft/tileentity/TileEntity;", iBlockAccess.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // IBlockState getBlockState(BlockPos pos) methods = getMatchingMethods(iBlockAccess, null, assembleDescriptor("(", blockPos, ")", iBlockState)); if (methods.size() == 1) { addMethodMapping("net/minecraft/world/IBlockAccess getBlockState (Lnet/minecraft/util/BlockPos;)Lnet/minecraft/block/state/IBlockState;", iBlockAccess.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // boolean isAirBlock(BlockPos pos); methods = getMatchingMethods(iBlockAccess, null, assembleDescriptor("(", blockPos, ")Z")); if (methods.size() == 1) { addMethodMapping("net/minecraft/world/IBlockAccess isAirBlock (Lnet/minecraft/util/BlockPos;)Z", iBlockAccess.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // int getStrongPower(BlockPos pos, EnumFacing direction) methods = getMatchingMethods(iBlockAccess, null, assembleDescriptor("(", blockPos, enumFacing, ")I")); if (methods.size() == 1) { addMethodMapping("net/minecraft/world/IBlockAccess getStrongPower (Lnet/minecraft/util/BlockPos;Lnet/minecraft/util/EnumFacing;)I", iBlockAccess.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // @ClientOnly // int getCombinedLight(BlockPos pos, int lightValue) // @ClientOnly // BiomeGenBase getBiomeGenForCoords(BlockPos pos); // @ClientOnly // boolean extendedLevelsInChunkCache(); // @ClientOnly // WorldType getWorldType(); return true; } @Mapping(provides="net/minecraft/util/BlockPos", depends="net/minecraft/block/Block") public boolean getBlockPosClass() { ClassNode block = getClassNode(getClassMapping("net/minecraft/block/Block")); if (block == null) return false; Map<String, Integer> counts = new HashMap<String, Integer>(); // Count the times a class is used as the second parameter of a method for (MethodNode method : block.methods) { Type t = Type.getMethodType(method.desc); Type[] args = t.getArgumentTypes(); if (args.length < 2) continue; String name = args[1].getClassName(); int count = (counts.containsKey(name) ? counts.get(name) : 0); count++; counts.put(name, count); } int max = 0; String maxClass = null; // Find the one with the most for (String key : counts.keySet()) { int count = counts.get(key); if (count > max) { max = count; maxClass = key; } } // It should be over 30 if (max < 10) return false; ClassNode blockPos = getClassNode(maxClass); addClassMapping("net/minecraft/util/BlockPos", blockPos); return true; } @Mapping(provides={ "net/minecraft/util/Vec3i" }, providesMethods={ "net/minecraft/util/BlockPos down (I)Lnet/minecraft/util/BlockPos;", "net/minecraft/util/BlockPos up (I)Lnet/minecraft/util/BlockPos;", "net/minecraft/util/BlockPos north (I)Lnet/minecraft/util/BlockPos;", "net/minecraft/util/BlockPos south (I)Lnet/minecraft/util/BlockPos;", "net/minecraft/util/BlockPos west (I)Lnet/minecraft/util/BlockPos;", "net/minecraft/util/BlockPos east (I)Lnet/minecraft/util/BlockPos;", "net/minecraft/util/BlockPos down ()Lnet/minecraft/util/BlockPos;", "net/minecraft/util/BlockPos up ()Lnet/minecraft/util/BlockPos;", "net/minecraft/util/BlockPos north ()Lnet/minecraft/util/BlockPos;", "net/minecraft/util/BlockPos south ()Lnet/minecraft/util/BlockPos;", "net/minecraft/util/BlockPos west ()Lnet/minecraft/util/BlockPos;", "net/minecraft/util/BlockPos east ()Lnet/minecraft/util/BlockPos;", "net/minecraft/util/BlockPos offset (Lnet/minecraft/util/EnumFacing;)Lnet/minecraft/util/BlockPos;" }, dependsFields={ "net/minecraft/util/EnumFacing DOWN Lnet/minecraft/util/EnumFacing;", "net/minecraft/util/EnumFacing UP Lnet/minecraft/util/EnumFacing;", "net/minecraft/util/EnumFacing NORTH Lnet/minecraft/util/EnumFacing;", "net/minecraft/util/EnumFacing SOUTH Lnet/minecraft/util/EnumFacing;", "net/minecraft/util/EnumFacing WEST Lnet/minecraft/util/EnumFacing;", "net/minecraft/util/EnumFacing EAST Lnet/minecraft/util/EnumFacing;" }, depends={ "net/minecraft/util/BlockPos", "net/minecraft/util/EnumFacing" }) public boolean processBlockPosClass() { ClassNode blockPos = getClassNodeFromMapping("net/minecraft/util/BlockPos"); ClassNode enumFacing = getClassNodeFromMapping("net/minecraft/util/EnumFacing"); if (blockPos == null || enumFacing == null) return false; if (searchConstantPoolForStrings(blockPos.superName, "x", "y", "z")) { addClassMapping("net/minecraft/util/Vec3i", blockPos.superName); } FieldNode[] facings = new FieldNode[6]; facings[0] = getFieldNodeFromMapping(enumFacing, "net/minecraft/util/EnumFacing DOWN Lnet/minecraft/util/EnumFacing;"); facings[1] = getFieldNodeFromMapping(enumFacing, "net/minecraft/util/EnumFacing UP Lnet/minecraft/util/EnumFacing;"); facings[2] = getFieldNodeFromMapping(enumFacing, "net/minecraft/util/EnumFacing NORTH Lnet/minecraft/util/EnumFacing;"); facings[3] = getFieldNodeFromMapping(enumFacing, "net/minecraft/util/EnumFacing SOUTH Lnet/minecraft/util/EnumFacing;"); facings[4] = getFieldNodeFromMapping(enumFacing, "net/minecraft/util/EnumFacing WEST Lnet/minecraft/util/EnumFacing;"); facings[5] = getFieldNodeFromMapping(enumFacing, "net/minecraft/util/EnumFacing EAST Lnet/minecraft/util/EnumFacing;"); for (int n = 0; n < 6; n++) { if (facings[n] == null) return false; } String[] dirs = new String[] { "down", "up", "north", "south", "west", "east" }; MethodNode[] offsetMethods = new MethodNode[6]; List<MethodNode> methods = getMatchingMethods(blockPos, null, "(I)L" + blockPos.name + ";"); if (methods.size() == 6) { for (int methodNum = 0; methodNum < 6; methodNum++) { AbstractInsnNode insn = findNextOpcodeNum(methods.get(methodNum).instructions.getFirst(), Opcodes.GETSTATIC); if (insn == null) continue; FieldInsnNode fn = (FieldInsnNode)insn; if (!fn.owner.equals(enumFacing.name) || !fn.desc.equals("L" + enumFacing.name + ";")) continue; for (int dirNum = 0; dirNum < 6; dirNum++) { if (facings[dirNum].name.equals(fn.name)) { addMethodMapping("net/minecraft/util/BlockPos " + dirs[dirNum] + " (I)Lnet/minecraft/util/BlockPos;", blockPos.name + " " + methods.get(methodNum).name + " " + methods.get(methodNum).desc); offsetMethods[dirNum] = methods.get(methodNum); } } } } // Went from 6 to 7 matching methods in 15w39c methods = getMatchingMethods(blockPos, null, "()L" + blockPos.name + ";"); if (methods.size() >= 6) { for (MethodNode method : methods) { AbstractInsnNode insn = findNextOpcodeNum(method.instructions.getFirst(), Opcodes.INVOKEVIRTUAL); if (insn == null) continue; MethodInsnNode mn = (MethodInsnNode)insn; if (!mn.owner.equals(blockPos.name) || !mn.desc.equals("(I)L" + blockPos.name + ";")) continue; for (int dirNum = 0; dirNum < 6; dirNum++) { if (offsetMethods[dirNum].name.equals(mn.name)) { addMethodMapping("net/minecraft/util/BlockPos " + dirs[dirNum] + " ()Lnet/minecraft/util/BlockPos;", blockPos.name + " " + method.name + " " + method.desc); } } } } // public BlockPos offset(EnumFacing facing) methods = getMatchingMethods(blockPos, null, "(L" + enumFacing.name + ";)L" + blockPos.name + ";"); if (methods.size() == 1) { addMethodMapping("net/minecraft/util/BlockPos offset (Lnet/minecraft/util/EnumFacing;)Lnet/minecraft/util/BlockPos;", blockPos.name + " " + methods.get(0).name + " " + methods.get(0).desc); } return true; } @Mapping(providesFields={ "net/minecraft/util/Vec3i x I", "net/minecraft/util/Vec3i y I", "net/minecraft/util/Vec3i z I" }, providesMethods={ "net/minecraft/util/Vec3i getX ()I", "net/minecraft/util/Vec3i getY ()I", "net/minecraft/util/Vec3i getZ ()I" }, depends={ "net/minecraft/util/Vec3i" }) public boolean processVec3iClass() { ClassNode vec3i = getClassNodeFromMapping("net/minecraft/util/Vec3i"); if (vec3i == null) return false; String x = null; String y = null; String z = null; List<FieldNode> fields = getMatchingFields(vec3i, null, "I"); if (fields.size() == 3) { x = fields.get(0).name; y = fields.get(1).name; z = fields.get(2).name; addFieldMapping("net/minecraft/util/Vec3i x I", vec3i.name + " " + x + " I"); addFieldMapping("net/minecraft/util/Vec3i y I", vec3i.name + " " + y + " I"); addFieldMapping("net/minecraft/util/Vec3i z I", vec3i.name + " " + z + " I"); } // public int getX() // public int getY() // public int getZ() List<MethodNode> methods = getMatchingMethods(vec3i, null, "()I"); for (MethodNode method : methods) { if (matchOpcodeSequence(method.instructions.getFirst(), Opcodes.ALOAD, Opcodes.GETFIELD, Opcodes.IRETURN)) { FieldInsnNode fn = (FieldInsnNode)findNextOpcodeNum(method.instructions.getFirst(), Opcodes.GETFIELD); if (!fn.owner.equals(vec3i.name) || !fn.desc.equals("I")) continue; if (fn.name.equals(x)) addMethodMapping("net/minecraft/util/Vec3i getX ()I", vec3i.name + " " + method.name + " ()I"); else if (fn.name.equals(y)) addMethodMapping("net/minecraft/util/Vec3i getY ()I", vec3i.name + " " + method.name + " ()I"); else if (fn.name.equals(z)) addMethodMapping("net/minecraft/util/Vec3i getZ ()I", vec3i.name + " " + method.name + " ()I"); } } return true; } @Mapping(providesFields={ "net/minecraft/util/Vec3 xCoord D", "net/minecraft/util/Vec3 yCoord D", "net/minecraft/util/Vec3 zCoord D" }, providesMethods={ }, depends={ "net/minecraft/util/Vec3" }) public boolean processVec3Class() { ClassNode vec3 = getClassNodeFromMapping("net/minecraft/util/Vec3"); if (!MeddleUtil.notNull(vec3)) return false; List<FieldNode> fields = getMatchingFields(vec3, null, "D"); if (fields.size() == 3) { addFieldMapping("net/minecraft/util/Vec3 xCoord D", vec3.name + " " + fields.get(0).name + " D"); addFieldMapping("net/minecraft/util/Vec3 yCoord D", vec3.name + " " + fields.get(1).name + " D"); addFieldMapping("net/minecraft/util/Vec3 zCoord D", vec3.name + " " + fields.get(2).name + " D"); } return true; } @Mapping(provides={ "net/minecraft/entity/item/EntityItem", "net/minecraft/item/ItemStack"}, providesMethods={ "net/minecraft/block/Block spawnAsEntity (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;Lnet/minecraft/item/ItemStack;)V" }, depends={ "net/minecraft/world/World", "net/minecraft/util/BlockPos", "net/minecraft/block/Block"}) public boolean getEntityItemClass() { ClassNode worldClass = getClassNode(getClassMapping("net/minecraft/world/World")); ClassNode blockPosClass = getClassNode(getClassMapping("net/minecraft/util/BlockPos")); ClassNode blockClass = getClassNode(getClassMapping("net/minecraft/block/Block")); if (!MeddleUtil.notNull(worldClass, blockPosClass, blockClass)) return false; // search for Block.spawnAsEntity(World worldIn, BlockPos pos, ItemStack stack) for (MethodNode method : blockClass.methods) { // We're looking for a static method if ((method.access & Opcodes.ACC_STATIC) != Opcodes.ACC_STATIC) continue; // Look for methods with three arguments Type methodType = Type.getMethodType(method.desc); Type[] arguments = methodType.getArgumentTypes(); if (arguments.length != 3) continue; // Make sure all arguments are objects if (arguments[0].getSort() != Type.OBJECT || arguments[1].getSort() != Type.OBJECT || arguments[2].getSort() != Type.OBJECT ) continue; // Make sure arg0 is World and arg1 is BlockPos if (!arguments[0].getClassName().equals(worldClass.name) || !arguments[1].getClassName().equals(blockPosClass.name)) continue; boolean foundString = false; for (AbstractInsnNode insn = method.instructions.getFirst(); insn != null; insn = insn.getNext()) { if (!foundString && isLdcWithString(insn, "doTileDrops")) { foundString = true; continue; } if (foundString && insn.getOpcode() == Opcodes.NEW) { TypeInsnNode newNode = (TypeInsnNode)insn; addClassMapping("net/minecraft/entity/item/EntityItem", getClassNode(newNode.desc)); // This also means that the last arg for spawnAsEntity is ItemStack addClassMapping("net/minecraft/item/ItemStack", getClassNode(arguments[2].getClassName())); addMethodMapping("net/minecraft/block/Block spawnAsEntity (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;Lnet/minecraft/item/ItemStack;)V", blockClass.name + " " + method.name + " " + method.desc); return true; } } } return false; } @Mapping(provides={ "net/minecraft/block/BlockFire", "net/minecraft/block/BlockLeaves", "net/minecraft/block/BlockChest", "net/minecraft/block/BlockSlab", "net/minecraft/block/BlockHopper", "net/minecraft/block/BlockGrass" }, providesFields={ "net/minecraft/init/Blocks air Lnet/minecraft/block/Block;", "net/minecraft/init/Blocks stone Lnet/minecraft/block/Block;", "net/minecraft/init/Blocks grass Lnet/minecraft/block/BlockGrass;", "net/minecraft/init/Blocks dirt Lnet/minecraft/block/Block;", "net/minecraft/init/Blocks cobblestone Lnet/minecraft/block/Block;", "net/minecraft/init/Blocks planks Lnet/minecraft/block/Block;", "net/minecraft/init/Blocks sapling Lnet/minecraft/block/Block;", "net/minecraft/init/Blocks bedrock Lnet/minecraft/block/Block;", "net/minecraft/init/Blocks iron_block Lnet/minecraft/block/Block;", "net/minecraft/init/Blocks chest Lnet/minecraft/block/BlockChest;", "net/minecraft/init/Blocks obsidian Lnet/minecraft/block/Block;", "net/minecraft/init/Blocks hopper Lnet/minecraft/block/BlockHopper;", "net/minecraft/init/Blocks glass_pane Lnet/minecraft/block/Block;" }, depends={ "net/minecraft/init/Blocks", "net/minecraft/block/Block"}) public boolean processBlocksClass() { Map<String, String> blocksClassFields = new HashMap<String, String>(); Map<String, FieldInsnNode> blocksFields = new HashMap<String, FieldInsnNode>(); ClassNode blockClass = getClassNode(getClassMapping("net/minecraft/block/Block")); ClassNode blocksClass = getClassNode(getClassMapping("net/minecraft/init/Blocks")); if (blockClass == null || blocksClass == null) return false; // Generate list for (MethodNode method : blocksClass.methods) { if (!method.name.equals("<clinit>")) continue; String lastString = null; for (AbstractInsnNode insn = method.instructions.getFirst(); insn != null; insn = insn.getNext()) { String s = getLdcString(insn); if (s != null) lastString = s; // Avoid any strings that definitely aren't block names if (lastString == null || lastString.contains(" ")) continue; if (insn.getOpcode() != Opcodes.PUTSTATIC) continue; FieldInsnNode fieldNode = (FieldInsnNode)insn; // Filter out non-objects and packaged classes, just in case if (!fieldNode.desc.startsWith("L") || fieldNode.desc.contains("/")) continue; blocksFields.put(lastString, fieldNode); // Filter out generic ones extending just the block class if (fieldNode.desc.equals("L" + blockClass.name + ";")) continue; blocksClassFields.put(lastString, fieldNode.desc.substring(1, fieldNode.desc.length() - 1)); } } String className; /* grass, flowing_water, water, flowing_lava, lava, sand, leaves2, sticky_piston, tallgrass, deadbush, piston, piston_head, piston_extension, yellow_flower, red_flower, brown_mushroom, red_mushroom, double_stone_slab, stone_slab, redstone_wire, cactus, reeds, portal, unpowered_repeater, powered_repeater, mycelium, cauldron, double_wooden_slab, wooden_slab, tripwire_hook, beacon, skull, unpowered_comparator, powered_comparator, daylight_detector, daylight_detector_inverted, hopper, double_plant, stained_glass, stained_glass_pane, double_stone_slab2, stone_slab2, purpur_double_slab, purpur_slab */ className = blocksClassFields.get("fire"); if (className != null && searchConstantPoolForStrings(className, "doFireTick")) { addClassMapping("net/minecraft/block/BlockFire", getClassNode(className)); } className = blocksClassFields.get("leaves"); if (className != null && searchConstantPoolForStrings(className, "decayable")) { addClassMapping("net/minecraft/block/BlockLeaves", getClassNode(className)); } className = blocksClassFields.get("chest"); if (className != null && searchConstantPoolForStrings(className, "container.chestDouble")) { addClassMapping("net/minecraft/block/BlockChest", getClassNode(className)); } className = blocksClassFields.get("stone_slab"); if (className != null && searchConstantPoolForStrings(className, "half")) { addClassMapping("net/minecraft/block/BlockSlab", className); } className = blocksClassFields.get("hopper"); if (className != null && searchConstantPoolForStrings(className, "facing", "enabled")) { addClassMapping("net/minecraft/block/BlockHopper", className); } className = blocksClassFields.get("grass"); if (className != null && searchConstantPoolForStrings(className, "snowy")) { addClassMapping("net/minecraft/block/BlockGrass", className); } FieldInsnNode field; field = blocksFields.get("air"); if (field != null) addFieldMapping("net/minecraft/init/Blocks air Lnet/minecraft/block/Block;", field); field = blocksFields.get("stone"); if (field != null) addFieldMapping("net/minecraft/init/Blocks stone Lnet/minecraft/block/Block;", field); field = blocksFields.get("grass"); if (field != null) addFieldMapping("net/minecraft/init/Blocks grass Lnet/minecraft/block/BlockGrass;", field); field = blocksFields.get("dirt"); if (field != null) addFieldMapping("net/minecraft/init/Blocks dirt Lnet/minecraft/block/Block;", field); field = blocksFields.get("cobblestone"); if (field != null) addFieldMapping("net/minecraft/init/Blocks cobblestone Lnet/minecraft/block/Block;", field); field = blocksFields.get("planks"); if (field != null) addFieldMapping("net/minecraft/init/Blocks planks Lnet/minecraft/block/Block;", field); field = blocksFields.get("sapling"); if (field != null) addFieldMapping("net/minecraft/init/Blocks sapling Lnet/minecraft/block/Block;", field); field = blocksFields.get("bedrock"); if (field != null) addFieldMapping("net/minecraft/init/Blocks bedrock Lnet/minecraft/block/Block;", field); field = blocksFields.get("chest"); if (field != null) addFieldMapping("net/minecraft/init/Blocks chest Lnet/minecraft/block/BlockChest;", field); field = blocksFields.get("glass_pane"); if (field != null) addFieldMapping("net/minecraft/init/Blocks glass_pane Lnet/minecraft/block/Block;", field); field = blocksFields.get("iron_block"); if (field != null) addFieldMapping("net/minecraft/init/Blocks iron_block Lnet/minecraft/block/Block;", field); field = blocksFields.get("obsidian"); if (field != null) addFieldMapping("net/minecraft/init/Blocks obsidian Lnet/minecraft/block/Block;", field); field = blocksFields.get("hopper"); if (field != null) addFieldMapping("net/minecraft/init/Blocks hopper Lnet/minecraft/block/BlockHopper;", field); return true; } @Mapping(providesFields={ "net/minecraft/init/Sounds entity_creeper_primed Lnet/minecraft/util/Sound;", "net/minecraft/init/Sounds entity_hostile_hurt Lnet/minecraft/util/Sound;", "net/minecraft/init/Sounds entity_hostile_swim Lnet/minecraft/util/Sound;", "net/minecraft/init/Sounds block_water_ambient Lnet/minecraft/util/Sound;", "net/minecraft/init/Sounds block_lava_pop Lnet/minecraft/util/Sound;", "net/minecraft/init/Sounds entity_generic_explode Lnet/minecraft/util/Sound;", "net/minecraft/init/Sounds ui_button_click Lnet/minecraft/util/Sound;", "net/minecraft/init/Sounds block_portal_trigger Lnet/minecraft/util/Sound;", "net/minecraft/init/Sounds entity_skeleton_step Lnet/minecraft/util/Sound;" }, depends={ "net/minecraft/util/Sound", "net/minecraft/init/Sounds" }) public boolean processSoundsClass() { ClassNode sound = getClassNodeFromMapping("net/minecraft/util/Sound"); ClassNode sounds = getClassNodeFromMapping("net/minecraft/init/Sounds"); if (sound == null || sounds == null) return false; Map<String, FieldInsnNode> soundFields = new HashMap<>(); // Generate list for (MethodNode method : sounds.methods) { if (!method.name.equals("<clinit>")) continue; String lastString = null; for (AbstractInsnNode insn = method.instructions.getFirst(); insn != null; insn = insn.getNext()) { String s = getLdcString(insn); if (s != null) lastString = s; // Avoid any strings that definitely aren't block names if (lastString == null || lastString.contains(" ")) continue; if (insn.getOpcode() != Opcodes.PUTSTATIC) continue; FieldInsnNode fieldNode = (FieldInsnNode)insn; // We only want sound objects if (!fieldNode.desc.equals("L" + sound.name + ";")) continue; soundFields.put(lastString, fieldNode); String newName = lastString.replace(".", "_"); addFieldMapping("net/minecraft/init/Sounds " + newName + " Lnet/minecraft/util/Sound;", fieldNode); } } return true; } @Mapping(provides={ "net/minecraft/inventory/InventoryHelper" }, providesFields={ "net/minecraft/block/BlockHopper FACING Lnet/minecraft/block/properties/PropertyDirection;", "net/minecraft/block/BlockHopper ENABLED Lnet/minecraft/block/properties/PropertyBool;", "net/minecraft/block/material/Material iron Lnet/minecraft/block/material/Material;" }, providesMethods={ "net/minecraft/block/properties/PropertyDirection create (Ljava/lang/String;Lcom/google/common/base/Predicate;)Lnet/minecraft/block/properties/PropertyDirection;", "net/minecraft/item/ItemStack hasDisplayName ()Z", //"net/minecraft/block/Block hasComparatorInputOverride (Lnet/minecraft/block/state/IBlockState;)Z", "net/minecraft/util/EnumFacing getOpposite ()Lnet/minecraft/util/EnumFacing;", "net/minecraft/inventory/InventoryHelper dropInventoryItems (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;Lnet/minecraft/inventory/IInventory;)V" }, dependsMethods={ "net/minecraft/block/Block onBlockPlacedBy (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;Lnet/minecraft/block/state/IBlockState;Lnet/minecraft/entity/EntityLivingBase;Lnet/minecraft/item/ItemStack;)V", "net/minecraft/block/Block isFullCube (Lnet/minecraft/block/state/IBlockState;)Z", "net/minecraft/block/Block isOpaqueCube (Lnet/minecraft/block/state/IBlockState;)Z", "net/minecraft/block/Block onBlockPlaced (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;Lnet/minecraft/util/EnumFacing;FFFILnet/minecraft/entity/EntityLivingBase;)Lnet/minecraft/block/state/IBlockState;", "net/minecraft/block/Block breakBlock (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;Lnet/minecraft/block/state/IBlockState;)V", }, depends={ "net/minecraft/block/Block", "net/minecraft/block/BlockHopper", "net/minecraft/block/properties/PropertyDirection", "net/minecraft/block/properties/PropertyBool", "net/minecraft/block/material/Material", "net/minecraft/item/ItemStack", "net/minecraft/block/state/IBlockState", "net/minecraft/util/EnumFacing", "net/minecraft/world/World", "net/minecraft/util/BlockPos", "net/minecraft/inventory/IInventory" }) public boolean processBlockHopperClass() { ClassNode block = getClassNodeFromMapping("net/minecraft/block/Block"); ClassNode blockHopper = getClassNodeFromMapping("net/minecraft/block/BlockHopper"); ClassNode propertyDirection = getClassNodeFromMapping("net/minecraft/block/properties/PropertyDirection"); ClassNode propertyBool = getClassNodeFromMapping("net/minecraft/block/properties/PropertyBool"); ClassNode material = getClassNodeFromMapping("net/minecraft/block/material/Material"); ClassNode itemStack = getClassNodeFromMapping("net/minecraft/item/ItemStack"); ClassNode iBlockState = getClassNodeFromMapping("net/minecraft/block/state/IBlockState"); ClassNode enumFacing = getClassNodeFromMapping("net/minecraft/util/EnumFacing"); ClassNode world = getClassNodeFromMapping("net/minecraft/world/World"); ClassNode blockPos = getClassNodeFromMapping("net/minecraft/util/BlockPos"); ClassNode iInventory = getClassNodeFromMapping("net/minecraft/inventory/IInventory"); if (!MeddleUtil.notNull(block, blockHopper, propertyDirection, propertyBool, material, itemStack, iBlockState, enumFacing, world, blockPos, iInventory)) return false; // Parse fields to find: // PropertyDirection FACING, // PropertyBool ENABLED List<FieldNode> fields = getMatchingFields(blockHopper, null, "L" + propertyDirection.name + ";"); if (fields.size() == 1) { addFieldMapping("net/minecraft/block/BlockHopper FACING Lnet/minecraft/block/properties/PropertyDirection;", blockHopper.name + " " + fields.get(0).name + " " + fields.get(0).desc); } fields = getMatchingFields(blockHopper, null, "L" + propertyBool.name + ";"); if (fields.size() == 1) { addFieldMapping("net/minecraft/block/BlockHopper ENABLED Lnet/minecraft/block/properties/PropertyBool;", blockHopper.name + " " + fields.get(0).name + " " + fields.get(0).desc); } // Parse class init to find: // public static PropertyDirection PropertyDirection.create(String, Predicate<EnumFacing>) List<MethodNode> methods = getMatchingMethods(blockHopper, "<clinit>", "()V"); if (methods.size() == 1) { List<MethodInsnNode> nodes = getAllInsnNodesOfType(methods.get(0), MethodInsnNode.class); nodes = filterMethodInsnNodes(nodes, propertyDirection.name, "(Ljava/lang/String;Lcom/google/common/base/Predicate;)L" + propertyDirection.name + ";"); if (nodes.size() == 1) { addMethodMapping("net/minecraft/block/properties/PropertyDirection create (Ljava/lang/String;Lcom/google/common/base/Predicate;)Lnet/minecraft/block/properties/PropertyDirection;", propertyDirection.name + " " + nodes.get(0).name + " " + nodes.get(0).desc); } } // Parse class init to find: // Material.iron methods = getMatchingMethods(blockHopper, "<init>", "()V"); if (methods.size() == 1) { List<FieldInsnNode> nodes = getAllInsnNodesOfType(methods.get(0), FieldInsnNode.class); // Get just the materials List<FieldInsnNode> materials = filterFieldInsnNodes(nodes, material.name, "L" + material.name + ";"); // Should only be one if (materials.size() == 1) { addFieldMapping("net/minecraft/block/material/Material iron Lnet/minecraft/block/material/Material;", material.name + " " + materials.get(0).name + " " + materials.get(0).desc); } } // Parse onBlockPlacedBy to find: // public boolean ItemStack.hasDisplayName() MethodNode onBlockPlacedBy = getMethodNodeFromMapping(blockHopper, "net/minecraft/block/Block onBlockPlacedBy (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;Lnet/minecraft/block/state/IBlockState;Lnet/minecraft/entity/EntityLivingBase;Lnet/minecraft/item/ItemStack;)V"); if (onBlockPlacedBy != null) { // Filter just the boolean-returning methods from ItemStack used in onBlockPlacedBy List<MethodInsnNode> nodes = getAllInsnNodesOfType(onBlockPlacedBy, MethodInsnNode.class); List<MethodInsnNode> hasDisplayNameList = filterMethodInsnNodes(nodes, itemStack.name, "()Z"); // Should only be one if (hasDisplayNameList.size() == 1) { // Get the actual method from ItemStack MethodNode hasDisplayName = getMethodNode(itemStack, "--- " + hasDisplayNameList.get(0).name + " " + hasDisplayNameList.get(0).desc); if (hasDisplayName != null) { // Double check that the method has a "Name" string used in it, then add mapping for (AbstractInsnNode insn = hasDisplayName.instructions.getFirst(); insn != null; insn = insn.getNext()) { if (isLdcWithString(insn, "Name")) { addMethodMapping("net/minecraft/item/ItemStack hasDisplayName ()Z", itemStack.name + " " + hasDisplayName.name + " " + hasDisplayName.desc); break; } } } } } MethodNode isFullCube = getMethodNodeFromMapping(blockHopper, "net/minecraft/block/Block isFullCube (Lnet/minecraft/block/state/IBlockState;)Z"); MethodNode isOpaqueCube = getMethodNodeFromMapping(blockHopper, "net/minecraft/block/Block isOpaqueCube (Lnet/minecraft/block/state/IBlockState;)Z"); // public boolean hasComparatorInputOverride(IBlockState param0) // Removed as of 15w49a, find elsewhere /*methods = getMatchingMethods(blockHopper, null, "(L" + iBlockState.name + ";)Z"); if (methods.size() > 0 && isFullCube != null && isOpaqueCube != null) { for (Iterator<MethodNode> it = methods.iterator(); it.hasNext();) { MethodNode mn = it.next(); if (mn.name.equals(isFullCube.name)) it.remove(); if (mn.name.equals(isOpaqueCube.name)) it.remove(); } if (methods.size() == 1) { addMethodMapping("net/minecraft/block/Block hasComparatorInputOverride (Lnet/minecraft/block/state/IBlockState;)Z", block.name + " " + methods.get(0).name + " " + methods.get(0).desc); } }*/ // Parse onBlockPlaced to find: // public EnumFacing EnumFacing.getOpposite() MethodNode onBlockPlaced = getMethodNodeFromMapping(blockHopper, "net/minecraft/block/Block onBlockPlaced (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;Lnet/minecraft/util/EnumFacing;FFFILnet/minecraft/entity/EntityLivingBase;)Lnet/minecraft/block/state/IBlockState;"); if (onBlockPlaced != null) { List<MethodInsnNode> nodes = getAllInsnNodesOfType(onBlockPlaced, MethodInsnNode.class); List<MethodInsnNode> getOpposite = filterMethodInsnNodes(nodes, enumFacing.name, "()L" + enumFacing.name + ";"); if (getOpposite.size() == 1) { addMethodMapping("net/minecraft/util/EnumFacing getOpposite ()Lnet/minecraft/util/EnumFacing;", enumFacing.name + " " + getOpposite.get(0).name + " " + getOpposite.get(0).desc); } } // class net/minecraft/inventory/InventoryHelper // public static void InventoryHelper.dropInventoryItems(World, BlockPos, IInventory) MethodNode breakBlock = getMethodNodeFromMapping(blockHopper, "net/minecraft/block/Block breakBlock (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;Lnet/minecraft/block/state/IBlockState;)V"); if (breakBlock != null) { List<MethodInsnNode> mnodes = getAllInsnNodesOfType(breakBlock, MethodInsnNode.class); mnodes = filterMethodInsnNodes(mnodes, null, assembleDescriptor("(", world, blockPos, iInventory, ")V")); if (mnodes.size() == 1 && mnodes.get(0).getOpcode() == Opcodes.INVOKESTATIC) { MethodInsnNode mn = (MethodInsnNode)mnodes.get(0); ClassNode inventoryHelper = getClassNode(mn.owner); // All the methods should be static boolean allStatic = true; for (MethodNode method : inventoryHelper.methods) { if (method.name.startsWith("<")) continue; if ((method.access & Opcodes.ACC_STATIC) == 0) allStatic = false; } if (allStatic) { addClassMapping("net/minecraft/inventory/InventoryHelper", inventoryHelper.name); addMethodMapping("net/minecraft/inventory/InventoryHelper dropInventoryItems (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;Lnet/minecraft/inventory/IInventory;)V", inventoryHelper.name + " " + mn.name + " " + mn.desc); } } // TODO - World.updateComparatorOutputLevel(pos, this); } return true; } @Mapping(providesMethods={ "net/minecraft/block/Block setTickRandomly (Z)Lnet/minecraft/block/Block;", "net/minecraft/block/Block isVisuallyOpaque ()Z", "net/minecraft/block/Block isOpaqueCube (Lnet/minecraft/block/state/IBlockState;)Z" }, depends={ "net/minecraft/block/Block", "net/minecraft/block/BlockLeaves", "net/minecraft/block/state/IBlockState" }) public boolean processBlockLeavesClass() { ClassNode blockLeaves = getClassNode(getClassMapping("net/minecraft/block/BlockLeaves")); ClassNode block = getClassNode(getClassMapping("net/minecraft/block/Block")); ClassNode iBlockState = getClassNodeFromMapping("net/minecraft/block/state/IBlockState"); if (!MeddleUtil.notNull(block, blockLeaves, iBlockState)) return false; // protected Block setTickRandomly(boolean) MethodNode init = getMethodNode(blockLeaves, "--- <init> ()V"); if (init != null) { List<MethodInsnNode> nodes = getAllInsnNodesOfType(init, MethodInsnNode.class); for (Iterator<MethodInsnNode> it = nodes.iterator(); it.hasNext();) { MethodInsnNode mn = it.next(); if (mn.owner.equals(blockLeaves.name) && mn.desc.equals("(Z)L" + block.name + ";")) continue; it.remove(); } if (nodes.size() == 1) { addMethodMapping("net/minecraft/block/Block setTickRandomly (Z)Lnet/minecraft/block/Block;", block.name + " " + nodes.get(0).name + " " + nodes.get(0).desc); } } // public boolean isVisuallyOpaque() List<MethodNode> methods = getMatchingMethods(blockLeaves, null, "()Z"); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/Block isVisuallyOpaque ()Z", block.name + " " + methods.get(0).name + " ()Z"); } // public boolean isOpaqueCube(IBlockState state) methods = getMatchingMethods(blockLeaves, null, assembleDescriptor("(", iBlockState, ")Z")); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/Block isOpaqueCube (Lnet/minecraft/block/state/IBlockState;)Z", block.name + " " + methods.get(0).name + " " + methods.get(0).desc); } return true; } @Mapping(providesFields={ "net/minecraft/block/Block fullBlock Z" }, providesMethods={ "net/minecraft/block/Block canSilkHarvest ()Z", "net/minecraft/block/Block getBlockBoundsBasedOnState (Lnet/minecraft/block/state/IBlockState;Lnet/minecraft/world/IBlockAccess;Lnet/minecraft/util/BlockPos;)Lnet/minecraft/util/AxisAlignedBB;", "net/minecraft/block/Block isFullCube (Lnet/minecraft/block/state/IBlockState;)Z" }, dependsMethods={ "net/minecraft/block/Block isOpaqueCube (Lnet/minecraft/block/state/IBlockState;)Z" }, depends={ "net/minecraft/block/Block", "net/minecraft/block/BlockSlab", "net/minecraft/block/material/Material", "net/minecraft/block/state/IBlockState", "net/minecraft/world/IBlockAccess", "net/minecraft/util/BlockPos", "net/minecraft/util/AxisAlignedBB", "net/minecraft/block/material/MapColor" }) public boolean processBlockSlabClass() { ClassNode block = getClassNodeFromMapping("net/minecraft/block/Block"); ClassNode blockSlab = getClassNodeFromMapping("net/minecraft/block/BlockSlab"); ClassNode material = getClassNodeFromMapping("net/minecraft/block/material/Material"); ClassNode iBlockState = getClassNodeFromMapping("net/minecraft/block/state/IBlockState"); ClassNode iBlockAccess = getClassNodeFromMapping("net/minecraft/world/IBlockAccess"); ClassNode blockPos = getClassNodeFromMapping("net/minecraft/util/BlockPos"); ClassNode aabb = getClassNodeFromMapping("net/minecraft/util/AxisAlignedBB"); ClassNode mapColor = getClassNodeFromMapping("net/minecraft/block/material/MapColor"); if (!MeddleUtil.notNull(block, blockSlab, material, iBlockState, iBlockAccess, blockPos, aabb, mapColor)) return false; List<MethodNode> methods = getMatchingMethods(blockSlab, "<init>", assembleDescriptor("(", material, mapColor, ")V")); if (methods.size() == 1) { MethodNode init = methods.get(0); List<FieldInsnNode> nodes = getAllInsnNodesOfType(init, FieldInsnNode.class); if (nodes.size() == 1 && nodes.get(0).owner.equals(blockSlab.name) && nodes.get(0).desc.equals("Z")) { addFieldMapping("net/minecraft/block/Block fullBlock Z", block.name + " " + nodes.get(0).name + " Z"); } } // protected boolean canSilkHarvest() methods = getMatchingMethods(blockSlab, null, "()Z"); methods = removeMethodsWithFlags(methods, Opcodes.ACC_ABSTRACT); if (methods.size() == 1) { MethodNode canSilkHarvest = getMethodNode(block, "--- " + methods.get(0).name + " " + methods.get(0).desc); if (canSilkHarvest != null) { addMethodMapping("net/minecraft/block/Block canSilkHarvest ()Z", block.name + " " + canSilkHarvest.name + " ()Z"); } } // public AxisAlignedBB getBlockBoundsBasedOnState(IBlockState state, IBlockAccess worldIn, BlockPos pos) methods = getMatchingMethods(blockSlab, null, assembleDescriptor("(", iBlockState, iBlockAccess, blockPos, ")", aabb)); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/Block getBlockBoundsBasedOnState (Lnet/minecraft/block/state/IBlockState;Lnet/minecraft/world/IBlockAccess;Lnet/minecraft/util/BlockPos;)Lnet/minecraft/util/AxisAlignedBB;", block.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public boolean isFullCube(IBlockState state) MethodNode isOpaqueCube = getMethodNodeFromMapping(block, "net/minecraft/block/Block isOpaqueCube (Lnet/minecraft/block/state/IBlockState;)Z"); methods = getMatchingMethods(blockSlab, null, "(L" + iBlockState.name + ";)Z"); methods = removeMethodsWithFlags(methods, Opcodes.ACC_STATIC); // Changed from 2 to 3 for 15w49a if (methods.size() == 3 && isOpaqueCube != null) { for (Iterator<MethodNode> it = methods.iterator(); it.hasNext();) { MethodNode method = it.next(); if (method.name.equals(isOpaqueCube.name) && method.desc.equals(isOpaqueCube.desc)) it.remove(); // Added for 15w49a to filter out new k(IBlockState)Z method; might not be the most reliable in the future if (!matchOpcodeSequence(method.instructions.getFirst(), Opcodes.ALOAD, Opcodes.INVOKEVIRTUAL, Opcodes.IRETURN)) it.remove(); } if (methods.size() == 1) { addMethodMapping("net/minecraft/block/Block isFullCube (Lnet/minecraft/block/state/IBlockState;)Z", block.name + " " + methods.get(0).name + " " + methods.get(0).desc); } } return true; } @Mapping(provides="net/minecraft/item/Item", depends={ "net/minecraft/block/Block", "net/minecraft/item/ItemStack" }) public boolean getItemClass() { ClassNode blockClass = getClassNode(getClassMapping("net/minecraft/block/Block")); ClassNode itemStackClass = getClassNode(getClassMapping("net/minecraft/item/ItemStack")); if (blockClass == null || itemStackClass == null) return false; List<String> possibleClasses = new ArrayList<String>(); for (MethodNode method : itemStackClass.methods) { if (!method.name.equals("<init>")) continue; Type t = Type.getMethodType(method.desc); Type[] args = t.getArgumentTypes(); if (args.length != 1 || args[0].getSort() != Type.OBJECT) continue; // Get the class of the first method parameter String className = args[0].getClassName(); // One of them will be the block class, ignore it if (className.equals(blockClass.name)) continue; possibleClasses.add(className); } //if (possibleClasses.size() == 1) { for (String className : possibleClasses) { if (searchConstantPoolForStrings(className, "item.", "arrow")) { addClassMapping("net/minecraft/item/Item", getClassNode(possibleClasses.get(0))); return true; } } return false; } @Mapping(provides={ "net/minecraft/block/BlockContainer", "net/minecraft/block/ITileEntityProvider" }, depends={ "net/minecraft/block/Block", "net/minecraft/block/BlockChest" }) public boolean getBlockContainerClass() { ClassNode blockClass = getClassNode(getClassMapping("net/minecraft/block/Block")); ClassNode blockChestClass = getClassNode(getClassMapping("net/minecraft/block/BlockChest")); if (blockClass == null || blockChestClass == null || blockChestClass.superName == null) return false; ClassNode containerClass = getClassNode(blockChestClass.superName); if (!containerClass.superName.equals(blockClass.name)) return false; if (containerClass.interfaces.size() != 1) return false; addClassMapping("net/minecraft/block/BlockContainer", containerClass); addClassMapping("net/minecraft/block/ITileEntityProvider", getClassNode(containerClass.interfaces.get(0))); return true; } @Mapping(provides="net/minecraft/tileentity/TileEntity", providesMethods="net/minecraft/block/ITileEntityProvider createNewTileEntity (Lnet/minecraft/world/World;I)Lnet/minecraft/tileentity/TileEntity;", depends={ "net/minecraft/block/ITileEntityProvider", "net/minecraft/world/World" }) public boolean getTileEntityClass() { ClassNode teProviderClass = getClassNode(getClassMapping("net/minecraft/block/ITileEntityProvider")); ClassNode world = getClassNodeFromMapping("net/minecraft/world/World"); if (teProviderClass == null || world == null) return false; String tileEntity_name = null; for (MethodNode method : teProviderClass.methods) { Type t = Type.getMethodType(method.desc); Type returnType = t.getReturnType(); if (returnType.getSort() != Type.OBJECT) return false; String className = returnType.getClassName(); if (tileEntity_name == null && searchConstantPoolForStrings(className, "furnace", "mob_spawner")) { // TE IDs changed in 16w32a addClassMapping("net/minecraft/tileentity/TileEntity", getClassNode(className)); tileEntity_name = className; } // TileEntity createNewTileEntity(World worldIn, int meta); if (tileEntity_name != null && method.desc.equals("(L" + world.name + ";I)L" + tileEntity_name + ";")) { addMethodMapping("net/minecraft/block/ITileEntityProvider createNewTileEntity (Lnet/minecraft/world/World;I)Lnet/minecraft/tileentity/TileEntity;", teProviderClass.name + " " + method.name + " " + method.desc); return true; } } return false; } @Mapping(provides={ "net/minecraft/tileentity/TileEntityChest", "net/minecraft/tileentity/TileEntityFurnace", "net/minecraft/tileentity/TileEntityEnderChest", "net/minecraft/block/BlockJukebox$TileEntityJukebox", "net/minecraft/tileentity/TileEntityDispenser", "net/minecraft/tileentity/TileEntityDropper", "net/minecraft/tileentity/TileEntitySign", "net/minecraft/tileentity/TileEntityMobSpawner", "net/minecraft/tileentity/TileEntityNoteblock", "net/minecraft/tileentity/TileEntityPiston", "net/minecraft/tileentity/TileEntityBrewingStand", "net/minecraft/tileentity/TileEntityEnchantingTable", "net/minecraft/tileentity/TileEntityEndPortal", "net/minecraft/tileentity/TileEntityBeacon", "net/minecraft/tileentity/TileEntitySkull", "net/minecraft/tileentity/TileEntityDaylightDetector", "net/minecraft/tileentity/TileEntityHopper", "net/minecraft/tileentity/TileEntityComparator", "net/minecraft/tileentity/TileEntityFlowerPot", "net/minecraft/tileentity/TileEntityBanner", "net/minecraft/tileentity/TileEntityStructureBlock", "net/minecraft/tileentity/TileEntityEndGateway", "net/minecraft/tileentity/TileEntityCommandBlock", "net/minecraft/network/PacketBuffer", "net/minecraft/network/Packet", "net/minecraft/crash/CrashReportCategory" }, providesFields={ "net/minecraft/tileentity/TileEntity worldObj Lnet/minecraft/world/World;", "net/minecraft/tileentity/TileEntity pos Lnet/minecraft/util/BlockPos;", "net/minecraft/tileentity/TileEntity tileEntityInvalid Z", "net/minecraft/tileentity/TileEntity blockMetadata I", "net/minecraft/tileentity/TileEntity blockType Lnet/minecraft/block/Block;" }, providesMethods={ "net/minecraft/tileentity/TileEntity addMapping (Ljava/lang/String;Ljava/lang/Class;)V", "net/minecraft/tileentity/TileEntity getWorld ()Lnet/minecraft/world/World;", "net/minecraft/tileentity/TileEntity setWorldObj (Lnet/minecraft/world/World;)V", "net/minecraft/tileentity/TileEntity setWorldCreate (Lnet/minecraft/world/World;)V", "net/minecraft/tileentity/TileEntity createAndLoadEntity (Lnet/minecraft/world/World;Lnet/minecraft/nbt/NBTTagCompound;)Lnet/minecraft/tileentity/TileEntity;", "net/minecraft/tileentity/TileEntity getBlockMetadata ()I", "net/minecraft/tileentity/TileEntity getPos ()Lnet/minecraft/util/BlockPos;", "net/minecraft/tileentity/TileEntity setPos (Lnet/minecraft/util/BlockPos;)V", "net/minecraft/tileentity/TileEntity getBlockType ()Lnet/minecraft/block/Block;", "net/minecraft/tileentity/TileEntity receiveClientEvent (II)Z", "net/minecraft/tileentity/TileEntity getDescriptionPacket ()Lnet/minecraft/network/Packet;", "net/minecraft/tileentity/TileEntity addInfoToCrashReport (Lnet/minecraft/crash/CrashReportCategory;)V", "net/minecraft/tileentity/TileEntity validate ()V", "net/minecraft/tileentity/TileEntity invalidate ()V", "net/minecraft/tileentity/TileEntity updateContainingBlockInfo ()V", "net/minecraft/tileentity/TileEntity markDirty ()V", "net/minecraft/tileentity/TileEntity readFromNBT (Lnet/minecraft/nbt/NBTTagCompound;)V", "net/minecraft/tileentity/TileEntity writeToNBT (Lnet/minecraft/nbt/NBTTagCompound;)Lnet/minecraft/nbt/NBTTagCompound;" }, depends={ "net/minecraft/tileentity/TileEntity", "net/minecraft/world/World", "net/minecraft/nbt/NBTTagCompound", "net/minecraft/util/BlockPos", "net/minecraft/block/Block", "net/minecraft/init/Blocks" }) public boolean processTileEntityClass() { ClassNode minecraftServer = getClassNode("net/minecraft/server/MinecraftServer"); ClassNode tileEntity = getClassNodeFromMapping("net/minecraft/tileentity/TileEntity"); ClassNode world = getClassNodeFromMapping("net/minecraft/world/World"); ClassNode tagCompound = getClassNodeFromMapping("net/minecraft/nbt/NBTTagCompound"); ClassNode blockPos = getClassNodeFromMapping("net/minecraft/util/BlockPos"); ClassNode block = getClassNodeFromMapping("net/minecraft/block/Block"); ClassNode blocks = getClassNodeFromMapping("net/minecraft/init/Blocks"); if (!MeddleUtil.notNull(tileEntity, world, tagCompound, blockPos, block, blocks)) return false; List<MethodNode> methods = getMatchingMethods(tileEntity, "<clinit>", "()V"); if (methods.size() != 1) return false; Map<String, String> teMap = new HashMap<>(); String lastName = null; for (AbstractInsnNode insn = getNextRealOpcode(methods.get(0).instructions.getFirst()); insn != null; insn = getNextRealOpcode(insn.getNext())) { String name = getLdcString(insn); if (name != null) { lastName = name; continue; } String c = getLdcClass(insn); if (c == null || lastName == null) continue; teMap.put(lastName, c); } // 16w32a changed all TE IDs // it's unnecessary to check if the registered TileEntity classes contains strings. If here is something wrong than mojang has fucked up done things for(Map.Entry<String, String> entry : teMap.entrySet()){ switch(entry.getKey()){ case "furnace":{ addClassMapping("net/minecraft/tileentity/TileEntityFurnace", entry.getValue()); break; } case "chest":{ addClassMapping("net/minecraft/tileentity/TileEntityChest", entry.getValue()); break; } case "ender_chest":{ addClassMapping("net/minecraft/tileentity/TileEntityEnderChest", entry.getValue()); break; } case "jukebox":{ addClassMapping("net/minecraft/block/BlockJukebox$TileEntityJukebox", entry.getValue()); break; } case "dispenser":{ addClassMapping("net/minecraft/tileentity/TileEntityDispenser", entry.getValue()); break; } case "dropper":{ addClassMapping("net/minecraft/tileentity/TileEntityDropper", entry.getValue()); break; } case "sign":{ addClassMapping("net/minecraft/tileentity/TileEntitySign", entry.getValue()); break; } case "mob_spawner":{ addClassMapping("net/minecraft/tileentity/TileEntityMobSpawner", entry.getValue()); break; } case "noteblock":{ addClassMapping("net/minecraft/tileentity/TileEntityNoteblock", entry.getValue()); break; } case "piston":{ addClassMapping("net/minecraft/tileentity/TileEntityPiston", entry.getValue()); break; } case "brewing_stand":{ addClassMapping("net/minecraft/tileentity/TileEntityBrewingStand", entry.getValue()); break; } case "enchanting_table":{ addClassMapping("net/minecraft/tileentity/TileEntityEnchantingTable", entry.getValue()); break; } case "end_portal":{ addClassMapping("net/minecraft/tileentity/TileEntityEndPortal", entry.getValue()); break; } case "beacon":{ addClassMapping("net/minecraft/tileentity/TileEntityBeacon", entry.getValue()); break; } case "skull":{ addClassMapping("net/minecraft/tileentity/TileEntitySkull", entry.getValue()); break; } case "daylight_detector":{ addClassMapping("net/minecraft/tileentity/TileEntityDaylightDetector", entry.getValue()); break; } case "hopper":{ addClassMapping("net/minecraft/tileentity/TileEntityHopper", entry.getValue()); break; } case "comparator":{ addClassMapping("net/minecraft/tileentity/TileEntityComparator", entry.getValue()); break; } case "flower_pot":{ addClassMapping("net/minecraft/tileentity/TileEntityFlowerPot", entry.getValue()); break; } case "banner":{ addClassMapping("net/minecraft/tileentity/TileEntityBanner", entry.getValue()); break; } case "structure_block":{ addClassMapping("net/minecraft/tileentity/TileEntityStructureBlock", entry.getValue()); break; } case "end_gateway":{ addClassMapping("net/minecraft/tileentity/TileEntityEndGateway", entry.getValue()); break; } case "command_block":{ addClassMapping("net/minecraft/tileentity/TileEntityCommandBlock", entry.getValue()); break; } } } // protected World worldObj List<FieldNode> fields = getMatchingFields(tileEntity, null, "L" + world.name + ";"); if (fields.size() == 1) { addFieldMapping("net/minecraft/tileentity/TileEntity worldObj Lnet/minecraft/world/World;", tileEntity.name + " " + fields.get(0).name + " " + fields.get(0).desc); } // protected BlockPos pos fields = getMatchingFields(tileEntity, null, "L" + blockPos.name + ";"); if (fields.size() == 1) { addFieldMapping("net/minecraft/tileentity/TileEntity pos Lnet/minecraft/util/BlockPos;", tileEntity.name + " " + fields.get(0).name + " " + fields.get(0).desc); } // protected boolean tileEntityInvalid fields = getMatchingFields(tileEntity, null, "Z"); if (fields.size() == 1) { addFieldMapping("net/minecraft/tileentity/TileEntity tileEntityInvalid Z", tileEntity.name + " " + fields.get(0).name + " " + fields.get(0).desc); } // private int blockMetadata; fields = getMatchingFields(tileEntity, null, "I"); if (fields.size() == 1) { addFieldMapping("net/minecraft/tileentity/TileEntity blockMetadata I", tileEntity.name + " " + fields.get(0).name + " " + fields.get(0).desc); } // protected Block blockType fields = getMatchingFields(tileEntity, null, "L" + block.name + ";"); if (fields.size() == 1) { addFieldMapping("net/minecraft/tileentity/TileEntity blockType Lnet/minecraft/block/Block;", tileEntity.name + " " + fields.get(0).name + " " + fields.get(0).desc); } // public static void addMapping(Class cl, String id) // 16w32a reversed fields methods = getMatchingMethods(tileEntity, null, "(Ljava/lang/String;Ljava/lang/Class;)V"); if (methods.size() == 1) { addMethodMapping("net/minecraft/tileentity/TileEntity addMapping (Ljava/lang/String;Ljava/lang/Class;)V", tileEntity.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public World getWorld() methods = getMatchingMethods(tileEntity, null, "()L" + world.name + ";"); if (methods.size() == 1) { addMethodMapping("net/minecraft/tileentity/TileEntity getWorld ()Lnet/minecraft/world/World;", tileEntity.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public void setWorldObj(World worldIn) methods = getMatchingMethods(tileEntity, null, "(L" + world.name + ";)V"); for(MethodNode method : methods){ boolean isSetWorldObj = false; for(AbstractInsnNode ins : method.instructions.toArray()){ if(!isSetWorldObj && ins.getOpcode() == Opcodes.PUTFIELD) isSetWorldObj = true; } if(isSetWorldObj){ addMethodMapping("net/minecraft/tileentity/TileEntity setWorldObj (Lnet/minecraft/world/World;)V", tileEntity.name + " " + method.name + " " + method.desc); } else { addMethodMapping("net/minecraft/tileentity/TileEntity setWorldCreate (Lnet/minecraft/world/World;)V", tileEntity.name + " " + method.name + " " + method.desc); } } // public static TileEntity createAndLoadEntity(NBTTagCompound nbt) // CHANGED in 15w38b // public static TileEntity createAndLoadEntity(MinecraftServer serevr, NBTTagCompound nbt) // CHANGED back in 1.9.3-preX // 1.10 added parameter World methods = getMatchingMethods(tileEntity, null, assembleDescriptor("(", world, tagCompound, ")", tileEntity)); if (methods.size() == 1) { addMethodMapping("net/minecraft/tileentity/TileEntity createAndLoadEntity (Lnet/minecraft/world/World;Lnet/minecraft/nbt/NBTTagCompound;)Lnet/minecraft/tileentity/TileEntity;", tileEntity.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public int getBlockMetadata() methods = getMatchingMethods(tileEntity, null, "()I"); if (methods.size() == 1) { addMethodMapping("net/minecraft/tileentity/TileEntity getBlockMetadata ()I", tileEntity.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public BlockPos getPos() methods = getMatchingMethods(tileEntity, null, "()L" + blockPos.name + ";"); if (methods.size() == 1) { addMethodMapping("net/minecraft/tileentity/TileEntity getPos ()Lnet/minecraft/util/BlockPos;", tileEntity.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public void setPos(BlockPos posIn) methods = getMatchingMethods(tileEntity, null, "(L" + blockPos.name + ";)V"); if (methods.size() == 1) { addMethodMapping("net/minecraft/tileentity/TileEntity setPos (Lnet/minecraft/util/BlockPos;)V", tileEntity.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public Block getBlockType() methods = getMatchingMethods(tileEntity, null, "()L" + block.name + ";"); if (methods.size() == 1) { addMethodMapping("net/minecraft/tileentity/TileEntity getBlockType ()Lnet/minecraft/block/Block;", tileEntity.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public boolean receiveClientEvent(int id, int type) methods = getMatchingMethods(tileEntity, null, "(II)Z"); if (methods.size() == 1) { addMethodMapping("net/minecraft/tileentity/TileEntity receiveClientEvent (II)Z", tileEntity.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public Packet getDescriptionPacket() for (MethodNode method : tileEntity.methods) { if (!method.desc.startsWith("()L")) continue; String tePacketClass = Type.getMethodType(method.desc).getReturnType().getClassName(); if (tePacketClass.contains(".")) continue; ClassNode tePacket = getClassNode(tePacketClass); if (tePacket == null) continue; if (tePacket.interfaces.size() != 1) continue; ClassNode packet = getClassNode(tePacket.interfaces.get(0)); if ((packet.access & Opcodes.ACC_INTERFACE) == 0) continue; boolean isPacket = false; for (MethodNode m : packet.methods) { Type t = Type.getMethodType(m.desc); Type[] args = t.getArgumentTypes(); if (args.length != 1) continue; String packetBuffer_name = args[0].getClassName(); if (searchConstantPoolForStrings(packetBuffer_name, "VarInt too big", "String too big (was")) { addClassMapping("net/minecraft/network/PacketBuffer", packetBuffer_name); isPacket = true; break; } } if (!isPacket) continue; // TODO - Perhaps confirm this one, just in case they change their minds addClassMapping("net/minecraft/network/play/server/SPacketUpdateTileEntity", tePacket); addClassMapping("net/minecraft/network/Packet", packet); addMethodMapping("net/minecraft/tileentity/TileEntity getDescriptionPacket ()Lnet/minecraft/network/Packet;", tileEntity.name + " " + method.name + " " + method.desc); break; } // public void addInfoToCrashReport(CrashReportCategory reportCategory) methods.clear(); for (MethodNode method : tileEntity.methods) { Type t = Type.getMethodType(method.desc); Type[] args = t.getArgumentTypes(); if (t.getReturnType().getSort() != Type.VOID) continue; if (args.length != 1) continue; String className = args[0].getClassName(); if (searchConstantPoolForStrings(className, "(Error finding world loc)", "Details:")) { addClassMapping("net/minecraft/crash/CrashReportCategory", className); methods.add(method); } } if (methods.size() == 1) { addMethodMapping("net/minecraft/tileentity/TileEntity addInfoToCrashReport (Lnet/minecraft/crash/CrashReportCategory;)V", tileEntity.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public void markDirty() // public void updateContainingBlockInfo() // public void invalidate() // public void validate() methods = getMatchingMethods(tileEntity, null, "()V"); for (Iterator<MethodNode> it = methods.iterator(); it.hasNext();) { if (it.next().name.contains("<")) it.remove(); } if (methods.size() == 4) { List<MethodNode> matchedMethods = new ArrayList<>(); // public void validate() for (MethodNode method : methods) { if (matchOpcodeSequence(method.instructions.getFirst(), Opcodes.ALOAD, Opcodes.ICONST_0, Opcodes.PUTFIELD, Opcodes.RETURN)) { matchedMethods.add(method); } } if (matchedMethods.size() == 1) { addMethodMapping("net/minecraft/tileentity/TileEntity validate ()V", tileEntity.name + " " + matchedMethods.get(0).name + " ()V"); methods.remove(matchedMethods.get(0)); } // public void invalidate() matchedMethods.clear(); for (MethodNode method : methods) { if (matchOpcodeSequence(method.instructions.getFirst(), Opcodes.ALOAD, Opcodes.ICONST_1, Opcodes.PUTFIELD, Opcodes.RETURN)) { matchedMethods.add(method); } } if (matchedMethods.size() == 1) { addMethodMapping("net/minecraft/tileentity/TileEntity invalidate ()V", tileEntity.name + " " + matchedMethods.get(0).name + " ()V"); methods.remove(matchedMethods.get(0)); } // public void updateContainingBlockInfo() matchedMethods.clear(); for (MethodNode method : methods) { if (matchOpcodeSequence(method.instructions.getFirst(), Opcodes.ALOAD, Opcodes.ACONST_NULL, Opcodes.PUTFIELD, Opcodes.ALOAD, Opcodes.ICONST_M1, Opcodes.PUTFIELD, Opcodes.RETURN)) { matchedMethods.add(method); } } if (matchedMethods.size() == 1) { addMethodMapping("net/minecraft/tileentity/TileEntity updateContainingBlockInfo ()V", tileEntity.name + " " + matchedMethods.get(0).name + " ()V"); methods.remove(matchedMethods.get(0)); } // public void markDirty() if (methods.size() == 1) { for (AbstractInsnNode insn = methods.get(0).instructions.getFirst(); insn != null; insn = insn.getNext()) { if (insn.getOpcode() != Opcodes.GETSTATIC) continue; if (((FieldInsnNode)insn).owner.equals(blocks.name)) { addMethodMapping("net/minecraft/tileentity/TileEntity markDirty ()V", tileEntity.name + " " + methods.get(0).name + " ()V"); break; } } } } // TODO // public boolean hasWorldObj() // public boolean isInvalid() // public void readFromNBT(NBTTagCompound compound) // public void writeToNBT(NBTTagCompound compound) /*methods = getMatchingMethods(tileEntity, null, "(L" + tagCompound.name + ";)V"); if (methods.size() == 2) { MethodNode readFromNBT = null; MethodNode writeToNBT = null; for (MethodNode method : methods) { for (AbstractInsnNode insn = method.instructions.getFirst(); insn != null; insn = insn.getNext()) { if (insn.getOpcode() != Opcodes.NEW) continue; className = ((TypeInsnNode)insn).desc; if (className.equals(blockPos.name)) readFromNBT = method; else if (className.equals("java/lang/RuntimeException")) writeToNBT = method; } } if (readFromNBT != null && writeToNBT != null && readFromNBT != writeToNBT) { addMethodMapping("net/minecraft/tileentity/TileEntity readFromNBT (Lnet/minecraft/nbt/NBTTagCompound;)V", tileEntity.name + " " + readFromNBT.name + " " + readFromNBT.desc); addMethodMapping("net/minecraft/tileentity/TileEntity writeToNBT (Lnet/minecraft/nbt/NBTTagCompound;)V", tileEntity.name + " " + writeToNBT.name + " " + writeToNBT.desc); } }*/ // public void readFromNBT(NBTTagCompound compound) methods = getMatchingMethods(tileEntity, null, assembleDescriptor("(", tagCompound, ")V")); if (methods.size() == 1) { addMethodMapping("net/minecraft/tileentity/TileEntity readFromNBT (Lnet/minecraft/nbt/NBTTagCompound;)V", tileEntity.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public void writeToNBT(NBTTagCompound compound) methods = getMatchingMethods(tileEntity, null, assembleDescriptor("(", tagCompound, ")", tagCompound)); if (methods.size() == 2) { // Remove private method for (Iterator<MethodNode> it = methods.iterator(); it.hasNext();) { if ((it.next().access & Opcodes.ACC_PRIVATE) != 0) it.remove(); } addMethodMapping("net/minecraft/tileentity/TileEntity writeToNBT (Lnet/minecraft/nbt/NBTTagCompound;)Lnet/minecraft/nbt/NBTTagCompound;", tileEntity.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // TODO // @ClientOnly // public double getDistanceSq(double x, double y, double z) // @ClientOnly // public double getMaxRenderDistanceSquared() return true; } @Mapping(provides={ "net/minecraft/inventory/ContainerChest", "net/minecraft/tileentity/TileEntityLockable", "net/minecraft/util/ITickable", "net/minecraft/tileentity/TileEntityLootable" }, providesMethods={ "net/minecraft/util/ITickable update ()V" }, depends={ "net/minecraft/tileentity/TileEntity", "net/minecraft/tileentity/TileEntityChest", "net/minecraft/entity/player/InventoryPlayer", "net/minecraft/entity/player/EntityPlayer", "net/minecraft/inventory/Container", "net/minecraft/inventory/IInventory" }) public boolean processTileEntityChestClass() { ClassNode tileEntity = getClassNodeFromMapping("net/minecraft/tileentity/TileEntity"); ClassNode tileEntityChest = getClassNodeFromMapping("net/minecraft/tileentity/TileEntityChest"); ClassNode inventoryPlayer = getClassNodeFromMapping("net/minecraft/entity/player/InventoryPlayer"); ClassNode entityPlayer = getClassNodeFromMapping("net/minecraft/entity/player/EntityPlayer"); ClassNode container = getClassNodeFromMapping("net/minecraft/inventory/Container"); ClassNode iInventory = getClassNodeFromMapping("net/minecraft/inventory/IInventory"); if (!MeddleUtil.notNull(tileEntity, tileEntityChest, inventoryPlayer, entityPlayer, container, iInventory)) return false; // canitzp - renamed IUpdatePlayerListBox to ITickable if (tileEntityChest.interfaces.size() == 1) { String iUpdatePlayerListBox_name = tileEntityChest.interfaces.get(0); ClassNode iUpdatePlayerListBox = getClassNode(iUpdatePlayerListBox_name); if (iUpdatePlayerListBox.methods.size() == 1) { MethodNode m = iUpdatePlayerListBox.methods.get(0); if (m.desc.equals("()V")) { addClassMapping("net/minecraft/util/ITickable", iUpdatePlayerListBox_name); addMethodMapping("net/minecraft/util/ITickable update ()V", iUpdatePlayerListBox.name + " " + m.name + " ()V"); } } } if (searchConstantPoolForStrings(tileEntityChest.superName, "LootTable")) { addClassMapping("net/minecraft/tileentity/TileEntityLootable", tileEntityChest.superName); ClassNode lootTableClass = getClassNode(tileEntityChest.superName); // TODO - Do this a bit safer, get other interface classes ClassNode tileEntityLockable = getClassNode(lootTableClass.superName); if (tileEntityLockable.superName.equals(tileEntity.name)) addClassMapping("net/minecraft/tileentity/TileEntityLockable", tileEntityLockable.name); } // public Container createContainer(InventoryPlayer playerInventory, EntityPlayer playerIn) List<MethodNode> methods = getMatchingMethods(tileEntityChest, null, assembleDescriptor("(", inventoryPlayer, entityPlayer, ")", container)); if (methods.size() == 1) { for (AbstractInsnNode insn = methods.get(0).instructions.getFirst(); insn != null; insn = insn.getNext()) { if (insn.getOpcode() != Opcodes.NEW) continue; TypeInsnNode tn = (TypeInsnNode)insn; ClassNode containerChest = getClassNode(tn.desc); if (!containerChest.superName.equals(container.name)) continue; addClassMapping("net/minecraft/inventory/ContainerChest", containerChest); } } return true; } @Mapping(provides={ }, providesMethods={ "net/minecraft/inventory/IInventory openInventory (Lnet/minecraft/entity/player/EntityPlayer;)V", "net/minecraft/inventory/IInventory closeInventory (Lnet/minecraft/entity/player/EntityPlayer;)V" }, depends={ "net/minecraft/inventory/ContainerChest", "net/minecraft/inventory/IInventory", "net/minecraft/entity/player/EntityPlayer" }) public boolean processContainerChest() { ClassNode containerChest = getClassNodeFromMapping("net/minecraft/inventory/ContainerChest"); ClassNode iInventory = getClassNodeFromMapping("net/minecraft/inventory/IInventory"); ClassNode entityPlayer = getClassNodeFromMapping("net/minecraft/entity/player/EntityPlayer"); if (!MeddleUtil.notNull(containerChest, iInventory, entityPlayer)) return false; String openInventory = null; List<MethodNode> methods = getMatchingMethods(containerChest, "<init>", assembleDescriptor("(", iInventory, iInventory, entityPlayer, ")V")); if (methods.size() == 1) { for (AbstractInsnNode insn = methods.get(0).instructions.getFirst(); insn != null; insn = insn.getNext()) { if (insn.getOpcode() != Opcodes.INVOKEINTERFACE) continue; MethodInsnNode mn = (MethodInsnNode)insn; if (mn.owner.equals(iInventory.name) && mn.desc.equals("(L" + entityPlayer.name + ";)V")) { openInventory = mn.name; } } } methods = getMatchingMethods(iInventory, null, "(L" + entityPlayer.name + ";)V"); if (openInventory != null && methods.size() == 2) { for (MethodNode method : methods) { if (method.name.equals(openInventory)) { addMethodMapping("net/minecraft/inventory/IInventory openInventory (Lnet/minecraft/entity/player/EntityPlayer;)V", iInventory.name + " " + method.name + " " + method.desc); } else { addMethodMapping("net/minecraft/inventory/IInventory closeInventory (Lnet/minecraft/entity/player/EntityPlayer;)V", iInventory.name + " " + method.name + " " + method.desc); } } } return true; } @Mapping(provides="net/minecraft/entity/player/EntityPlayer", depends={ "net/minecraft/server/MinecraftServer", "net/minecraft/world/World", "net/minecraft/util/BlockPos"}) public boolean getEntityPlayerClass() { ClassNode serverClass = getClassNode(getClassMapping("net/minecraft/server/MinecraftServer")); ClassNode worldClass = getClassNode(getClassMapping("net/minecraft/world/World")); ClassNode blockPosClass = getClassNode(getClassMapping("net/minecraft/util/BlockPos")); if (serverClass == null || worldClass == null || blockPosClass == null) return false; List<String> potentialClasses = new ArrayList<String>(); // Find isBlockProtected(World, BlockPos, EntityPlayer)Z for (MethodNode method : serverClass.methods) { Type t = Type.getMethodType(method.desc); if (t.getReturnType().getSort() != Type.BOOLEAN) continue; if (!checkMethodParameters(method, Type.OBJECT, Type.OBJECT, Type.OBJECT)) continue; Type[] args = t.getArgumentTypes(); if (!args[0].getClassName().equals(worldClass.name) || !args[1].getClassName().equals(blockPosClass.name)) continue; potentialClasses.add(args[2].getClassName()); } if (potentialClasses.size() != 1) return false; String className = potentialClasses.get(0); if (!searchConstantPoolForStrings(className, "Inventory", "Notch")) return false; addClassMapping("net/minecraft/entity/player/EntityPlayer", getClassNode(className)); return true; } @Mapping(provides="net/minecraft/entity/EntityLivingBase", depends="net/minecraft/entity/player/EntityPlayer") public boolean getEntityLivingBaseClass() { ClassNode entityPlayerClass = getClassNode(getClassMapping("net/minecraft/entity/player/EntityPlayer")); if (entityPlayerClass == null || entityPlayerClass.superName == null) return false; if (!searchConstantPoolForStrings(entityPlayerClass.superName, "Health", "doMobLoot", "ai")) return false; addClassMapping("net/minecraft/entity/EntityLivingBase", getClassNode(entityPlayerClass.superName)); return true; } @Mapping(provides="net/minecraft/entity/Entity", depends="net/minecraft/entity/EntityLivingBase") public boolean getEntityClass() { ClassNode entityLivingBase = getClassNode(getClassMapping("net/minecraft/entity/EntityLivingBase")); if (entityLivingBase == null || entityLivingBase.superName == null) return false; ClassNode entity = getClassNode(entityLivingBase.superName); if (!entity.superName.equals("java/lang/Object")) return false; addClassMapping("net/minecraft/entity/Entity", entity); return true; } @Mapping(providesMethods={ "net/minecraft/entity/Entity getFlag (I)Z", "net/minecraft/entity/Entity isSneaking ()Z" }, depends={ "net/minecraft/entity/Entity" }) public boolean processEntityClass() { ClassNode entity = getClassNodeFromMapping("net/minecraft/entity/Entity"); if (entity == null) return false; MethodNode getFlag = null; // protected boolean getFlag(int flag) List<MethodNode> methods = getMatchingMethods(entity, null, "(I)Z"); if (methods.size() == 1) { getFlag = methods.get(0); addMethodMapping("net/minecraft/entity/Entity getFlag (I)Z", entity.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public boolean isSneaking() methods = getMatchingMethods(entity, null, "()Z"); for (Iterator<MethodNode> it = methods.iterator(); it.hasNext();) { MethodNode method = it.next(); AbstractInsnNode[] nodes = getOpcodeSequenceArray(method.instructions.getFirst(), Opcodes.ALOAD, Opcodes.ICONST_1, Opcodes.INVOKEVIRTUAL, Opcodes.IRETURN); if (nodes == null) { it.remove(); continue; } MethodInsnNode mn = (MethodInsnNode)nodes[2]; if (!mn.owner.equals(entity.name) || !mn.name.equals(getFlag.name) || !mn.desc.equals(getFlag.desc)) it.remove(); } if (methods.size() == 1) { addMethodMapping("net/minecraft/entity/Entity isSneaking ()Z", entity.name + " " + methods.get(0).name + " " + methods.get(0).desc); } return true; } @Mapping(provides="net/minecraft/entity/EntityList", depends="net/minecraft/entity/Entity") public boolean getEntityListClass() { ClassNode entity = getClassNode(getClassMapping("net/minecraft/entity/Entity")); if (entity == null) return false; String className = null; // Try to find: public void travelToDimension(int) // NOTE: Mojang changed to public Entity travelToDimension(int, BlockPos) for (MethodNode method : entity.methods) { if (!method.desc.startsWith("(I")) continue; boolean foundFirst = false; boolean foundSecond = false; for (AbstractInsnNode insn = method.instructions.getFirst(); insn != null; insn = insn.getNext()) { if (!foundFirst && !isLdcWithString(insn, "changeDimension")) continue; else foundFirst = true; if (!foundSecond && !isLdcWithString(insn, "reloading")) continue; else foundSecond = true; if (insn.getOpcode() == Opcodes.INVOKESTATIC) { MethodInsnNode mn = (MethodInsnNode)insn; if (className == null) { className = mn.owner; continue; } else if (!className.equals(mn.owner)) return false; } if (className != null) break; } if (className != null) break; } if (!searchConstantPoolForStrings(className, "ThrownPotion", "EnderDragon")) return false; addClassMapping("net/minecraft/entity/EntityList", getClassNode(className)); return true; } // Parses net.minecraft.entity.EntityList to match entity names to // their associated classes. // Note: Doesn't handle minecarts, as those aren't registered directly with names. @Mapping(provides={ "net/minecraft/entity/monster/EntityZombie", "net/minecraft/entity/passive/EntityVillager", "net/minecraft/entity/passive/EntitySheep", "net/minecraft/entity/monster/EntityEnderman", "net/minecraft/entity/item/EntityEnderPearl", "net/minecraft/entity/monster/EntityCreeper", "net/minecraft/entity/passive/EntityOcelot", "net/minecraft/entity/item/EntityItemFrame", "net/minecraft/entity/item/EntityPainting", "net/minecraft/entity/projectile/EntityPotion", "net/minecraft/entity/item/EntityFallingBlock", "net/minecraft/entity/item/EntityFireworkRocket", "net/minecraft/entity/item/EntityArmorStand", //"net/minecraft/entity/EntityLiving", "net/minecraft/entity/monster/EntitySkeleton", "net/minecraft/entity/monster/EntitySlime", "net/minecraft/entity/boss/EntityDragon", "net/minecraft/entity/passive/EntityBat", "net/minecraft/entity/passive/EntityChicken", "net/minecraft/entity/passive/EntityWolf", "net/minecraft/entity/passive/EntityHorse", "net/minecraft/entity/passive/EntityRabbit", "net/minecraft/entity/item/EntityEnderCrystal" }, dependsFields={ "net/minecraft/init/Sounds entity_skeleton_step Lnet/minecraft/util/Sound;" }, depends={ "net/minecraft/entity/EntityList" } ) public boolean parseEntityList() { Map<String, String> entityListClasses = new HashMap<String, String>(); ClassNode entityList = getClassNode(getClassMapping("net/minecraft/entity/EntityList")); if (entityList == null) return false; List<MethodNode> methods = getMatchingMethods(entityList, null, "()V"); for (Iterator<MethodNode> it = methods.iterator(); it.hasNext(); ) { MethodNode mn = it.next(); if (mn.name.startsWith("<")) it.remove(); if ((mn.access & Opcodes.ACC_STATIC) == 0) continue; } if (methods.size() != 1) return false; String entityClass = null; String entityName = null; // Create entity list for (AbstractInsnNode insn = getNextRealOpcode(methods.get(0).instructions.getFirst()); insn != null; insn = getNextRealOpcode(insn.getNext())) { // Ignore numeric ID insn = getNextRealOpcode(insn.getNext()); if (insn == null) break; String newID = getLdcString(insn); if (newID == null) continue; insn = getNextRealOpcode(insn.getNext()); if (insn == null) break; entityClass = getLdcClass(insn); if (entityClass == null) continue; insn = getNextRealOpcode(insn.getNext()); if (insn == null) break; entityName = getLdcString(insn); if (entityName == null) continue; // ignore invokestatic insn = getNextRealOpcode(insn.getNext()); if (insn == null) break; entityListClasses.put(entityName, entityClass); } // Get EntityZombie String zombieClass = entityListClasses.get("Zombie"); if (zombieClass != null) { if (searchConstantPoolForStrings(zombieClass, "zombie.spawnReinforcements", "IsBaby")) { addClassMapping("net/minecraft/entity/monster/EntityZombie", zombieClass); } } String villagerClass = entityListClasses.get("Villager"); if (villagerClass != null) { if (searchConstantPoolForStrings(villagerClass, "Profession", "entity.Villager.")) { addClassMapping("net/minecraft/entity/passive/EntityVillager", villagerClass); } } // Can't detect "mob.sheep.shear" as of 15w43a String sheepClass = entityListClasses.get("Sheep"); if (sheepClass != null) { if (searchConstantPoolForStrings(sheepClass, "Sheared")) { addClassMapping("net/minecraft/entity/passive/EntitySheep", sheepClass); } } // Can't detect for "mob.endermen.portal" as of 15w43a String endermanClass = entityListClasses.get("Enderman"); if (endermanClass != null) { if (searchConstantPoolForStrings(endermanClass, "carried", "carriedData")) { addClassMapping("net/minecraft/entity/monster/EntityEnderman", endermanClass); } } String enderpearlClass = entityListClasses.get("ThrownEnderpearl"); if (enderpearlClass != null) { if (searchConstantPoolForStrings(enderpearlClass, "doMobSpawning")) { // TODO - Better detection addClassMapping("net/minecraft/entity/item/EntityEnderPearl", enderpearlClass); } } String creeperClass = entityListClasses.get("Creeper"); if (creeperClass != null) { if (searchConstantPoolForStrings(creeperClass, "mobGriefing", "Fuse", "ExplosionRadius")) { addClassMapping("net/minecraft/entity/monster/EntityCreeper", creeperClass); } } String ocelotClass = entityListClasses.get("Ozelot"); if (ocelotClass != null) { if (searchConstantPoolForStrings(ocelotClass, "CatType", "entity.Cat.name")) { addClassMapping("net/minecraft/entity/passive/EntityOcelot", ocelotClass); } } String itemFrameClass = entityListClasses.get("ItemFrame"); if (itemFrameClass != null) { if (searchConstantPoolForStrings(itemFrameClass, "frame-", "ItemRotation")) { addClassMapping("net/minecraft/entity/item/EntityItemFrame", itemFrameClass); } } String paintingClass = entityListClasses.get("Painting"); if (paintingClass != null) { if (searchConstantPoolForStrings(paintingClass, "Motive", "doEntityDrops")) { addClassMapping("net/minecraft/entity/item/EntityPainting", paintingClass); } } String potionClass = entityListClasses.get("ThrownPotion"); if (potionClass != null) { if (searchConstantPoolForStrings(potionClass, "ThrownPotion entity {} has no item?!")) { addClassMapping("net/minecraft/entity/projectile/EntityPotion", potionClass); } } String fallingBlockClass = entityListClasses.get("FallingSand"); if (fallingBlockClass != null) { if (searchConstantPoolForStrings(fallingBlockClass, "DropItem", "FallHurtAmount")) { addClassMapping("net/minecraft/entity/item/EntityFallingBlock", fallingBlockClass); } } String fireworkClass = entityListClasses.get("FireworksRocketEntity"); if (fireworkClass != null) { if (searchConstantPoolForStrings(fireworkClass, "Fireworks", "Flight")) { addClassMapping("net/minecraft/entity/item/EntityFireworkRocket", fireworkClass); } } String armorStandClass = entityListClasses.get("ArmorStand"); if (armorStandClass != null) { if (searchConstantPoolForStrings(armorStandClass, "ArmorItems", "ShowArms", "Pose")) { addClassMapping("net/minecraft/entity/item/EntityArmorStand", armorStandClass); } } // No longer present in 16w32a /*String livingClass = entityListClasses.get("Mob"); if (livingClass != null) { if (searchConstantPoolForStrings(livingClass, "mobBaseTick", "CanPickUpLoot", "PersistenceRequired")) { addClassMapping("net/minecraft/entity/EntityLiving", livingClass); } }*/ String skeletonClass = entityListClasses.get("Skeleton"); if (skeletonClass != null) { if (searchConstantPoolForFields(skeletonClass, getSoundFieldFull("entity_skeleton_step"))) { addClassMapping("net/minecraft/entity/monster/EntitySkeleton", skeletonClass); } } String slimeClass = entityListClasses.get("Slime"); if (slimeClass != null) { if (searchConstantPoolForStrings(slimeClass, "Size", "wasOnGround")) { addClassMapping("net/minecraft/entity/monster/EntitySlime", slimeClass); } } String dragonClass = entityListClasses.get("EnderDragon"); if (dragonClass != null) { if (searchConstantPoolForStrings(dragonClass, "Failed to find path from {} to {}", "DragonPhase")) { addClassMapping("net/minecraft/entity/boss/EntityDragon", dragonClass); } } String batClass = entityListClasses.get("Bat"); if (batClass != null) { if (searchConstantPoolForStrings(batClass, "BatFlags")) { addClassMapping("net/minecraft/entity/passive/EntityBat", batClass); } } String chickenClass = entityListClasses.get("Chicken"); if (chickenClass != null) { if (searchConstantPoolForStrings(chickenClass, "IsChickenJockey", "EggLayTime")) { addClassMapping("net/minecraft/entity/passive/EntityChicken", chickenClass); } } String wolfClass = entityListClasses.get("Wolf"); if (wolfClass != null) { if (searchConstantPoolForStrings(wolfClass, "Angry", "CollarColor")) { addClassMapping("net/minecraft/entity/passive/EntityWolf", wolfClass); } } String horseClass = entityListClasses.get("Horse"); if (horseClass != null) { if (searchConstantPoolForStrings(horseClass, "Horse armor bonus")) { addClassMapping("net/minecraft/entity/passive/EntityHorse", horseClass); } } String rabbitClass = entityListClasses.get("Rabbit"); if (rabbitClass != null) { if (searchConstantPoolForStrings(rabbitClass, "RabbitType", "MoreCarrotTicks")) { addClassMapping("net/minecraft/entity/passive/EntityRabbit", rabbitClass); } } String enderCrystalClass = entityListClasses.get("EnderCrystal"); if (enderCrystalClass != null) { if (searchConstantPoolForStrings(enderCrystalClass, "BeamTarget", "ShowBottom")) { addClassMapping("net/minecraft/entity/item/EntityEnderCrystal", enderCrystalClass); } } return true; } @Mapping(provides={ "net/minecraft/entity/monster/EntityMob", "net/minecraft/world/GameRules", "net/minecraft/world/Explosion" }, providesMethods={ "net/minecraft/entity/Entity onUpdate ()V", "net/minecraft/entity/Entity playSound (Lnet/minecraft/util/Sound;FF)V", "net/minecraft/entity/monster/EntityCreeper explode ()V", "net/minecraft/world/World getGameRules ()Lnet/minecraft/world/GameRules;", "net/minecraft/world/World createExplosion (Lnet/minecraft/entity/Entity;DDDFZ)Lnet/minecraft/world/Explosion;" }, dependsFields={ "net/minecraft/init/Sounds entity_creeper_primed Lnet/minecraft/util/Sound;", "net/minecraft/init/Sounds entity_hostile_hurt Lnet/minecraft/util/Sound;", "net/minecraft/init/Sounds entity_hostile_swim Lnet/minecraft/util/Sound;", "net/minecraft/init/Sounds entity_generic_explode Lnet/minecraft/util/Sound;" }, depends={ "net/minecraft/entity/monster/EntityCreeper", "net/minecraft/entity/Entity", "net/minecraft/world/World", "net/minecraft/init/Sounds", "net/minecraft/util/Sound" }) public boolean processEntityCreeperClass() { ClassNode creeper = getClassNodeFromMapping("net/minecraft/entity/monster/EntityCreeper"); ClassNode entity = getClassNodeFromMapping("net/minecraft/entity/Entity"); ClassNode world = getClassNodeFromMapping("net/minecraft/world/World"); ClassNode sounds = getClassNodeFromMapping("net/minecraft/init/Sounds"); ClassNode sound = getClassNodeFromMapping("net/minecraft/util/Sound"); if (!MeddleUtil.notNull(creeper, entity, world, sound, sounds)) return false; String hurtSound = getSoundFieldFull("entity.hostile.hurt"); String swimSound = getSoundFieldFull("entity.hostile.swim"); if (searchConstantPoolForFields(creeper.superName, hurtSound, swimSound)) addClassMapping("net/minecraft/entity/monster/EntityMob", creeper.superName); String fieldPrimed = getSoundField("entity.creeper.primed"); // public void onUpdate() List<MethodNode> methods = getMatchingMethods(creeper, null, "()V"); for (Iterator<MethodNode> it = methods.iterator(); it.hasNext();) { MethodNode method = it.next(); boolean hasIt = false; //for (AbstractInsnNode insn = method.instructions.getFirst(); insn != null; insn = insn.getNext()) { //if (isLdcWithString(insn, "creeper.primed")) hasIt = true; //} List<FieldInsnNode> fields = getAllInsnNodesOfType(method.instructions.getFirst(), FieldInsnNode.class); for (FieldInsnNode fn : fields) { if (fn.owner.equals(sounds.name) && fn.name.equals(fieldPrimed)) hasIt = true; } if (!hasIt) it.remove(); } String explodeName = null; if (methods.size() == 1) { addMethodMapping("net/minecraft/entity/Entity onUpdate ()V", entity.name + " " + methods.get(0).name + " ()V"); MethodInsnNode playSound = null; int playSoundCount = 0; MethodInsnNode explode = null; int explodeCount = 0; // public void playSound(String name, float volume, float pitch) List<MethodInsnNode> nodes = getAllInsnNodesOfType(methods.get(0).instructions.getFirst(), MethodInsnNode.class); for (MethodInsnNode mn : nodes) { //System.out.println(mn.owner + "(" + DynamicMappings.getReverseClassMapping(mn.owner) + ") " + mn.name + " " + mn.desc); if (mn.owner.equals(creeper.name) && mn.desc.equals("(L" + sound.name + ";FF)V")) { playSound = mn; playSoundCount++; } if (mn.owner.equals(creeper.name) && mn.desc.equals("()V")) { explode = mn; explodeCount++; } if (playSoundCount == 1) { addMethodMapping("net/minecraft/entity/Entity playSound (Lnet/minecraft/util/Sound;FF)V", entity.name + " " + playSound.name + " " + playSound.desc); } if (explodeCount == 1) { addMethodMapping("net/minecraft/entity/monster/EntityCreeper explode ()V", creeper.name + " " + explode.name + " ()V"); explodeName = explode.name; } } } String gameRules = null; String soundExplosion = getSoundFieldFull("entity.generic.explode"); // net/minecraft/world/GameRules // World: public GameRules getGameRules() // World: public Explosion createExplosion(Entity param0, double param1, double param2, double param3, float param4, boolean param5) { MethodNode explode = getMethodNodeFromMapping(creeper, "net/minecraft/entity/monster/EntityCreeper explode ()V"); if (explode != null) { List<MethodInsnNode> miNodes = getAllInsnNodesOfType(explode.instructions.getFirst(), MethodInsnNode.class); for (MethodInsnNode mn : miNodes) { //System.out.println(mn.owner + "(" + DynamicMappings.getReverseClassMapping(mn.owner) + ") " + mn.name + " " + mn.desc); if (mn.owner.equals(world.name)) { if (mn.desc.startsWith("()L")) { String returnClass = Type.getMethodType(mn.desc).getReturnType().getClassName(); if (searchConstantPoolForStrings(returnClass, "doFireTick", "doDaylightCycle", "reducedDebugInfo")) { gameRules = returnClass; addClassMapping("net/minecraft/world/GameRules", returnClass); addMethodMapping("net/minecraft/world/World getGameRules ()Lnet/minecraft/world/GameRules;", world.name + " " + mn.name + " " + mn.desc); } } else if (mn.desc.startsWith("(L" + entity.name + ";DDDFZ)L")) { String returnClass = Type.getMethodType(mn.desc).getReturnType().getClassName(); if (searchConstantPoolForFields(returnClass, soundExplosion)) { addClassMapping("net/minecraft/world/Explosion", returnClass); addMethodMapping("net/minecraft/world/World createExplosion (Lnet/minecraft/entity/Entity;DDDFZ)Lnet/minecraft/world/Explosion;", world.name + " " + mn.name + " " + mn.desc); } } } } } return true; } @Mapping(providesMethods={ "net/minecraft/world/Explosion doExplosionA ()V", "net/minecraft/world/Explosion doExplosionB (Z)V" }, depends={ "net/minecraft/world/Explosion" }) public boolean processExplosionClass() { ClassNode explosion = getClassNodeFromMapping("net/minecraft/world/Explosion"); if (explosion == null) return false; // public void doExplosionA() List<MethodNode> methods = getMatchingMethods(explosion, null, "()V"); for (Iterator<MethodNode> it = methods.iterator(); it.hasNext();) { MethodNode mn = it.next(); if (mn.name.startsWith("<")) { it.remove(); continue; } if (matchOpcodeSequence(mn.instructions.getFirst(), Opcodes.ALOAD, Opcodes.GETFIELD, Opcodes.INVOKEINTERFACE, Opcodes.RETURN)) { it.remove(); continue; } } if (methods.size() == 1) { addMethodMapping("net/minecraft/world/Explosion doExplosionA ()V", explosion.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public void doExplosionB(boolean p_77279_1_) methods = getMatchingMethods(explosion, null, "(Z)V"); if (methods.size() == 1) { addMethodMapping("net/minecraft/world/Explosion doExplosionB (Z)V", explosion.name + " " + methods.get(0).name + " " + methods.get(0).desc); } return true; } @Mapping(provides={ }, providesFields={ "net/minecraft/entity/monster/EntityEnderman carriableBlocks Ljava/util/Set;" }, providesMethods={ //"net/minecraft/entity/Entity setPositionAndUpdate (DDD)V" }, depends={ "net/minecraft/entity/monster/EntityEnderman", "net/minecraft/entity/EntityLivingBase", "net/minecraft/entity/Entity" }) public boolean processEntityEndermanClass() { ClassNode entityEnderman = getClassNodeFromMapping("net/minecraft/entity/monster/EntityEnderman"); ClassNode entityLivingBase = getClassNodeFromMapping("net/minecraft/entity/EntityLivingBase"); ClassNode entity = getClassNodeFromMapping("net/minecraft/entity/Entity"); if (!MeddleUtil.notNull(entityEnderman, entityLivingBase, entity)) return false; List<FieldNode> fields = getMatchingFields(entityEnderman, null, "Ljava/util/Set;"); if (fields.size() == 1) { addFieldMapping("net/minecraft/entity/monster/EntityEnderman carriableBlocks Ljava/util/Set;", entityEnderman.name + " " + fields.get(0).name + " " + fields.get(0).desc); } /* * Removed for 15w49a, moved elsewhere * List<MethodNode> methods = getMatchingMethods(entityEnderman, null, "(L" + entityLivingBase.name + ";DDD)Z"); if (methods.size() == 1) { Set<String> methodNames = new HashSet<>(); for (AbstractInsnNode insn = methods.get(0).instructions.getFirst(); insn != null; insn = insn.getNext()) { if (insn.getOpcode() == Opcodes.INVOKEVIRTUAL) { MethodInsnNode mn = (MethodInsnNode)insn; if (mn.owner.equals(entityLivingBase.name) && mn.desc.equals("(DDD)V")) methodNames.add(mn.name); continue; } } // Entity.setPositionAndUpdate(DDD)V if (methodNames.size() == 1) { String name = methodNames.iterator().next(); addMethodMapping("net/minecraft/entity/Entity setPositionAndUpdate (DDD)V", entity.name + " " + name + " (DDD)V"); } }*/ // TODO /*for (FieldNode field : entityEnderman.fields) { Type t = Type.getType(field.desc); if (t.getSort() != Type.OBJECT) continue; System.out.println(t.getClassName()); }*/ return true; } @Mapping(providesFields={ "net/minecraft/entity/Entity fallDistance F" }, depends={ "net/minecraft/entity/item/EntityEnderPearl", "net/minecraft/entity/Entity", "net/minecraft/entity/EntityLivingBase", "net/minecraft/util/MovingObjectPosition" }) public boolean processEntityEnderPearlClass() { ClassNode pearl = getClassNodeFromMapping("net/minecraft/entity/item/EntityEnderPearl"); ClassNode entity = getClassNodeFromMapping("net/minecraft/entity/Entity"); ClassNode entityLivingBase = getClassNodeFromMapping("net/minecraft/entity/EntityLivingBase"); ClassNode movingObjectPos = getClassNodeFromMapping("net/minecraft/util/MovingObjectPosition"); if (pearl == null || entity == null || movingObjectPos == null) return false; // protected void onImpact(MovingObjectPosition param0) List<MethodNode> methods = getMatchingMethods(pearl, null, "(L" + movingObjectPos.name + ";)V"); if (methods.size() == 1) { Set<String> fieldNames = new HashSet<>(); for (AbstractInsnNode insn = methods.get(0).instructions.getFirst(); insn != null; insn = insn.getNext()) { if (insn.getOpcode() == Opcodes.FCONST_0) { AbstractInsnNode node = getNextRealOpcode(insn.getNext()); if (node != null && node.getOpcode() == Opcodes.PUTFIELD) { FieldInsnNode fn = (FieldInsnNode)node; if (fn.owner.equals(entityLivingBase.name) && fn.desc.equals("F")) fieldNames.add(fn.name); } } } if (fieldNames.size() == 1 ) { String name = fieldNames.iterator().next(); addFieldMapping("net/minecraft/entity/Entity fallDistance F", entity.name + " " + name + " F"); } } return true; } @Mapping(provides={ "net/minecraft/block/BlockAir", "net/minecraft/block/BlockStone", "net/minecraft/block/BlockGrass", "net/minecraft/block/BlockDirt", "net/minecraft/block/BlockPlanks", "net/minecraft/block/BlockSapling", "net/minecraft/block/BlockDynamicLiquid", "net/minecraft/block/BlockStaticLiquid", "net/minecraft/block/BlockSand", "net/minecraft/block/BlockGravel", "net/minecraft/block/BlockOre", "net/minecraft/block/BlockOldLog", "net/minecraft/block/BlockOldLeaf", "net/minecraft/block/BlockSponge", "net/minecraft/block/BlockGlass", "net/minecraft/block/BlockDispenser", "net/minecraft/block/BlockSandStone", "net/minecraft/block/BlockNote", "net/minecraft/block/BlockBed", "net/minecraft/block/BlockRailPowered", "net/minecraft/block/BlockRailDetector", "net/minecraft/block/BlockPistonBase", "net/minecraft/block/BlockWeb", "net/minecraft/block/BlockTallGrass", "net/minecraft/block/BlockDeadBush", "net/minecraft/block/BlockPistonExtension", "net/minecraft/block/BlockColored", "net/minecraft/block/BlockPistonMoving", "net/minecraft/block/BlockYellowFlower", "net/minecraft/block/BlockRedFlower", "net/minecraft/block/BlockMushroom", "net/minecraft/block/BlockDoubleStoneSlab", "net/minecraft/block/BlockHalfStoneSlab", "net/minecraft/block/BlockTNT", "net/minecraft/block/BlockBookshelf", "net/minecraft/block/BlockObsidian", "net/minecraft/block/BlockTorch", "net/minecraft/block/BlockFire", "net/minecraft/block/BlockMobSpawner", "net/minecraft/block/BlockStairs", "net/minecraft/block/BlockChest", "net/minecraft/block/BlockRedstoneWire", "net/minecraft/block/BlockWorkbench", "net/minecraft/block/BlockWorkbench$InterfaceCraftingTable", "net/minecraft/block/BlockCrops", "net/minecraft/block/BlockFarmland", "net/minecraft/block/BlockFurnace", "net/minecraft/block/BlockStandingSign", "net/minecraft/block/BlockDoor", "net/minecraft/block/BlockLadder", "net/minecraft/block/BlockRail", "net/minecraft/block/BlockWallSign", "net/minecraft/block/BlockLever", "net/minecraft/block/BlockPressurePlate", "net/minecraft/block/BlockRedstoneOre", "net/minecraft/block/BlockRedstoneTorch", "net/minecraft/block/BlockButtonStone", "net/minecraft/block/BlockSnow", "net/minecraft/block/BlockIce", "net/minecraft/block/BlockSnowBlock", "net/minecraft/block/BlockCactus", "net/minecraft/block/BlockClay", "net/minecraft/block/BlockReed", "net/minecraft/block/BlockJukebox", "net/minecraft/block/BlockFence", "net/minecraft/block/BlockPumpkin", "net/minecraft/block/BlockNetherrack", "net/minecraft/block/BlockSoulSand", "net/minecraft/block/BlockGlowstone", "net/minecraft/block/BlockPortal", "net/minecraft/block/BlockCake", "net/minecraft/block/BlockRedstoneRepeater", "net/minecraft/block/BlockStainedGlass", "net/minecraft/block/BlockTrapDoor", "net/minecraft/block/BlockSilverfish", "net/minecraft/block/BlockStoneBrick", "net/minecraft/block/BlockHugeMushroom", "net/minecraft/block/BlockPane", "net/minecraft/block/BlockMelon", "net/minecraft/block/BlockStem", "net/minecraft/block/BlockVine", "net/minecraft/block/BlockFenceGate", "net/minecraft/block/BlockMycelium", "net/minecraft/block/BlockLilyPad", "net/minecraft/block/BlockNetherBrick", "net/minecraft/block/BlockNetherWart", "net/minecraft/block/BlockEnchantmentTable", "net/minecraft/block/BlockBrewingStand", "net/minecraft/block/BlockCauldron", "net/minecraft/block/BlockEndPortal", "net/minecraft/block/BlockEndPortalFrame", "net/minecraft/block/BlockDragonEgg", "net/minecraft/block/BlockRedstoneLight", "net/minecraft/block/BlockDoubleWoodSlab", "net/minecraft/block/BlockHalfWoodSlab", "net/minecraft/block/BlockCocoa", "net/minecraft/block/BlockEnderChest", "net/minecraft/block/BlockTripWireHook", "net/minecraft/block/BlockTripWire", "net/minecraft/block/BlockCommandBlock", "net/minecraft/block/BlockBeacon", "net/minecraft/block/BlockWall", "net/minecraft/block/BlockFlowerPot", "net/minecraft/block/BlockCarrot", "net/minecraft/block/BlockPotato", "net/minecraft/block/BlockButtonWood", "net/minecraft/block/BlockSkull", "net/minecraft/block/BlockAnvil", "net/minecraft/block/BlockPressurePlateWeighted", "net/minecraft/block/BlockRedstoneComparator", "net/minecraft/block/BlockDaylightDetector", "net/minecraft/block/BlockCompressedPowered", "net/minecraft/block/BlockHopper", "net/minecraft/block/BlockQuartz", "net/minecraft/block/BlockDropper", "net/minecraft/block/BlockStainedGlassPane", "net/minecraft/block/BlockNewLeaf", "net/minecraft/block/BlockNewLog", "net/minecraft/block/BlockSlime", "net/minecraft/block/BlockBarrier", "net/minecraft/block/BlockPrismarine", "net/minecraft/block/BlockSeaLantern", "net/minecraft/block/BlockHay", "net/minecraft/block/BlockCarpet", "net/minecraft/block/BlockHardenedClay", "net/minecraft/block/BlockPackedIce", "net/minecraft/block/BlockDoublePlant", "net/minecraft/block/BlockBanner$BlockBannerStanding", "net/minecraft/block/BlockBanner$BlockBannerHanging", "net/minecraft/block/BlockRedSandstone", "net/minecraft/block/BlockDoubleStoneSlabNew", "net/minecraft/block/BlockHalfStoneSlabNew" }, dependsMethods={ "net/minecraft/block/Block registerBlocks ()V" }, depends={ "net/minecraft/block/Block", "net/minecraft/util/ResourceLocation" }) public boolean discoverBlocks() { ClassNode block = getClassNodeFromMapping("net/minecraft/block/Block"); MethodNode registerBlocks = getMethodNodeFromMapping(block, "net/minecraft/block/Block registerBlocks ()V"); MethodNode registerBlock1 = getMethodNodeFromMapping(block, "net/minecraft/block/Block registerBlock (ILjava/lang/String;Lnet/minecraft/block/Block;)V"); MethodNode registerBlock2 = getMethodNodeFromMapping(block, "net/minecraft/block/Block registerBlock (ILnet/minecraft/util/ResourceLocation;Lnet/minecraft/block/Block;)V"); if (registerBlocks == null || registerBlock1 == null || registerBlock2 == null) return false; // Create a map if the block ids and their respective classes. Map<Integer, String> blockClassMap = new HashMap<>(); blockClassMap.put(0, "net/minecraft/block/BlockAir"); // 0 - air blockClassMap.put(1, "net/minecraft/block/BlockStone"); // 1 - stone blockClassMap.put(2, "net/minecraft/block/BlockGrass"); // 2 - grass blockClassMap.put(3, "net/minecraft/block/BlockDirt"); // 3 - dirt // 4 - cobblestone already mapped (Block) blockClassMap.put(5, "net/minecraft/block/BlockPlanks"); // 5 - planks blockClassMap.put(6, "net/minecraft/block/BlockSapling"); // 6 - sapling // 7 - bedrock already mapped (Block) blockClassMap.put(8, "net/minecraft/block/BlockDynamicLiquid"); // 8 - flowing_water blockClassMap.put(9, "net/minecraft/block/BlockStaticLiquid"); // 9 - water // 10 - flowing_lava already mapped (BlockDynamicLiquid) // 11 - lava already mapped (BlockStaticLiquid) blockClassMap.put(12, "net/minecraft/block/BlockSand"); // 12 - sand blockClassMap.put(13, "net/minecraft/block/BlockGravel"); // 13 - gravel blockClassMap.put(14, "net/minecraft/block/BlockOre"); // 14 - gold_ore // 15 - iron_ore already mapped (BlockOre) // 16 - coal_ore already mapped (BlockOre) blockClassMap.put(17, "net/minecraft/block/BlockOldLog"); // 17 - log blockClassMap.put(18, "net/minecraft/block/BlockOldLeaf"); // 18 - leaves blockClassMap.put(19, "net/minecraft/block/BlockSponge"); // 19 - sponge blockClassMap.put(20, "net/minecraft/block/BlockGlass"); // 20 - glass // 21 - lapis_ore already mapped (BlockOre) // blockClassMap.put(22, "net/minecraft/block/BlockCompressed"); // 22 - lapis_block - now it's a Block blockClassMap.put(23, "net/minecraft/block/BlockDispenser"); // 23 - dispenser blockClassMap.put(24, "net/minecraft/block/BlockSandStone"); // 24 - sandstone blockClassMap.put(25, "net/minecraft/block/BlockNote"); // 25 - noteblock blockClassMap.put(26, "net/minecraft/block/BlockBed"); // 26 - bed blockClassMap.put(27, "net/minecraft/block/BlockRailPowered"); // 27 - golden_rail blockClassMap.put(28, "net/minecraft/block/BlockRailDetector"); // 28 - detector_rail blockClassMap.put(29, "net/minecraft/block/BlockPistonBase"); // 29 - sticky_piston blockClassMap.put(30, "net/minecraft/block/BlockWeb"); // 30 - web blockClassMap.put(31, "net/minecraft/block/BlockTallGrass"); // 31 - tallgrass blockClassMap.put(32, "net/minecraft/block/BlockDeadBush"); // 32 - deadbush // 33 - piston already mapped (BlockPistonBase) blockClassMap.put(34, "net/minecraft/block/BlockPistonExtension"); // 34 - piston_head blockClassMap.put(35, "net/minecraft/block/BlockColored"); // 35 - wool blockClassMap.put(36, "net/minecraft/block/BlockPistonMoving"); // 36 - piston_extension blockClassMap.put(37, "net/minecraft/block/BlockYellowFlower"); // 37 - yellow_flower blockClassMap.put(38, "net/minecraft/block/BlockRedFlower"); // 38 - red_flower blockClassMap.put(39, "net/minecraft/block/BlockMushroom"); // 39 - brown_mushroom // 40 - red_mushroom already mapped (BlockMushroom) // 41 - gold_block already mapped (BlockCompressed) // 42 - iron_block already mapped (BlockCompressed) blockClassMap.put(43, "net/minecraft/block/BlockDoubleStoneSlab"); // 43 - double_stone_slab blockClassMap.put(44, "net/minecraft/block/BlockHalfStoneSlab"); // 44 - stone_slab // 45 - brick_block already mapped (Block) blockClassMap.put(46, "net/minecraft/block/BlockTNT"); // 46 - tnt blockClassMap.put(47, "net/minecraft/block/BlockBookshelf"); // 47 - bookshelf // 48 - mossy_cobblestone already mapped (Block) blockClassMap.put(49, "net/minecraft/block/BlockObsidian"); // 49 - obsidian blockClassMap.put(50, "net/minecraft/block/BlockTorch"); // 50 - torch blockClassMap.put(51, "net/minecraft/block/BlockFire"); // 51 - fire blockClassMap.put(52, "net/minecraft/block/BlockMobSpawner"); // 52 - mob_spawner blockClassMap.put(53, "net/minecraft/block/BlockStairs"); // 53 - oak_stairs blockClassMap.put(54, "net/minecraft/block/BlockChest"); // 54 - chest blockClassMap.put(55, "net/minecraft/block/BlockRedstoneWire"); // 55 - redstone_wire // 56 - diamond_ore already mapped (BlockOre) // 57 - diamond_block already mapped (BlockCompressed) blockClassMap.put(58, "net/minecraft/block/BlockWorkbench"); // 58 - crafting_table blockClassMap.put(59, "net/minecraft/block/BlockCrops"); // 59 - wheat blockClassMap.put(60, "net/minecraft/block/BlockFarmland"); // 60 - farmland blockClassMap.put(61, "net/minecraft/block/BlockFurnace"); // 61 - furnace // 62 - lit_furnace already mapped (BlockFurnace) blockClassMap.put(63, "net/minecraft/block/BlockStandingSign"); // 63 - standing_sign blockClassMap.put(64, "net/minecraft/block/BlockDoor"); // 64 - wooden_door blockClassMap.put(65, "net/minecraft/block/BlockLadder"); // 65 - ladder blockClassMap.put(66, "net/minecraft/block/BlockRail"); // 66 - rail // 67 - stone_stairs already mapped (BlockStairs) blockClassMap.put(68, "net/minecraft/block/BlockWallSign"); // 68 - wall_sign blockClassMap.put(69, "net/minecraft/block/BlockLever"); // 69 - lever blockClassMap.put(70, "net/minecraft/block/BlockPressurePlate"); // 70 - stone_pressure_plate // 71 - iron_door already mapped (BlockDoor) // 72 - wooden_pressure_plate already mapped (BlockPressurePlate) blockClassMap.put(73, "net/minecraft/block/BlockRedstoneOre"); // 73 - redstone_ore // 74 - lit_redstone_ore already mapped (BlockRedstoneOre) blockClassMap.put(75, "net/minecraft/block/BlockRedstoneTorch"); // 75 - unlit_redstone_torch // 76 - redstone_torch already mapped (BlockRedstoneTorch) blockClassMap.put(77, "net/minecraft/block/BlockButtonStone"); // 77 - stone_button blockClassMap.put(78, "net/minecraft/block/BlockSnow"); // 78 - snow_layer blockClassMap.put(79, "net/minecraft/block/BlockIce"); // 79 - ice blockClassMap.put(80, "net/minecraft/block/BlockSnowBlock"); // 80 - snow blockClassMap.put(81, "net/minecraft/block/BlockCactus"); // 81 - cactus blockClassMap.put(82, "net/minecraft/block/BlockClay"); // 82 - clay blockClassMap.put(83, "net/minecraft/block/BlockReed"); // 83 - reeds blockClassMap.put(84, "net/minecraft/block/BlockJukebox"); // 84 - jukebox blockClassMap.put(85, "net/minecraft/block/BlockFence"); // 85 - fence blockClassMap.put(86, "net/minecraft/block/BlockPumpkin"); // 86 - pumpkin blockClassMap.put(87, "net/minecraft/block/BlockNetherrack"); // 87 - netherrack blockClassMap.put(88, "net/minecraft/block/BlockSoulSand"); // 88 - soul_sand blockClassMap.put(89, "net/minecraft/block/BlockGlowstone"); // 89 - glowstone blockClassMap.put(90, "net/minecraft/block/BlockPortal"); // 90 - portal // 91 - lit_pumpkin already mapped (BlockPumpkin) blockClassMap.put(92, "net/minecraft/block/BlockCake"); // 92 - cake blockClassMap.put(93, "net/minecraft/block/BlockRedstoneRepeater"); // 93 - unpowered_repeater // 94 - powered_repeater already mapped (BlockRedstoneRepeater) blockClassMap.put(95, "net/minecraft/block/BlockStainedGlass"); // 95 - stained_glass blockClassMap.put(96, "net/minecraft/block/BlockTrapDoor"); // 96 - trapdoor blockClassMap.put(97, "net/minecraft/block/BlockSilverfish"); // 97 - monster_egg blockClassMap.put(98, "net/minecraft/block/BlockStoneBrick"); // 98 - stonebrick blockClassMap.put(99, "net/minecraft/block/BlockHugeMushroom"); // 99 - brown_mushroom_block // 100 - red_mushroom_block already mapped (BlockHugeMushroom) blockClassMap.put(101, "net/minecraft/block/BlockPane"); // 101 - iron_bars // 102 - glass_pane already mapped (BlockPane) blockClassMap.put(103, "net/minecraft/block/BlockMelon"); // 103 - melon_block blockClassMap.put(104, "net/minecraft/block/BlockStem"); // 104 - pumpkin_stem // 105 - melon_stem already mapped (BlockStem) blockClassMap.put(106, "net/minecraft/block/BlockVine"); // 106 - vine blockClassMap.put(107, "net/minecraft/block/BlockFenceGate"); // 107 - fence_gate // 108 - brick_stairs already mapped (BlockStairs) // 109 - stone_brick_stairs already mapped (BlockStairs) blockClassMap.put(110, "net/minecraft/block/BlockMycelium"); // 110 - mycelium blockClassMap.put(111, "net/minecraft/block/BlockLilyPad"); // 111 - waterlily blockClassMap.put(112, "net/minecraft/block/BlockNetherBrick"); // 112 - nether_brick // 113 - nether_brick_fence already mapped (BlockFence) // 114 - nether_brick_stairs already mapped (BlockStairs) blockClassMap.put(115, "net/minecraft/block/BlockNetherWart"); // 115 - nether_wart blockClassMap.put(116, "net/minecraft/block/BlockEnchantmentTable"); // 116 - enchanting_table blockClassMap.put(117, "net/minecraft/block/BlockBrewingStand"); // 117 - brewing_stand blockClassMap.put(118, "net/minecraft/block/BlockCauldron"); // 118 - cauldron blockClassMap.put(119, "net/minecraft/block/BlockEndPortal"); // 119 - end_portal blockClassMap.put(120, "net/minecraft/block/BlockEndPortalFrame"); // 120 - end_portal_frame // 121 - end_stone already mapped (Block) blockClassMap.put(122, "net/minecraft/block/BlockDragonEgg"); // 122 - dragon_egg blockClassMap.put(123, "net/minecraft/block/BlockRedstoneLight"); // 123 - redstone_lamp // 124 - lit_redstone_lamp already mapped (BlockRedstoneLight) blockClassMap.put(125, "net/minecraft/block/BlockDoubleWoodSlab"); // 125 - double_wooden_slab blockClassMap.put(126, "net/minecraft/block/BlockHalfWoodSlab"); // 126 - wooden_slab blockClassMap.put(127, "net/minecraft/block/BlockCocoa"); // 127 - cocoa // 128 - sandstone_stairs already mapped (BlockStairs) // 129 - emerald_ore already mapped (BlockOre) blockClassMap.put(130, "net/minecraft/block/BlockEnderChest"); // 130 - ender_chest blockClassMap.put(131, "net/minecraft/block/BlockTripWireHook"); // 131 - tripwire_hook blockClassMap.put(132, "net/minecraft/block/BlockTripWire"); // 132 - tripwire // 133 - emerald_block already mapped (BlockCompressed) // 134 - spruce_stairs already mapped (BlockStairs) // 135 - birch_stairs already mapped (BlockStairs) // 136 - jungle_stairs already mapped (BlockStairs) blockClassMap.put(137, "net/minecraft/block/BlockCommandBlock"); // 137 - command_block blockClassMap.put(138, "net/minecraft/block/BlockBeacon"); // 138 - beacon blockClassMap.put(139, "net/minecraft/block/BlockWall"); // 139 - cobblestone_wall blockClassMap.put(140, "net/minecraft/block/BlockFlowerPot"); // 140 - flower_pot blockClassMap.put(141, "net/minecraft/block/BlockCarrot"); // 141 - carrots blockClassMap.put(142, "net/minecraft/block/BlockPotato"); // 142 - potatoes blockClassMap.put(143, "net/minecraft/block/BlockButtonWood"); // 143 - wooden_button blockClassMap.put(144, "net/minecraft/block/BlockSkull"); // 144 - skull blockClassMap.put(145, "net/minecraft/block/BlockAnvil"); // 145 - anvil // 146 - trapped_chest already mapped (BlockChest) blockClassMap.put(147, "net/minecraft/block/BlockPressurePlateWeighted"); // 147 - light_weighted_pressure_plate // 148 - heavy_weighted_pressure_plate already mapped (BlockPressurePlateWeighted) blockClassMap.put(149, "net/minecraft/block/BlockRedstoneComparator"); // 149 - unpowered_comparator // 150 - powered_comparator already mapped (BlockRedstoneComparator) blockClassMap.put(151, "net/minecraft/block/BlockDaylightDetector"); // 151 - daylight_detector blockClassMap.put(152, "net/minecraft/block/BlockCompressedPowered"); // 152 - redstone_block // 153 - quartz_ore already mapped (BlockOre) blockClassMap.put(154, "net/minecraft/block/BlockHopper"); // 154 - hopper blockClassMap.put(155, "net/minecraft/block/BlockQuartz"); // 155 - quartz_block // 156 - quartz_stairs already mapped (BlockStairs) // 157 - activator_rail already mapped (BlockRailPowered) blockClassMap.put(158, "net/minecraft/block/BlockDropper"); // 158 - dropper // 159 - stained_hardened_clay already mapped (BlockColored) blockClassMap.put(160, "net/minecraft/block/BlockStainedGlassPane"); // 160 - stained_glass_pane blockClassMap.put(161, "net/minecraft/block/BlockNewLeaf"); // 161 - leaves2 blockClassMap.put(162, "net/minecraft/block/BlockNewLog"); // 162 - log2 // 163 - acacia_stairs already mapped (BlockStairs) // 164 - dark_oak_stairs already mapped (BlockStairs) blockClassMap.put(165, "net/minecraft/block/BlockSlime"); // 165 - slime blockClassMap.put(166, "net/minecraft/block/BlockBarrier"); // 166 - barrier // 167 - iron_trapdoor already mapped (BlockTrapDoor) blockClassMap.put(168, "net/minecraft/block/BlockPrismarine"); // 168 - prismarine blockClassMap.put(169, "net/minecraft/block/BlockSeaLantern"); // 169 - sea_lantern blockClassMap.put(170, "net/minecraft/block/BlockHay"); // 170 - hay_block blockClassMap.put(171, "net/minecraft/block/BlockCarpet"); // 171 - carpet blockClassMap.put(172, "net/minecraft/block/BlockHardenedClay"); // 172 - hardened_clay // 173 - coal_block already mapped (Block) blockClassMap.put(174, "net/minecraft/block/BlockPackedIce"); // 174 - packed_ice blockClassMap.put(175, "net/minecraft/block/BlockDoublePlant"); // 175 - double_plant blockClassMap.put(176, "net/minecraft/block/BlockBanner$BlockBannerStanding"); // 176 - standing_banner blockClassMap.put(177, "net/minecraft/block/BlockBanner$BlockBannerHanging"); // 177 - wall_banner // 178 - daylight_detector_inverted already mapped (BlockDaylightDetector) blockClassMap.put(179, "net/minecraft/block/BlockRedSandstone"); // 179 - red_sandstone // 180 - red_sandstone_stairs already mapped (BlockStairs) blockClassMap.put(181, "net/minecraft/block/BlockDoubleStoneSlabNew"); // 181 - double_stone_slab2 blockClassMap.put(182, "net/minecraft/block/BlockHalfStoneSlabNew"); // 182 - stone_slab2 // 183 - spruce_fence_gate already mapped (BlockFenceGate) // 184 - birch_fence_gate already mapped (BlockFenceGate) // 185 - jungle_fence_gate already mapped (BlockFenceGate) // 186 - dark_oak_fence_gate already mapped (BlockFenceGate) // 187 - acacia_fence_gate already mapped (BlockFenceGate) // 188 - spruce_fence already mapped (BlockFence) // 189 - birch_fence already mapped (BlockFence) // 190 - jungle_fence already mapped (BlockFence) // 191 - dark_oak_fence already mapped (BlockFence) // 192 - acacia_fence already mapped (BlockFence) // 193 - spruce_door already mapped (BlockDoor) // 194 - birch_door already mapped (BlockDoor) // 195 - jungle_door already mapped (BlockDoor) // 196 - acacia_door already mapped (BlockDoor) // 197 - dark_oak_door already mapped (BlockDoor) MethodCallVisitor registerBlocksMethodVisitor = new MethodCallVisitor(registerBlocks, false); for (MethodCall call : registerBlocksMethodVisitor) { MethodInsnNode mi = call.methodNode; if ((mi.name.equals(registerBlock1.name) && mi.desc.equals(registerBlock1.desc)) || (mi.name.equals(registerBlock2.name) && mi.desc.equals(registerBlock2.desc))) { int blockId = (Integer)call.args[0]; String blockClass = (String)call.args[2]; if (blockClassMap.containsKey(blockId)) { addClassMapping(blockClassMap.get(blockId), blockClass); if (blockClassMap.get(blockId).equals("net/minecraft/block/BlockWorkbench")) { ClassNode workbench = getClassNode(blockClass); if (workbench != null) { List<TypeInsnNode> typeNodes = getAllInsnNodesOfType(workbench, TypeInsnNode.class); for (TypeInsnNode tn : typeNodes) { if (tn.desc.startsWith(blockClass + "$") && searchConstantPoolForStrings(tn.desc, "minecraft:crafting_table")) { addClassMapping("net/minecraft/block/BlockWorkbench$InterfaceCraftingTable", tn.desc); break; } } } } } } } return true; } public static int argCount(String methodDesc) { int count = 0; boolean complexType = false; for (int i = 1; i < methodDesc.length() && methodDesc.charAt(i) != ')'; i++) { if (complexType) { if (methodDesc.charAt(i) == ';') { complexType = false; count++; } continue; } if (methodDesc.charAt(i) == '[' || methodDesc.charAt(i) == 'L') complexType = true; else count++; } return count; } @Mapping(providesFields={ "net/minecraft/block/BlockTNT EXPLODE Lnet/minecraft/block/properties/PropertyBool;" }, providesMethods={ "net/minecraft/block/Block onBlockAdded (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;Lnet/minecraft/block/state/IBlockState;)V", "net/minecraft/block/Block onBlockDestroyedByPlayer (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;Lnet/minecraft/block/state/IBlockState;)V", "net/minecraft/block/properties/PropertyBool create (Ljava/lang/String;)Lnet/minecraft/block/properties/PropertyBool;", "net/minecraft/block/Block onEntityCollidedWithBlock (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;Lnet/minecraft/block/state/IBlockState;Lnet/minecraft/entity/Entity;)V", "net/minecraft/world/World setBlockToAir (Lnet/minecraft/util/BlockPos;)Z", "net/minecraft/block/BlockTNT explode (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;Lnet/minecraft/block/state/IBlockState;Lnet/minecraft/entity/EntityLivingBase;)V", "net/minecraft/world/World spawnEntityInWorld (Lnet/minecraft/entity/Entity;)Z", //"net/minecraft/world/World playSoundAtEntity (Lnet/minecraft/entity/Entity;Lnet/minecraft/util/Sound;FF)V" }, depends={ "net/minecraft/block/Block", "net/minecraft/block/BlockTNT", "net/minecraft/world/World", "net/minecraft/util/BlockPos", "net/minecraft/block/state/IBlockState", "net/minecraft/block/properties/PropertyBool", "net/minecraft/entity/Entity", "net/minecraft/entity/EntityLivingBase", "net/minecraft/util/Sound" }) public boolean processBlockTNTClass() { ClassNode block = getClassNodeFromMapping("net/minecraft/block/Block"); ClassNode tnt = getClassNodeFromMapping("net/minecraft/block/BlockTNT"); ClassNode world = getClassNodeFromMapping("net/minecraft/world/World"); ClassNode blockPos = getClassNodeFromMapping("net/minecraft/util/BlockPos"); ClassNode iBlockState = getClassNodeFromMapping("net/minecraft/block/state/IBlockState"); ClassNode propertyBool = getClassNodeFromMapping("net/minecraft/block/properties/PropertyBool"); ClassNode entity = getClassNodeFromMapping("net/minecraft/entity/Entity"); ClassNode entityLivingBase = getClassNodeFromMapping("net/minecraft/entity/EntityLivingBase"); ClassNode sound = getClassNodeFromMapping("net/minecraft/util/Sound"); if (!MeddleUtil.notNull(block, tnt, world, blockPos, iBlockState, propertyBool, entity, entityLivingBase, sound)) return false; MethodNode clinit = getMethodNode(tnt, "--- <clinit> ()V"); if (clinit != null) { List<MethodInsnNode> nodes = getAllInsnNodesOfType(clinit, MethodInsnNode.class); for (Iterator<MethodInsnNode> it = nodes.iterator(); it.hasNext();) { MethodInsnNode mn = it.next(); if (mn.owner.equals(propertyBool.name) && mn.desc.equals("(Ljava/lang/String;)L" + propertyBool.name + ";")) continue; it.remove(); } if (nodes.size() == 1) { addMethodMapping("net/minecraft/block/properties/PropertyBool create (Ljava/lang/String;)Lnet/minecraft/block/properties/PropertyBool;", propertyBool.name + " " + nodes.get(0).name + " " + nodes.get(0).desc); } } List<FieldNode> fields = getMatchingFields(tnt, null, "L" + propertyBool.name + ";"); if (fields.size() == 1) { addFieldMapping("net/minecraft/block/BlockTNT EXPLODE Lnet/minecraft/block/properties/PropertyBool;", tnt.name + " " + fields.get(0).name + " " + fields.get(0).desc); } // public void onBlockAdded(World worldIn, BlockPos pos, IBlockState state) // public void onBlockDestroyedByPlayer(World worldIn, BlockPos pos, IBlockState state) List<MethodNode> methods = getMatchingMethods(tnt, null, assembleDescriptor("(", world, blockPos, iBlockState, ")V")); if (methods.size() == 2) { List<MethodNode> onDestroyed = new ArrayList<>(); for (Iterator<MethodNode> it = methods.iterator(); it.hasNext();) { MethodNode method = it.next(); // Match instructions for onBlockDestroyedByPlayer if (matchOpcodeSequence(method.instructions.getFirst(), Opcodes.ALOAD, Opcodes.ALOAD, Opcodes.ALOAD, Opcodes.ALOAD, Opcodes.ACONST_NULL, Opcodes.INVOKEVIRTUAL, Opcodes.RETURN)) { onDestroyed.add(method); it.remove(); } } if (methods.size() == 1) { addMethodMapping("net/minecraft/block/Block onBlockAdded (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;Lnet/minecraft/block/state/IBlockState;)V", block.name + " " + methods.get(0).name + " " + methods.get(0).desc); } if (onDestroyed.size() == 1) { addMethodMapping("net/minecraft/block/Block onBlockDestroyedByPlayer (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;Lnet/minecraft/block/state/IBlockState;)V", block.name + " " + onDestroyed.get(0).name + " " + onDestroyed.get(0).desc); } } // public void onEntityCollidedWithBlock(World worldIn, BlockPos pos, IBlockState state, Entity entityIn) methods = getMatchingMethods(tnt, null, assembleDescriptor("(", world, blockPos, iBlockState, entity, ")V")); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/Block onEntityCollidedWithBlock (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;Lnet/minecraft/block/state/IBlockState;Lnet/minecraft/entity/Entity;)V", block.name + " " + methods.get(0).name + " " + methods.get(0).desc); List<MethodInsnNode> nodes = getAllInsnNodesOfType(methods.get(0), MethodInsnNode.class); for (Iterator<MethodInsnNode> it = nodes.iterator(); it.hasNext();) { MethodInsnNode mn = it.next(); if (mn.owner.equals(world.name) && mn.desc.equals("(L" + blockPos.name + ";)Z")) continue; it.remove(); } if (nodes.size() == 1) { addMethodMapping("net/minecraft/world/World setBlockToAir (Lnet/minecraft/util/BlockPos;)Z", world.name + " " + nodes.get(0).name + " " + nodes.get(0).desc); } } // public void explode(World worldIn, BlockPos pos, IBlockState state, EntityLivingBase igniter) methods = getMatchingMethods(tnt, null, assembleDescriptor("(", world, blockPos, iBlockState, entityLivingBase, ")V")); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/BlockTNT explode (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;Lnet/minecraft/block/state/IBlockState;Lnet/minecraft/entity/EntityLivingBase;)V", tnt.name + " " + methods.get(0).name + " " + methods.get(0).desc); List<MethodInsnNode> nodes = getAllInsnNodesOfType(methods.get(0), MethodInsnNode.class); List<MethodInsnNode> spawnEntityInWorld = new ArrayList<>(); //List<MethodInsnNode> playSoundAtEntity = new ArrayList<>(); for (MethodInsnNode mn : nodes) { if (mn.owner.equals(world.name)) { if (mn.desc.equals("(L" + entity.name + ";)Z")) spawnEntityInWorld.add(mn); //else if (mn.desc.equals("(L" + entity.name + ";L" + sound.name + ";FF)V")) playSoundAtEntity.add(mn); } } if (spawnEntityInWorld.size() == 1) { addMethodMapping("net/minecraft/world/World spawnEntityInWorld (Lnet/minecraft/entity/Entity;)Z", world.name + " " + spawnEntityInWorld.get(0).name + " " + spawnEntityInWorld.get(0).desc); } /* * 15w49a changed to playSoundEffect, so remove this * if (playSoundAtEntity.size() == 1) { addMethodMapping("net/minecraft/world/World playSoundAtEntity (Lnet/minecraft/entity/Entity;Lnet/minecraft/util/Sound;FF)V", world.name + " " + playSoundAtEntity.get(0).name + " " + playSoundAtEntity.get(0).desc); }*/ } return true; } @Mapping(provides={ "net/minecraft/block/IGrowable" }, providesMethods={ }, depends={ "net/minecraft/block/Block", "net/minecraft/block/BlockGrass", "net/minecraft/block/state/IBlockState", "net/minecraft/util/BlockPos" }) public boolean processBlockGrassClass() { ClassNode block = getClassNodeFromMapping("net/minecraft/block/Block"); ClassNode grass = getClassNodeFromMapping("net/minecraft/block/BlockGrass"); ClassNode iBlockState = getClassNodeFromMapping("net/minecraft/block/state/IBlockState"); ClassNode blockPos = getClassNodeFromMapping("net/minecraft/util/BlockPos"); if (!MeddleUtil.notNull(block, grass, iBlockState, blockPos)) return false; ClassNode iGrowable = null; if (grass.interfaces.size() == 1) { iGrowable = getClassNode(grass.interfaces.get(0)); if (iGrowable != null && iGrowable.methods.size() == 3) { addClassMapping("net/minecraft/block/IGrowable", iGrowable.name); } else iGrowable = null; } return true; } @Mapping(providesMethods={ "net/minecraft/block/IGrowable canGrow (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;Lnet/minecraft/block/state/IBlockState;Z)Z", "net/minecraft/block/IGrowable canUseBonemeal (Lnet/minecraft/world/World;Ljava/util/Random;Lnet/minecraft/util/BlockPos;Lnet/minecraft/block/state/IBlockState;)Z", "net/minecraft/block/IGrowable grow (Lnet/minecraft/world/World;Ljava/util/Random;Lnet/minecraft/util/BlockPos;Lnet/minecraft/block/state/IBlockState;)V" }, depends={ "net/minecraft/block/IGrowable", "net/minecraft/block/Block", "net/minecraft/block/BlockGrass", "net/minecraft/block/state/IBlockState", "net/minecraft/util/BlockPos", "net/minecraft/world/World" }) public boolean processIGrowableClass() { ClassNode iGrowable = getClassNodeFromMapping("net/minecraft/block/IGrowable"); ClassNode block = getClassNodeFromMapping("net/minecraft/block/Block"); ClassNode grass = getClassNodeFromMapping("net/minecraft/block/BlockGrass"); ClassNode iBlockState = getClassNodeFromMapping("net/minecraft/block/state/IBlockState"); ClassNode blockPos = getClassNodeFromMapping("net/minecraft/util/BlockPos"); ClassNode world = getClassNodeFromMapping("net/minecraft/world/World"); if (!MeddleUtil.notNull(iGrowable, block, grass, iBlockState, blockPos, world)) return false; // boolean canGrow(World worldIn, BlockPos pos, IBlockState state, boolean isClient); List<MethodNode> methods = getMatchingMethods(iGrowable, null, assembleDescriptor("(", world, blockPos, iBlockState, "Z)Z")); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/IGrowable canGrow (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;Lnet/minecraft/block/state/IBlockState;Z)Z", iGrowable.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // boolean canUseBonemeal(World worldIn, Random rand, BlockPos pos, IBlockState state); methods = getMatchingMethods(iGrowable, null, assembleDescriptor("(", world, "Ljava/util/Random;", blockPos, iBlockState, ")Z")); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/IGrowable canUseBonemeal (Lnet/minecraft/world/World;Ljava/util/Random;Lnet/minecraft/util/BlockPos;Lnet/minecraft/block/state/IBlockState;)Z", iGrowable.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // void grow(World worldIn, Random rand, BlockPos pos, IBlockState state); methods = getMatchingMethods(iGrowable, null, assembleDescriptor("(", world, "Ljava/util/Random;", blockPos, iBlockState, ")V")); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/IGrowable grow (Lnet/minecraft/world/World;Ljava/util/Random;Lnet/minecraft/util/BlockPos;Lnet/minecraft/block/state/IBlockState;)V", iGrowable.name + " " + methods.get(0).name + " " + methods.get(0).desc); } return true; } @Mapping(provides="net/minecraft/block/EnumRenderType", providesFields={ "net/minecraft/block/material/Material air Lnet/minecraft/block/material/Material;" }, providesMethods={ "net/minecraft/block/Block getCollisionBoundingBox (Lnet/minecraft/block/state/IBlockState;Lnet/minecraft/world/IBlockAccess;Lnet/minecraft/util/BlockPos;)Lnet/minecraft/util/AxisAlignedBB;", //"net/minecraft/block/Block isOpaqueCube (Lnet/minecraft/block/state/IBlockState;)Z", "net/minecraft/block/Block canCollideCheck (Lnet/minecraft/block/state/IBlockState;Z)Z", "net/minecraft/block/Block isReplaceable (Lnet/minecraft/world/IBlockAccess;Lnet/minecraft/util/BlockPos;)Z", "net/minecraft/block/Block getRenderType ()Lnet/minecraft/block/EnumRenderType;" }, depends={ "net/minecraft/block/Block", "net/minecraft/block/BlockAir", "net/minecraft/world/World", "net/minecraft/util/BlockPos", "net/minecraft/block/state/IBlockState", "net/minecraft/block/material/Material", "net/minecraft/util/AxisAlignedBB", "net/minecraft/world/IBlockAccess" }) public boolean processBlockAirClass() { ClassNode block = getClassNodeFromMapping("net/minecraft/block/Block"); ClassNode blockAir = getClassNodeFromMapping("net/minecraft/block/BlockAir"); ClassNode world = getClassNodeFromMapping("net/minecraft/world/World"); ClassNode blockPos = getClassNodeFromMapping("net/minecraft/util/BlockPos"); ClassNode iBlockState = getClassNodeFromMapping("net/minecraft/block/state/IBlockState"); ClassNode material = getClassNodeFromMapping("net/minecraft/block/material/Material"); ClassNode aabb = getClassNodeFromMapping("net/minecraft/util/AxisAlignedBB"); ClassNode iBlockAccess = getClassNodeFromMapping("net/minecraft/world/IBlockAccess"); if (!MeddleUtil.notNull(block, blockAir, world, blockPos, iBlockState, material, aabb, iBlockAccess)) return false; List<FieldInsnNode> fieldNodes = getAllInsnNodesOfType(blockAir, FieldInsnNode.class); for (Iterator<FieldInsnNode> it = fieldNodes.iterator(); it.hasNext();) { if (!it.next().desc.equals("L" + material.name + ";")) it.remove(); } if (fieldNodes.size() == 1) { addFieldMapping("net/minecraft/block/material/Material air Lnet/minecraft/block/material/Material;", material.name + " " + fieldNodes.get(0).name + " " + fieldNodes.get(0).desc); } // public AxisAlignedBB getCollisionBoundingBox(IBlockState state, World worldIn, BlockPos pos) List<MethodNode> methods = getMatchingMethods(blockAir, null, assembleDescriptor("(", iBlockState, iBlockAccess, blockPos, ")", aabb)); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/Block getCollisionBoundingBox (Lnet/minecraft/block/state/IBlockState;Lnet/minecraft/world/IBlockAccess;Lnet/minecraft/util/BlockPos;)Lnet/minecraft/util/AxisAlignedBB;", block.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public boolean isOpaqueCube(IBlockState state) /*methods = getMatchingMethods(blockAir, null, assembleDescriptor("(", iBlockState, ")Z")); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/Block isOpaqueCube (Lnet/minecraft/block/state/IBlockState;)Z", block.name + " " + methods.get(0).name + " " + methods.get(0).desc); }*/ // public boolean canCollideCheck(IBlockState state, boolean hitIfLiquid) methods = getMatchingMethods(blockAir, null, assembleDescriptor("(", iBlockState, "Z)Z")); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/Block canCollideCheck (Lnet/minecraft/block/state/IBlockState;Z)Z", block.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public boolean isReplaceable(IBlockAccess worldIn, BlockPos pos) methods = getMatchingMethods(blockAir, null, assembleDescriptor("(", iBlockAccess, blockPos, ")Z")); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/Block isReplaceable (Lnet/minecraft/world/IBlockAccess;Lnet/minecraft/util/BlockPos;)Z", block.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public EnumRenderType getRenderType() methods.clear(); for (MethodNode method : blockAir.methods) { if (method.desc.startsWith("(L" + iBlockState.name + ";)L")) methods.add(method); } if (methods.size() == 1) { String renderType = Type.getMethodType(methods.get(0).desc).getReturnType().getClassName(); if (searchConstantPoolForStrings(renderType, "INVISIBLE", "LIQUID")) { addClassMapping("net/minecraft/block/EnumRenderType", renderType); addMethodMapping("net/minecraft/block/Block getRenderType ()Lnet/minecraft/block/EnumRenderType;", block.name + " " + methods.get(0).name + " " + methods.get(0).desc); } } return true; } @Mapping(providesFields={ "net/minecraft/block/EnumRenderType INVISIBLE Lnet/minecraft/block/EnumRenderType;", "net/minecraft/block/EnumRenderType LIQUID Lnet/minecraft/block/EnumRenderType;", "net/minecraft/block/EnumRenderType ENTITYBLOCK_ANIMATED Lnet/minecraft/block/EnumRenderType;", "net/minecraft/block/EnumRenderType MODEL Lnet/minecraft/block/EnumRenderType;" }, depends="net/minecraft/block/EnumRenderType") public boolean processEnumRenderTypeClass() { ClassNode renderType = getClassNodeFromMapping("net/minecraft/block/EnumRenderType"); if (renderType == null) return false; Map<String, FieldInsnNode> map = new HashMap<>(); MethodNode clinit = getMethodNode(renderType, "--- <clinit> ()V"); if (clinit == null) return false; // Extract LDC strings and the PUTSTATICs that follow them, into a map String lastString = null; for (AbstractInsnNode insn = clinit.instructions.getFirst(); insn != null; insn = insn.getNext()) { String string = getLdcString(insn); if (string != null) { lastString = string; continue; } if (insn.getOpcode() != Opcodes.PUTSTATIC || lastString == null) continue; FieldInsnNode fn = (FieldInsnNode)insn; if (fn.owner.equals(renderType.name) && fn.desc.equals("L" + renderType.name + ";")) { if (lastString.equals("INVISIBLE")) { addFieldMapping("net/minecraft/block/EnumRenderType INVISIBLE Lnet/minecraft/block/EnumRenderType;", renderType.name + " " + fn.name + " " + fn.desc); } else if (lastString.equals("LIQUID")) { addFieldMapping("net/minecraft/block/EnumRenderType LIQUID Lnet/minecraft/block/EnumRenderType;", renderType.name + " " + fn.name + " " + fn.desc); } else if (lastString.equals("ENTITYBLOCK_ANIMATED")) { addFieldMapping("net/minecraft/block/EnumRenderType ENTITYBLOCK_ANIMATED Lnet/minecraft/block/EnumRenderType;", renderType.name + " " + fn.name + " " + fn.desc); } else if (lastString.equals("MODEL")) { addFieldMapping("net/minecraft/block/EnumRenderType MODEL Lnet/minecraft/block/EnumRenderType;", renderType.name + " " + fn.name + " " + fn.desc); } lastString = null; } } return true; } @Mapping(provides={ "net/minecraft/stats/StatList", "net/minecraft/util/ChatComponentTranslation", "net/minecraft/inventory/ContainerWorkbench" }, depends={ "net/minecraft/block/BlockWorkbench", "net/minecraft/block/BlockWorkbench$InterfaceCraftingTable", "net/minecraft/inventory/Container" }) public boolean processBlockWorkbenchClass() { ClassNode workbench = getClassNodeFromMapping("net/minecraft/block/BlockWorkbench"); ClassNode workbenchIface = getClassNodeFromMapping("net/minecraft/block/BlockWorkbench$InterfaceCraftingTable"); ClassNode container = getClassNodeFromMapping("net/minecraft/inventory/Container"); if (!MeddleUtil.notNull(workbench, workbenchIface, container)) return false; List<FieldInsnNode> fieldNodes = getAllInsnNodesOfType(workbench, FieldInsnNode.class); for (FieldInsnNode fn : fieldNodes) { if (fn.getOpcode() != Opcodes.GETSTATIC) continue; if (searchConstantPoolForStrings(fn.owner, "stat.leaveGame", "stat.playerKills")) { addClassMapping("net/minecraft/stats/StatList", fn.owner); } } boolean foundTranslate = false; List<TypeInsnNode> typeNodes = getAllInsnNodesOfType(workbenchIface, TypeInsnNode.class); List<TypeInsnNode> containers = new ArrayList<>(); for (TypeInsnNode tn : typeNodes) { if (!foundTranslate && searchConstantPoolForStrings(tn.desc, "TranslatableComponent{key=\'")) { foundTranslate = true; addClassMapping("net/minecraft/util/ChatComponentTranslation", tn.desc); } else { ClassNode cn = getClassNode(tn.desc); if (cn != null && cn.superName != null && cn.superName.equals(container.name)) containers.add(tn); } } if (containers.size() == 1) { addClassMapping("net/minecraft/inventory/ContainerWorkbench", containers.get(0).desc); } return true; } @Mapping(provides={ "net/minecraft/block/BlockLog", "net/minecraft/block/BlockRotatedPillar" }, depends={ "net/minecraft/block/BlockOldLog", "net/minecraft/block/Block" }) public boolean processBlockOldLog() { ClassNode oldLog = getClassNodeFromMapping("net/minecraft/block/BlockOldLog"); ClassNode block = getClassNodeFromMapping("net/minecraft/block/Block"); if (oldLog == null || block == null) return false; if (searchConstantPoolForStrings(oldLog.superName, "axis")) { ClassNode blockLog = getClassNode(oldLog.superName); if (blockLog != null && searchConstantPoolForStrings(blockLog.superName, "axis")) { ClassNode rotatedPillar = getClassNode(blockLog.superName); if (rotatedPillar != null && rotatedPillar.superName.equals(block.name)) { addClassMapping("net/minecraft/block/BlockLog", blockLog.name); addClassMapping("net/minecraft/block/BlockRotatedPillar", rotatedPillar.name); return true; } } } return false; } private boolean verifyBlockSoundTypeClass(String className) { ClassNode soundType = getClassNode(className); ClassNode sound = getClassNodeFromMapping("net/minecraft/util/Sound"); if (soundType == null || sound == null) return false; List<MethodNode> methods = getMatchingMethods(soundType, "<init>", assembleDescriptor("(FF", sound, sound, sound, sound, sound, ")V")); if (methods.size() == 1) return true; return false; } @Mapping(provides={ "net/minecraft/block/BlockSoundType" }, providesFields={ "net/minecraft/block/material/Material wood Lnet/minecraft/block/material/Material;", "net/minecraft/block/Block soundTypeWood Lnet/minecraft/block/Block$SoundType;", "net/minecraft/block/material/Material leaves Lnet/minecraft/block/material/Material;" }, providesMethods={ "net/minecraft/block/Block setHardness (F)Lnet/minecraft/block/Block;", "net/minecraft/block/Block setStepSound (Lnet/minecraft/block/Block$SoundType;)Lnet/minecraft/block/Block;", "net/minecraft/block/Block breakBlock (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;Lnet/minecraft/block/state/IBlockState;)V", "net/minecraft/world/World isAreaLoaded (Lnet/minecraft/util/BlockPos;Lnet/minecraft/util/BlockPos;)Z", "net/minecraft/util/BlockPos add (III)Lnet/minecraft/util/BlockPos;", "net/minecraft/util/BlockPos getAllInBox (Lnet/minecraft/util/BlockPos;Lnet/minecraft/util/BlockPos;)Ljava/lang/Iterable;" }, depends={ "net/minecraft/block/BlockLog", "net/minecraft/block/Block", "net/minecraft/block/material/Material", "net/minecraft/creativetab/CreativeTabs", "net/minecraft/world/World", "net/minecraft/util/BlockPos", "net/minecraft/block/state/IBlockState", "net/minecraft/util/Sound" }) public boolean processBlockLog() { ClassNode blockLog = getClassNodeFromMapping("net/minecraft/block/BlockLog"); ClassNode block = getClassNodeFromMapping("net/minecraft/block/Block"); ClassNode material = getClassNodeFromMapping("net/minecraft/block/material/Material"); ClassNode creativeTabs = getClassNodeFromMapping("net/minecraft/creativetab/CreativeTabs"); ClassNode world = getClassNodeFromMapping("net/minecraft/world/World"); ClassNode blockPos = getClassNodeFromMapping("net/minecraft/util/BlockPos"); ClassNode iBlockState = getClassNodeFromMapping("net/minecraft/block/state/IBlockState"); if (!MeddleUtil.notNull(blockLog, block, material, creativeTabs, world, blockPos, iBlockState)) return false; List<MethodNode> methods = getMatchingMethods(blockLog, "<init>", "()V"); if (methods.size() == 1) { List<FieldInsnNode> fieldNodes = getAllInsnNodesOfType(methods.get(0).instructions.getFirst(), FieldInsnNode.class); List<MethodInsnNode> methodNodes = getAllInsnNodesOfType(methods.get(0).instructions.getFirst(), MethodInsnNode.class); String wood_name = null; int materialCount = 0; String soundType_name = null; String sound_name = null; int soundCount = 0; for (FieldInsnNode fn : fieldNodes) { if (!fn.desc.startsWith("L")) continue; String className = Type.getType(fn.desc).getClassName(); if (className.equals(creativeTabs.name)) continue; else if (className.equals(material.name)) { wood_name = fn.name; materialCount++; } else if (verifyBlockSoundTypeClass(className)) { if (soundType_name == null) { soundType_name = className; addClassMapping("net/minecraft/block/BlockSoundType", className); } sound_name = fn.name; soundCount++; } } if (materialCount == 1) { addFieldMapping("net/minecraft/block/material/Material wood Lnet/minecraft/block/material/Material;", material.name + " " + wood_name + " L" + material.name + ";"); } if (soundCount == 1) { addFieldMapping("net/minecraft/block/Block soundTypeWood Lnet/minecraft/block/Block$SoundType;", block.name + " " + sound_name + " L" + soundType_name + ";"); } String setHardness_name = null; int setHardness_count = 0; String setStepSound_name = null; int setStepSound_count = 0; for (MethodInsnNode mn : methodNodes) { if (!mn.owner.equals(blockLog.name)) continue; if (mn.desc.equals("(F)L" + block.name + ";")) { setHardness_name = mn.name; setHardness_count++; } else if (soundType_name != null && mn.desc.equals("(L" + soundType_name + ";)L" + block.name + ";")) { setStepSound_name = mn.name; setStepSound_count++; } } if (setHardness_count == 1) { addMethodMapping("net/minecraft/block/Block setHardness (F)Lnet/minecraft/block/Block;", block.name + " " + setHardness_name + " (F)L" + block.name + ";"); } if (setStepSound_count == 1) { addMethodMapping("net/minecraft/block/Block setStepSound (Lnet/minecraft/block/Block$SoundType;)Lnet/minecraft/block/Block;", block.name + " " + setStepSound_name + " (L" + soundType_name + ";)L" + block.name + ";"); } } // public void breakBlock(World worldIn, BlockPos pos, IBlockState state) methods = getMatchingMethods(blockLog, null, assembleDescriptor("(", world, blockPos, iBlockState, ")V")); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/Block breakBlock (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;Lnet/minecraft/block/state/IBlockState;)V", block.name + " " + methods.get(0).name + " " + methods.get(0).desc); // World: public boolean isAreaLoaded(BlockPos param0, BlockPos param1) List<MethodInsnNode> methodNodes = getAllInsnNodesOfType(methods.get(0).instructions.getFirst(), MethodInsnNode.class); for (Iterator<MethodInsnNode> it = methodNodes.iterator(); it.hasNext();) { MethodInsnNode mn = it.next(); if (!(mn.owner.equals(world.name) && mn.desc.equals("(L" + blockPos.name + ";L" + blockPos.name + ";)Z"))) it.remove(); } if (methodNodes.size() == 1) { addMethodMapping("net/minecraft/world/World isAreaLoaded (Lnet/minecraft/util/BlockPos;Lnet/minecraft/util/BlockPos;)Z", world.name + " " + methodNodes.get(0).name + " " + methodNodes.get(0).desc); } // Blockpos: public BlockPos add(int param0, int param1, int param2) methodNodes = getAllInsnNodesOfType(methods.get(0).instructions.getFirst(), MethodInsnNode.class); for (Iterator<MethodInsnNode> it = methodNodes.iterator(); it.hasNext();) { MethodInsnNode mn = it.next(); if (!(mn.owner.equals(blockPos.name) && mn.desc.equals("(III)L" + blockPos.name + ";"))) it.remove(); } if (methodNodes.size() > 0) { String add_name = methodNodes.get(0).name; int add_matches = 0; for (MethodInsnNode mn : methodNodes) { if (mn.name.equals(add_name)) add_matches++; } if (methodNodes.size() == add_matches) { addMethodMapping("net/minecraft/util/BlockPos add (III)Lnet/minecraft/util/BlockPos;", blockPos.name + " " + methodNodes.get(0).name + " " + methodNodes.get(0).desc); } } // BlockPos: public static Iterable getAllInBox(BlockPos from, BlockPos to) methodNodes = getAllInsnNodesOfType(methods.get(0).instructions.getFirst(), MethodInsnNode.class); for (Iterator<MethodInsnNode> it = methodNodes.iterator(); it.hasNext();) { MethodInsnNode mn = it.next(); if (!(mn.owner.equals(blockPos.name) && mn.desc.equals(assembleDescriptor("(", blockPos, blockPos, ")Ljava/lang/Iterable;")))) it.remove(); } if (methodNodes.size() == 1) { addMethodMapping("net/minecraft/util/BlockPos getAllInBox (Lnet/minecraft/util/BlockPos;Lnet/minecraft/util/BlockPos;)Ljava/lang/Iterable;", blockPos.name + " " + methodNodes.get(0).name + " " + methodNodes.get(0).desc); } List<FieldInsnNode> fieldNodes = getAllInsnNodesOfType(methods.get(0).instructions.getFirst(), FieldInsnNode.class); for (Iterator<FieldInsnNode> it = fieldNodes.iterator(); it.hasNext();) { FieldInsnNode fn = it.next(); if (!fn.owner.equals(material.name)) it.remove(); } if (fieldNodes.size() == 1) { addFieldMapping("net/minecraft/block/material/Material leaves Lnet/minecraft/block/material/Material;", material.name + " " + fieldNodes.get(0).name + " " + fieldNodes.get(0).desc); } } return true; } @Mapping(provides={ }, providesFields={ "net/minecraft/block/BlockPane NORTH Lnet/minecraft/block/properties/PropertyBool;", "net/minecraft/block/BlockPane SOUTH Lnet/minecraft/block/properties/PropertyBool;", "net/minecraft/block/BlockPane WEST Lnet/minecraft/block/properties/PropertyBool;", "net/minecraft/block/BlockPane EAST Lnet/minecraft/block/properties/PropertyBool;" }, providesMethods={ }, depends={ "net/minecraft/block/BlockPane", "net/minecraft/block/properties/PropertyBool" }) public boolean processBlockPaneClass() { ClassNode pane = getClassNodeFromMapping("net/minecraft/block/BlockPane"); ClassNode propBool = getClassNodeFromMapping("net/minecraft/block/properties/PropertyBool"); if (!MeddleUtil.notNull(pane, propBool)) return false; MethodNode clinit = getMethodNode(pane, "- <clinit> ()V"); if (clinit == null) return false; String lastString = null; String north = null; String south = null; String east = null; String west = null; for (AbstractInsnNode insn = clinit.instructions.getFirst(); insn != null; insn = insn.getNext()) { String s = getLdcString(insn); if (s != null) { lastString = s; continue; } if (lastString == null) continue; FieldInsnNode fn = getNextInsnNodeOfType(insn, FieldInsnNode.class); if (fn == null || fn.getOpcode() != Opcodes.PUTSTATIC) continue; if (lastString != null && fn.owner.equals(pane.name) && fn.desc.equals("L" + propBool.name + ";")) { if (lastString.equals("north") && north == null) north = fn.name; else if (lastString.equals("south") && south == null) south = fn.name; else if (lastString.equals("east") && east == null) east = fn.name; else if (lastString.equals("west") && west == null) west = fn.name; lastString = null; insn = fn; } } if (MeddleUtil.notNull(north, south, east, west)) { addFieldMapping("net/minecraft/block/BlockPane NORTH Lnet/minecraft/block/properties/PropertyBool;", pane.name + " " + north + " L" + propBool.name + ";"); addFieldMapping("net/minecraft/block/BlockPane SOUTH Lnet/minecraft/block/properties/PropertyBool;", pane.name + " " + south + " L" + propBool.name + ";"); addFieldMapping("net/minecraft/block/BlockPane WEST Lnet/minecraft/block/properties/PropertyBool;", pane.name + " " + west + " L" + propBool.name + ";"); addFieldMapping("net/minecraft/block/BlockPane EAST Lnet/minecraft/block/properties/PropertyBool;", pane.name + " " + east + " L" + propBool.name + ";"); } return true; } @Mapping(provides={ "net/minecraft/block/BlockLiquid" }, providesMethods={ }, depends={ "net/minecraft/block/BlockDynamicLiquid" }) public boolean processBlockDynamicLiquidClass() { ClassNode dynamicLiquid = getClassNodeFromMapping("net/minecraft/block/BlockDynamicLiquid"); if (!MeddleUtil.notNull(dynamicLiquid)) return false; String blockLiquid_name = dynamicLiquid.superName; if (searchConstantPoolForStrings(blockLiquid_name, "level")) { addClassMapping("net/minecraft/block/BlockLiquid", blockLiquid_name); } return true; } @Mapping(provides={ "net/minecraft/block/properties/PropertyBool", "net/minecraft/block/BlockDoor$EnumHingePosition", "net/minecraft/block/BlockDoor$EnumDoorHalf" }, providesFields={ "net/minecraft/block/BlockDoor FACING Lnet/minecraft/block/properties/PropertyDirection;", "net/minecraft/block/BlockDoor HINGE Lnet/minecraft/block/properties/PropertyEnum;", "net/minecraft/block/BlockDoor HALF Lnet/minecraft/block/properties/PropertyEnum;", "net/minecraft/block/BlockDoor OPEN Lnet/minecraft/block/properties/PropertyBool;", "net/minecraft/block/BlockDoor POWERED Lnet/minecraft/block/properties/PropertyBool;" }, providesMethods={}, depends={ "net/minecraft/block/BlockDoor", "net/minecraft/block/properties/PropertyDirection", "net/minecraft/block/properties/PropertyHelper", "net/minecraft/block/properties/PropertyEnum" }) public boolean processBlockDoorClass() { ClassNode blockDoor = getClassNodeFromMapping("net/minecraft/block/BlockDoor"); ClassNode propertyDirection = getClassNodeFromMapping("net/minecraft/block/properties/PropertyDirection"); ClassNode propertyHelper = getClassNodeFromMapping("net/minecraft/block/properties/PropertyHelper"); ClassNode propertyEnum = getClassNodeFromMapping("net/minecraft/block/properties/PropertyEnum"); if (!MeddleUtil.notNull(blockDoor, propertyDirection, propertyHelper, propertyEnum)) return false; Set<String> classNames = new HashSet<>(); List<FieldNode> directionFields = new ArrayList<>(); List<FieldNode> enumFields = new ArrayList<>(); List<FieldNode> unknownFields = new ArrayList<>(); for (FieldNode field : blockDoor.fields) { Type t = Type.getType(field.desc); if (t.getSort() != Type.OBJECT) continue; if (t.getClassName().equals(propertyDirection.name)) directionFields.add(field); else if (t.getClassName().equals(propertyEnum.name)) enumFields.add(field); else { unknownFields.add(field); classNames.add(t.getClassName()); } } if (directionFields.size() == 1) { addFieldMapping("net/minecraft/block/BlockDoor FACING Lnet/minecraft/block/properties/PropertyDirection;", blockDoor.name + " " + directionFields.get(0).name + " " + directionFields.get(0).desc); } ClassNode propertyBool = null; for (String className : classNames) { ClassNode cn = getClassNode(className); if (!cn.superName.equals(propertyHelper.name)) continue; List<MethodNode> methods = getMatchingMethods(cn, "<init>", "(Ljava/lang/String;)V"); if (methods.size() == 1) { AbstractInsnNode insn = findNextOpcodeNum(methods.get(0).instructions.getFirst(), Opcodes.LDC); if (insn == null) continue; LdcInsnNode ldc = (LdcInsnNode)insn; if (!(ldc.cst instanceof Type)) continue; if (!((Type)ldc.cst).getClassName().equals("java.lang.Boolean")) continue; addClassMapping("net/minecraft/block/properties/PropertyBool", className); propertyBool = cn; break; } } // Find the PropertyEnum and PropertyBool fields List<MethodNode> methods = getMatchingMethods(blockDoor, "<clinit>", "()V"); if (methods.size() == 1) { for (AbstractInsnNode insn = methods.get(0).instructions.getFirst(); insn != null; insn = insn.getNext()) { AbstractInsnNode[] nodes; // Try to find PropertyEnum fields if ((nodes = getOpcodeSequenceArray(insn, Opcodes.LDC, Opcodes.LDC, Opcodes.INVOKESTATIC, Opcodes.PUTSTATIC)) != null) { LdcInsnNode ldc1 = (LdcInsnNode)nodes[0]; LdcInsnNode ldc2 = (LdcInsnNode)nodes[1]; MethodInsnNode mn = (MethodInsnNode)nodes[2]; FieldInsnNode fn = (FieldInsnNode)nodes[3]; if (!(ldc1.cst instanceof String)) continue; if (!(ldc2.cst instanceof Type)) continue; if (!mn.owner.equals(propertyEnum.name)) continue; if (!fn.owner.equals(blockDoor.name) || !fn.desc.equals("L" + propertyEnum.name + ";")) continue; if (((String)ldc1.cst).equals("hinge")) { String enumHingePosition = ((Type)ldc2.cst).getClassName(); if (searchConstantPoolForStrings(enumHingePosition, "LEFT", "RIGHT")) { addClassMapping("net/minecraft/block/BlockDoor$EnumHingePosition", enumHingePosition); addFieldMapping("net/minecraft/block/BlockDoor HINGE Lnet/minecraft/block/properties/PropertyEnum;", blockDoor.name + " " + fn.name + " " + fn.desc); } } else if (((String)ldc1.cst).equals("half")) { String enumDoorHalf = ((Type)ldc2.cst).getClassName(); if (searchConstantPoolForStrings(enumDoorHalf, "UPPER", "LOWER")) { addClassMapping("net/minecraft/block/BlockDoor$EnumDoorHalf", enumDoorHalf); addFieldMapping("net/minecraft/block/BlockDoor HALF Lnet/minecraft/block/properties/PropertyEnum;", blockDoor.name + " " + fn.name + " " + fn.desc); } } insn = nodes[3]; continue; } // Try to find PropertyBool fields else if ((nodes = getOpcodeSequenceArray(insn, Opcodes.LDC, Opcodes.INVOKESTATIC, Opcodes.PUTSTATIC)) != null) { LdcInsnNode ldc = (LdcInsnNode)nodes[0]; MethodInsnNode mn = (MethodInsnNode)nodes[1]; FieldInsnNode fn = (FieldInsnNode)nodes[2]; if (!(ldc.cst instanceof String)) continue; if (!mn.owner.equals(propertyBool.name)) continue; if (!fn.owner.equals(blockDoor.name) || !fn.desc.equals("L" + propertyBool.name + ";")) continue; if (((String)ldc.cst).equals("open")) { addFieldMapping("net/minecraft/block/BlockDoor OPEN Lnet/minecraft/block/properties/PropertyBool;", blockDoor.name + " " + fn.name + " " + fn.desc); } else if (((String)ldc.cst).equals("powered")) { addFieldMapping("net/minecraft/block/BlockDoor POWERED Lnet/minecraft/block/properties/PropertyBool;", blockDoor.name + " " + fn.name + " " + fn.desc); } insn = nodes[2]; continue; } } } return true; } @Mapping(provides={ "net/minecraft/util/IStringSerializable" }, providesMethods={ "net/minecraft/util/IStringSerializable getName ()Ljava/lang/String;" }, providesFields={ "net/minecraft/block/BlockDoor$EnumHingePosition LEFT Lnet/minecraft/block/BlockDoor$EnumHingePosition;", "net/minecraft/block/BlockDoor$EnumHingePosition RIGHT Lnet/minecraft/block/BlockDoor$EnumHingePosition;", "net/minecraft/block/BlockDoor$EnumDoorHalf UPPER Lnet/minecraft/block/BlockDoor$EnumDoorHalf;", "net/minecraft/block/BlockDoor$EnumDoorHalf LOWER Lnet/minecraft/block/BlockDoor$EnumDoorHalf;" }, depends={ "net/minecraft/block/BlockDoor$EnumHingePosition", "net/minecraft/block/BlockDoor$EnumDoorHalf" }) public boolean processBlockDoorProperties() { ClassNode hingePosition = getClassNodeFromMapping("net/minecraft/block/BlockDoor$EnumHingePosition"); ClassNode doorHalf = getClassNodeFromMapping("net/minecraft/block/BlockDoor$EnumDoorHalf"); if (hingePosition == null || doorHalf == null) return false; List<FieldNode> fields = getMatchingFields(hingePosition, null, "L" + hingePosition.name + ";"); if (fields.size() == 2) { addFieldMapping("net/minecraft/block/BlockDoor$EnumHingePosition LEFT Lnet/minecraft/block/BlockDoor$EnumHingePosition;", hingePosition.name + " " + fields.get(0).name + " " + fields.get(0).desc); addFieldMapping("net/minecraft/block/BlockDoor$EnumHingePosition RIGHT Lnet/minecraft/block/BlockDoor$EnumHingePosition;", hingePosition.name + " " + fields.get(1).name + " " + fields.get(1).desc); } fields = getMatchingFields(doorHalf, null, "L" + doorHalf.name + ";"); if (fields.size() == 2) { addFieldMapping("net/minecraft/block/BlockDoor$EnumDoorHalf UPPER Lnet/minecraft/block/BlockDoor$EnumDoorHalf;", doorHalf.name + " " + fields.get(0).name + " " + fields.get(0).desc); addFieldMapping("net/minecraft/block/BlockDoor$EnumDoorHalf LOWER Lnet/minecraft/block/BlockDoor$EnumDoorHalf;", doorHalf.name + " " + fields.get(1).name + " " + fields.get(1).desc); } // Find IStringSerializable while we're here if (hingePosition.interfaces.size() == 1 && doorHalf.interfaces.size() == 1 && hingePosition.interfaces.get(0).equals(doorHalf.interfaces.get(0))) { String iStringSerializable_name = hingePosition.interfaces.get(0); ClassNode iStringSerializable = getClassNode(iStringSerializable_name); if (iStringSerializable == null) return false; List<MethodNode> methods = getMatchingMethods(iStringSerializable, null, "()Ljava/lang/String;"); if (methods.size() == 1) { addClassMapping("net/minecraft/util/IStringSerializable", iStringSerializable_name); addMethodMapping("net/minecraft/util/IStringSerializable getName ()Ljava/lang/String;", iStringSerializable_name + " " + methods.get(0).name + " " + methods.get(0).desc); } } return true; } @Mapping(provides={ "net/minecraft/block/BlockDirectional", "net/minecraft/block/properties/PropertyDirection" }, providesFields={ "net/minecraft/block/BlockDirectional FACING Lnet/minecraft/block/properties/PropertyDirection;" }, depends={ "net/minecraft/block/BlockBed", "net/minecraft/block/BlockFenceGate", "net/minecraft/block/Block", "net/minecraft/util/EnumFacing" }) public boolean getBlockDirectionalClass() { ClassNode blockBed = getClassNodeFromMapping("net/minecraft/block/BlockBed"); ClassNode blockFenceGate = getClassNodeFromMapping("net/minecraft/block/BlockFenceGate"); ClassNode block = getClassNodeFromMapping("net/minecraft/block/Block"); ClassNode enumFacing = getClassNodeFromMapping("net/minecraft/util/EnumFacing"); if (!MeddleUtil.notNull(blockBed, blockFenceGate, block, enumFacing)) return false; // These should share this class as their parent if (!blockBed.superName.equals(blockFenceGate.superName)) return false; if (!searchConstantPoolForStrings(blockBed.superName, "facing")) return false; addClassMapping("net/minecraft/block/BlockDirectional", blockBed.superName); ClassNode blockDirectional = getClassNode(blockBed.superName); // Should only have one PropertyDirection field if (blockDirectional.fields.size() != 1) return false; if (!blockDirectional.fields.get(0).desc.startsWith("L")) return false; String propertyDirection_name = Type.getType(blockDirectional.fields.get(0).desc).getClassName(); if (!searchConstantPoolForClasses(propertyDirection_name, enumFacing.name)) return false; addClassMapping("net/minecraft/block/properties/PropertyDirection", propertyDirection_name); addFieldMapping("net/minecraft/block/BlockDirectional FACING Lnet/minecraft/block/properties/PropertyDirection;", blockDirectional.name + " " + blockDirectional.fields.get(0).name + " " + blockDirectional.fields.get(0).desc); return true; } @Mapping(provides={ "net/minecraft/block/properties/PropertyEnum", "net/minecraft/block/properties/PropertyHelper" }, providesMethods = { "net/minecraft/block/properties/PropertyDirection create (Ljava/lang/String;)Lnet/minecraft/block/properties/PropertyDirection;", "net/minecraft/block/properties/PropertyEnum create (Ljava/lang/String;Ljava/lang/Class;)Lnet/minecraft/block/properties/PropertyEnum;" }, depends={ "net/minecraft/block/properties/PropertyDirection", "net/minecraft/block/properties/IProperty" }) public boolean processPropertyDirectionClass() { ClassNode propertyDirection = getClassNodeFromMapping("net/minecraft/block/properties/PropertyDirection"); ClassNode iProperty = getClassNodeFromMapping("net/minecraft/block/properties/IProperty"); if (!MeddleUtil.notNull(propertyDirection,iProperty)) return false; List<MethodNode> methods = getMatchingMethods(propertyDirection, null, "(Ljava/lang/String;)L" + propertyDirection.name + ";"); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/properties/PropertyDirection create (Ljava/lang/String;)Lnet/minecraft/block/properties/PropertyDirection;", propertyDirection.name + " " + methods.get(0).name + " " + methods.get(0).desc); } String propertyEnum_name = null; if (searchConstantPoolForStrings(propertyDirection.superName, "Multiple values have the same name \'")) { propertyEnum_name = propertyDirection.superName; addClassMapping("net/minecraft/block/properties/PropertyEnum", propertyEnum_name); } else return false; ClassNode propertyEnum = getClassNode(propertyEnum_name); if (propertyEnum == null) return false; String propertyHelper_name = null; if (searchConstantPoolForStrings(propertyEnum.superName, "name", "clazz", "values")) { propertyHelper_name = propertyEnum.superName; addClassMapping("net/minecraft/block/properties/PropertyHelper", propertyHelper_name); } // public static PropertyEnum create(String param0, Class param1) methods = getMatchingMethods(propertyEnum, null, "(Ljava/lang/String;Ljava/lang/Class;)L" + propertyEnum.name + ";"); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/properties/PropertyEnum create (Ljava/lang/String;Ljava/lang/Class;)Lnet/minecraft/block/properties/PropertyEnum;", propertyEnum.name + " " + methods.get(0).name + " " + methods.get(0).desc); } return true; } @Mapping(provides={ "net/minecraft/world/IInteractionObject", "net/minecraft/block/BlockAnvil$Anvil", "net/minecraft/entity/player/InventoryPlayer", "net/minecraft/inventory/Container" }, providesMethods={ "net/minecraft/world/IInteractionObject getGuiID ()Ljava/lang/String;", "net/minecraft/world/IInteractionObject createContainer (Lnet/minecraft/entity/player/InventoryPlayer;Lnet/minecraft/entity/player/EntityPlayer;)Lnet/minecraft/inventory/Container;", "net/minecraft/entity/player/EntityPlayer displayGui (Lnet/minecraft/world/IInteractionObject;)V" }, dependsMethods={ "net/minecraft/block/Block onBlockActivated (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;Lnet/minecraft/block/state/IBlockState;Lnet/minecraft/entity/player/EntityPlayer;Lnet/minecraft/util/MainOrOffHand;Lnet/minecraft/util/EnumFacing;FFF)Z" }, depends={ "net/minecraft/block/BlockAnvil", "net/minecraft/entity/player/EntityPlayer" }) public boolean getIInteractionObjectClass() { ClassNode blockAnvil = getClassNodeFromMapping("net/minecraft/block/BlockAnvil"); ClassNode entityPlayer = getClassNodeFromMapping("net/minecraft/entity/player/EntityPlayer"); if (blockAnvil == null || entityPlayer == null) return false; MethodNode onBlockActivated = getMethodNodeFromMapping(blockAnvil, "net/minecraft/block/Block onBlockActivated (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;Lnet/minecraft/block/state/IBlockState;Lnet/minecraft/entity/player/EntityPlayer;Lnet/minecraft/util/MainOrOffHand;Lnet/minecraft/util/EnumFacing;FFF)Z"); if (onBlockActivated == null) return false; String iInteractionObject = null; String anvilInteractionObject = null; for (AbstractInsnNode insn = onBlockActivated.instructions.getFirst(); insn != null; insn = insn.getNext()) { if (insn.getOpcode() != Opcodes.NEW) continue; TypeInsnNode tn = (TypeInsnNode)insn; if (searchConstantPoolForStrings(tn.desc, "anvil")) { anvilInteractionObject = tn.desc; addClassMapping("net/minecraft/block/BlockAnvil$Anvil", tn.desc); break; } } if (anvilInteractionObject != null) { ClassNode anvil = getClassNode(anvilInteractionObject); if (anvil.interfaces.size() == 1) { iInteractionObject = anvil.interfaces.get(0); addClassMapping("net/minecraft/world/IInteractionObject", iInteractionObject); } } if (iInteractionObject != null) { ClassNode iiobject = getClassNode(iInteractionObject); // String getGuiID(); List<MethodNode> methods = getMatchingMethods(iiobject, null, "()Ljava/lang/String;"); if (methods.size() == 1) { addMethodMapping("net/minecraft/world/IInteractionObject getGuiID ()Ljava/lang/String;", iInteractionObject + " " + methods.get(0).name + " " + methods.get(0).desc); } // Container createContainer(InventoryPlayer, EntityPlayer); methods.clear(); for (MethodNode method : iiobject.methods) { if (!checkMethodParameters(method, Type.OBJECT, Type.OBJECT)) continue; Type t = Type.getMethodType(method.desc); if (t.getReturnType().getSort() != Type.OBJECT) continue; Type[] args = t.getArgumentTypes(); if (!args[1].getClassName().equals(entityPlayer.name)) continue; methods.add(method); } if (methods.size() == 1) { MethodNode m = methods.get(0); Type t = Type.getMethodType(m.desc); String inventoryPlayer = t.getArgumentTypes()[0].getClassName(); String container = t.getReturnType().getClassName(); boolean match1 = false; if (searchConstantPoolForStrings(inventoryPlayer, "Adding item to inventory", "container.inventory")) { match1 = true; addClassMapping("net/minecraft/entity/player/InventoryPlayer", inventoryPlayer); } boolean match2 = false; if (searchConstantPoolForStrings(container, "Listener already listening")) { match2 = true; addClassMapping("net/minecraft/inventory/Container", container); } if (match1 && match2) { addMethodMapping("net/minecraft/world/IInteractionObject createContainer (Lnet/minecraft/entity/player/InventoryPlayer;Lnet/minecraft/entity/player/EntityPlayer;)Lnet/minecraft/inventory/Container;", iInteractionObject + " " + m.name + " " + m.desc); } } // EntityPlayer.displayGui(IInteractionObject)V for (AbstractInsnNode insn = onBlockActivated.instructions.getFirst(); insn != null; insn = insn.getNext()) { if (insn.getOpcode() != Opcodes.INVOKEVIRTUAL) continue; MethodInsnNode mn = (MethodInsnNode)insn; if (mn.desc.equals("(L" + iInteractionObject + ";)V")) { addMethodMapping("net/minecraft/entity/player/EntityPlayer displayGui (Lnet/minecraft/world/IInteractionObject;)V", entityPlayer.name + " " + mn.name + " " + mn.desc); } } } return true; } @Mapping(provides={ "net/minecraft/inventory/Slot", "net/minecraft/inventory/EnumContainerAction" }, providesFields={ "net/minecraft/inventory/Container inventorySlots Ljava/util/List;", "net/minecraft/inventory/Container crafters Ljava/util/List;" }, providesMethods={ "net/minecraft/inventory/Container addSlotToContainer (Lnet/minecraft/inventory/Slot;)Lnet/minecraft/inventory/Slot;", "net/minecraft/inventory/Container canInteractWith (Lnet/minecraft/entity/player/EntityPlayer;)Z", "net/minecraft/inventory/Container transferStackInSlot (Lnet/minecraft/entity/player/EntityPlayer;I)Lnet/minecraft/item/ItemStack;", "net/minecraft/inventory/Container onContainerClosed (Lnet/minecraft/entity/player/EntityPlayer;)V", "net/minecraft/inventory/Container getSlot (I)Lnet/minecraft/inventory/Slot;", "net/minecraft/inventory/Container mergeItemStack (Lnet/minecraft/item/ItemStack;IIZ)Z", "net/minecraft/inventory/Container slotClick (IILnet/minecraft/inventory/EnumContainerAction;Lnet/minecraft/entity/player/EntityPlayer;)Lnet/minecraft/item/ItemStack;", "net/minecraft/inventory/Container putStackInSlot (ILnet/minecraft/item/ItemStack;)V", "net/minecraft/inventory/Container onCraftMatrixChanged (Lnet/minecraft/inventory/IInventory;)V", "net/minecraft/inventory/Container detectAndSendChanges ()V", "net/minecraft/inventory/Container canAddItemToSlot (Lnet/minecraft/inventory/Slot;Lnet/minecraft/item/ItemStack;Z)Z" }, depends={ "net/minecraft/inventory/Container", "net/minecraft/entity/player/EntityPlayer", "net/minecraft/item/ItemStack", "net/minecraft/inventory/IInventory", "net/minecraft/inventory/ICrafting" }) public boolean processContainerClass() { ClassNode container = getClassNodeFromMapping("net/minecraft/inventory/Container"); ClassNode entityPlayer = getClassNodeFromMapping("net/minecraft/entity/player/EntityPlayer"); ClassNode itemStack = getClassNodeFromMapping("net/minecraft/item/ItemStack"); ClassNode iInventory = getClassNodeFromMapping("net/minecraft/inventory/IInventory"); ClassNode iCrafting = getClassNodeFromMapping("net/minecraft/inventory/ICrafting"); if (!MeddleUtil.notNull(container, entityPlayer, itemStack, iInventory, iCrafting)) return false; List<MethodNode> methods = new ArrayList<>(); String slotClass = null; // protected Slot addSlotToContainer(Slot slotIn) for (MethodNode method : container.methods) { Type t = Type.getMethodType(method.desc); Type[] args = t.getArgumentTypes(); Type returnType = t.getReturnType(); if (args.length != 1) continue; if (args[0].getSort() != Type.OBJECT || returnType.getSort() != Type.OBJECT) continue; if (args[0].getClassName().equals(returnType.getClassName())) methods.add(method); } if (methods.size() == 1) { slotClass = Type.getMethodType(methods.get(0).desc).getReturnType().getClassName(); // TODO - Better class detection addClassMapping("net/minecraft/inventory/Slot", slotClass); addMethodMapping("net/minecraft/inventory/Container addSlotToContainer (Lnet/minecraft/inventory/Slot;)Lnet/minecraft/inventory/Slot;", container.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public abstract boolean canInteractWith(EntityPlayer playerIn); methods.clear(); for (MethodNode method : container.methods) { if ((method.access & Opcodes.ACC_ABSTRACT) == 0) continue; if (!method.desc.equals("(L" + entityPlayer.name + ";)Z")) continue; methods.add(method); } if (methods.size() == 1) { addMethodMapping("net/minecraft/inventory/Container canInteractWith (Lnet/minecraft/entity/player/EntityPlayer;)Z", container.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public ItemStack transferStackInSlot(EntityPlayer playerIn, int index) methods = getMatchingMethods(container, null, assembleDescriptor("(", entityPlayer, "I)", itemStack)); if (methods.size() == 1) { addMethodMapping("net/minecraft/inventory/Container transferStackInSlot (Lnet/minecraft/entity/player/EntityPlayer;I)Lnet/minecraft/item/ItemStack;", container.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public void onContainerClosed(EntityPlayer playerIn) methods = getMatchingMethods(container, null, assembleDescriptor("(", entityPlayer, ")V")); if (methods.size() == 1) { addMethodMapping("net/minecraft/inventory/Container onContainerClosed (Lnet/minecraft/entity/player/EntityPlayer;)V", container.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // inventorySlots // public Slot getSlot(int slotId) methods = getMatchingMethods(container, null, "(I)L" + slotClass + ";"); if (methods.size() == 1) { addMethodMapping("net/minecraft/inventory/Container getSlot (I)Lnet/minecraft/inventory/Slot;", container.name + " " + methods.get(0).name + " " + methods.get(0).desc); for (AbstractInsnNode insn = methods.get(0).instructions.getFirst(); insn != null; insn = insn.getNext()) { if (insn.getOpcode() != Opcodes.GETFIELD) continue; FieldInsnNode fn = (FieldInsnNode)insn; if (fn.desc.equals("Ljava/util/List;")) { addFieldMapping("net/minecraft/inventory/Container inventorySlots Ljava/util/List;", container.name + " " + fn.name + " " + fn.desc); } } } // protected boolean mergeItemStack(ItemStack, int, int, boolean) methods = getMatchingMethods(container, null, "(L" + itemStack.name + ";IIZ)Z"); if (methods.size() == 1) { addMethodMapping("net/minecraft/inventory/Container mergeItemStack (Lnet/minecraft/item/ItemStack;IIZ)Z", container.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public ItemStack slotClick(int slotId, int clickedButton, int mode, EntityPlayer playerIn) // As of 15w44a: public ItemStack slotClick(int slotId, int clickedButton, EnumContainerAction mode, EntityPlayer playerIn) methods.clear(); // = getMatchingMethods(container, null, "(IIIL" + entityPlayer.name + ";)L" + itemStack.name + ";"); for (MethodNode method : container.methods) { if (method.desc.startsWith("(IIL") && method.desc.endsWith(";L" + entityPlayer.name + ";)L" + itemStack.name + ";")) { Type[] args = Type.getMethodType(method.desc).getArgumentTypes(); if (args.length == 4) methods.add(method); } } if (methods.size() == 1) { String containerAction = Type.getMethodType(methods.get(0).desc).getArgumentTypes()[2].getClassName(); if (searchConstantPoolForStrings(containerAction, "PICKUP", "QUICK_CRAFT")) { addClassMapping("net/minecraft/inventory/EnumContainerAction", containerAction); addMethodMapping("net/minecraft/inventory/Container slotClick (IILnet/minecraft/inventory/EnumContainerAction;Lnet/minecraft/entity/player/EntityPlayer;)Lnet/minecraft/item/ItemStack;", container.name + " " + methods.get(0).name + " " + methods.get(0).desc); } } // public void putStackInSlot(int p_75141_1_, ItemStack p_75141_2_) methods = getMatchingMethods(container, null, "(IL" + itemStack.name + ";)V"); if (methods.size() == 1) { addMethodMapping("net/minecraft/inventory/Container putStackInSlot (ILnet/minecraft/item/ItemStack;)V", container.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public void onCraftMatrixChanged(IInventory inventoryIn) // public void detectAndSendChanges() methods = getMatchingMethods(container, null, "(L" + iInventory.name + ";)V"); if (methods.size() == 1) { addMethodMapping("net/minecraft/inventory/Container onCraftMatrixChanged (Lnet/minecraft/inventory/IInventory;)V", container.name + " " + methods.get(0).name + " " + methods.get(0).desc); List<MethodInsnNode> list = getAllInsnNodesOfType(methods.get(0).instructions.getFirst(), MethodInsnNode.class); if (list.size() == 1) { MethodInsnNode mn = list.get(0); if (mn.owner.equals(container.name) && mn.desc.equals("()V")) { addMethodMapping("net/minecraft/inventory/Container detectAndSendChanges ()V", container.name + " " + mn.name + " ()V"); } } } // public static boolean canAddItemToSlot(Slot slotIn, ItemStack stack, boolean stackSizeMatters) methods = getMatchingMethods(container, null, "(L" + slotClass + ";L" + itemStack.name + ";Z)Z"); if (methods.size() == 1) { addMethodMapping("net/minecraft/inventory/Container canAddItemToSlot (Lnet/minecraft/inventory/Slot;Lnet/minecraft/item/ItemStack;Z)Z", container.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // protected List crafters methods = getMatchingMethods(container, null, "(L" + iCrafting.name + ";)V"); if (methods.size() > 0) { Set<String> fieldNames = new HashSet<>(); for (MethodNode method : methods) { List<FieldInsnNode> list = getAllInsnNodesOfType(method.instructions.getFirst(), FieldInsnNode.class); for (FieldInsnNode fn : list) { if (fn.owner.equals(container.name) && fn.desc.equals("Ljava/util/List;")) fieldNames.add(fn.name); } } if (fieldNames.size() == 1) { String fieldName = fieldNames.toArray(new String[1])[0]; addFieldMapping("net/minecraft/inventory/Container crafters Ljava/util/List;", container.name + " " + fieldName + " Ljava/util/List;"); } } return true; } @Mapping(providesMethods={ "net/minecraft/inventory/ICrafting updateCraftingInventory (Lnet/minecraft/inventory/Container;Lnet/minecraft/util/MCList;)V", "net/minecraft/inventory/ICrafting sendSlotContents (Lnet/minecraft/inventory/Container;ILnet/minecraft/item/ItemStack;)V", "net/minecraft/inventory/ICrafting sendProgressBarUpdate (Lnet/minecraft/inventory/Container;II)V", "net/minecraft/inventory/ICrafting sendAllWindowProperties (Lnet/minecraft/inventory/Container;Lnet/minecraft/inventory/IInventory;)V" }, depends={ "net/minecraft/inventory/ICrafting", "net/minecraft/inventory/Container", "net/minecraft/item/ItemStack", "net/minecraft/inventory/IInventory", "net/minecraft/util/MCList" }) public boolean processICraftingClass() { ClassNode iCrafting = getClassNodeFromMapping("net/minecraft/inventory/ICrafting"); ClassNode container = getClassNodeFromMapping("net/minecraft/inventory/Container"); ClassNode itemStack = getClassNodeFromMapping("net/minecraft/item/ItemStack"); ClassNode iInventory = getClassNodeFromMapping("net/minecraft/inventory/IInventory"); ClassNode mcList = getClassNodeFromMapping("net/minecraft/util/MCList"); if (!MeddleUtil.notNull(iCrafting, container, itemStack, iInventory)) return false; // void updateCraftingInventory(Container containerToSend, MCList itemsList); // 16w32? java list change to MCList List<MethodNode> methods = getMatchingMethods(iCrafting, null, "(L" + container.name + ";L" + mcList.name + ";)V"); if (methods.size() == 1) { addMethodMapping("net/minecraft/inventory/ICrafting updateCraftingInventory (Lnet/minecraft/inventory/Container;Lnet/minecraft/util/MCList;)V", iCrafting.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // void sendSlotContents(Container containerToSend, int slotInd, ItemStack stack); methods = getMatchingMethods(iCrafting, null, "(L" + container.name + ";IL" + itemStack.name + ";)V"); if (methods.size() == 1) { addMethodMapping("net/minecraft/inventory/ICrafting sendSlotContents (Lnet/minecraft/inventory/Container;ILnet/minecraft/item/ItemStack;)V", iCrafting.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // void sendProgressBarUpdate(Container containerIn, int varToUpdate, int newValue); methods = getMatchingMethods(iCrafting, null, "(L" + container.name + ";II)V"); if (methods.size() == 1) { addMethodMapping("net/minecraft/inventory/ICrafting sendProgressBarUpdate (Lnet/minecraft/inventory/Container;II)V", iCrafting.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // void sendAllWindowProperties(Container p_175173_1_, IInventory p_175173_2_); methods = getMatchingMethods(iCrafting, null, "(L" + container.name + ";L" + iInventory.name + ";)V"); if (methods.size() == 1) { addMethodMapping("net/minecraft/inventory/ICrafting sendAllWindowProperties (Lnet/minecraft/inventory/Container;Lnet/minecraft/inventory/IInventory;)V", iCrafting.name + " " + methods.get(0).name + " " + methods.get(0).desc); } return true; } @Mapping(providesFields={ "net/minecraft/inventory/Slot inventory Lnet/minecraft/inventory/IInventory;", "net/minecraft/inventory/Slot slotIndex I", "net/minecraft/inventory/Slot xDisplayPosition I", "net/minecraft/inventory/Slot yDisplayPosition I", "net/minecraft/inventory/Slot slotNumber I" }, providesMethods={ "net/minecraft/inventory/Slot onSlotChange (Lnet/minecraft/item/ItemStack;Lnet/minecraft/item/ItemStack;)V", "net/minecraft/inventory/Slot onCrafting (Lnet/minecraft/item/ItemStack;I)V", "net/minecraft/inventory/Slot onCrafting (Lnet/minecraft/item/ItemStack;)V", "net/minecraft/inventory/Slot putStack (Lnet/minecraft/item/ItemStack;)V", "net/minecraft/inventory/Slot onPickupFromSlot (Lnet/minecraft/entity/player/EntityPlayer;Lnet/minecraft/item/ItemStack;)Lnet/minecraft/item/ItemStack;", "net/minecraft/inventory/Slot isItemValid (Lnet/minecraft/item/ItemStack;)Z", "net/minecraft/inventory/Slot getStack ()Lnet/minecraft/item/ItemStack;", "net/minecraft/inventory/Slot getHasStack ()Z", "net/minecraft/inventory/Slot onSlotChanged ()V", "net/minecraft/inventory/Slot getSlotStackLimit ()I", "net/minecraft/inventory/Slot getItemStackLimit (Lnet/minecraft/item/ItemStack;)I", "net/minecraft/inventory/Slot decrStackSize (I)Lnet/minecraft/item/ItemStack;", "net/minecraft/inventory/Slot isHere (Lnet/minecraft/inventory/IInventory;I)Z", "net/minecraft/inventory/Slot canTakeStack (Lnet/minecraft/entity/player/EntityPlayer;)Z" }, depends={ "net/minecraft/inventory/Slot", "net/minecraft/item/ItemStack", "net/minecraft/entity/player/EntityPlayer", "net/minecraft/inventory/IInventory" }) public boolean processSlotClass() { ClassNode slot = getClassNodeFromMapping("net/minecraft/inventory/Slot"); ClassNode itemStack = getClassNodeFromMapping("net/minecraft/item/ItemStack"); ClassNode entityPlayer = getClassNodeFromMapping("net/minecraft/entity/player/EntityPlayer"); ClassNode iInventory = getClassNodeFromMapping("net/minecraft/inventory/IInventory"); if (!MeddleUtil.notNull(slot, itemStack, entityPlayer, iInventory)) return false; List<MethodNode> methods = getMatchingMethods(slot, "<init>", assembleDescriptor("(",iInventory, "III)V")); String slotIndex = null; String xDisplayPosition = null; String yDisplayPosition = null; if (methods.size() == 1) { for (AbstractInsnNode insn = methods.get(0).instructions.getFirst(); insn != null; insn = insn.getNext()) { if (insn.getOpcode() != Opcodes.PUTFIELD) continue; FieldInsnNode fn = (FieldInsnNode)insn; if (!fn.owner.equals(slot.name)) continue; if (fn.desc.equals("L" + iInventory.name + ";")) { addFieldMapping("net/minecraft/inventory/Slot inventory Lnet/minecraft/inventory/IInventory;", slot.name + " " + fn.name + " " + fn.desc); continue; } if (fn.desc.equals("I")) { if (slotIndex == null) { slotIndex = fn.name; continue; } if (xDisplayPosition == null) { xDisplayPosition = fn.name; continue; } if (yDisplayPosition == null) { yDisplayPosition = fn.name; continue; } } } } if (MeddleUtil.notNull(slotIndex, xDisplayPosition, yDisplayPosition)) { List<FieldNode> fields = getMatchingFields(slot, null, "I"); if (fields.size() == 4) { for (FieldNode field : fields) { if (field.name.equals(slotIndex)) addFieldMapping("net/minecraft/inventory/Slot slotIndex I", slot.name + " " + field.name + " I"); else if (field.name.equals(xDisplayPosition)) addFieldMapping("net/minecraft/inventory/Slot xDisplayPosition I", slot.name + " " + field.name + " I"); else if (field.name.equals(yDisplayPosition)) addFieldMapping("net/minecraft/inventory/Slot yDisplayPosition I", slot.name + " " + field.name + " I"); else addFieldMapping("net/minecraft/inventory/Slot slotNumber I", slot.name + " " + field.name + " I"); } } } // public void onSlotChange(ItemStack, ItemStack) methods = getMatchingMethods(slot, null, assembleDescriptor("(", itemStack, itemStack, ")V")); if (methods.size() == 1) { addMethodMapping("net/minecraft/inventory/Slot onSlotChange (Lnet/minecraft/item/ItemStack;Lnet/minecraft/item/ItemStack;)V", slot.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // protected void onCrafting(ItemStack, int) methods = getMatchingMethods(slot, null, assembleDescriptor("(",itemStack,"I)V")); if (methods.size() == 1) { addMethodMapping("net/minecraft/inventory/Slot onCrafting (Lnet/minecraft/item/ItemStack;I)V", slot.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // protected void onCrafting(ItemStack) // public void putStack(ItemStack) methods = getMatchingMethods(slot, null, assembleDescriptor("(",itemStack,")V")); if (methods.size() == 2) { MethodNode onCrafting = null; MethodNode putStack = null; boolean isReturn1 = getNextRealOpcode(methods.get(0).instructions.getFirst()).getOpcode() == Opcodes.RETURN; boolean isReturn2 = getNextRealOpcode(methods.get(1).instructions.getFirst()).getOpcode() == Opcodes.RETURN; if (isReturn1 && !isReturn2) { onCrafting = methods.get(0); putStack = methods.get(1); } else if (!isReturn1 && isReturn2) { onCrafting = methods.get(1); putStack = methods.get(0); } if (onCrafting != null && putStack != null) { addMethodMapping("net/minecraft/inventory/Slot onCrafting (Lnet/minecraft/item/ItemStack;)V", slot.name + " " + onCrafting.name + " " + onCrafting.desc); addMethodMapping("net/minecraft/inventory/Slot putStack (Lnet/minecraft/item/ItemStack;)V", slot.name + " " + putStack.name + " " + putStack.desc); } } // public void onPickupFromSlot(EntityPlayer, ItemStack) methods = getMatchingMethods(slot, null, assembleDescriptor("(",entityPlayer, itemStack,")", itemStack)); if (methods.size() == 1) { addMethodMapping("net/minecraft/inventory/Slot onPickupFromSlot (Lnet/minecraft/entity/player/EntityPlayer;Lnet/minecraft/item/ItemStack;)Lnet/minecraft/item/ItemStack;", slot.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public boolean isItemValid(ItemStack) methods = getMatchingMethods(slot, null, assembleDescriptor("(",itemStack,")Z")); if (methods.size() == 1) { addMethodMapping("net/minecraft/inventory/Slot isItemValid (Lnet/minecraft/item/ItemStack;)Z", slot.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public ItemStack getStack() String getStack = null; methods = getMatchingMethods(slot, null, assembleDescriptor("()",itemStack)); if (methods.size() == 1) { getStack = slot.name + " " + methods.get(0).name + " " + methods.get(0).desc; addMethodMapping("net/minecraft/inventory/Slot getStack ()Lnet/minecraft/item/ItemStack;", getStack); } // public boolean getHasStack() methods = getMatchingMethods(slot, null, "()Z"); // Do this since canBeHovered()Z is client-only and may or may not be here if (getStack != null && (methods.size() == 1 || methods.size() == 2)) { startloop: for (MethodNode method : methods) { for (AbstractInsnNode insn = method.instructions.getFirst(); insn != null; insn = insn.getNext()) { // getHasStack() will call getStack if (insn.getOpcode() != Opcodes.INVOKEVIRTUAL) continue; MethodInsnNode mn = (MethodInsnNode)insn; if (!getStack.equals(mn.owner + " " + mn.name + " " + mn.desc)) continue; addMethodMapping("net/minecraft/inventory/Slot getHasStack ()Z", slot.name + " " + method.name + " " + method.desc); break startloop; } } } // public void onSlotChanged() methods = getMatchingMethods(slot, null, "()V"); if (methods.size() == 1) { addMethodMapping("net/minecraft/inventory/Slot onSlotChanged ()V", slot.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public int getSlotStackLimit() methods = getMatchingMethods(slot, null, "()I"); if (methods.size() == 1) { addMethodMapping("net/minecraft/inventory/Slot getSlotStackLimit ()I", slot.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public int getItemStackLimit(ItemStack) methods = getMatchingMethods(slot, null, assembleDescriptor("(", itemStack, ")I")); if (methods.size() == 1) { addMethodMapping("net/minecraft/inventory/Slot getItemStackLimit (Lnet/minecraft/item/ItemStack;)I", slot.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public ItemStack decrStackSize(int) methods = getMatchingMethods(slot, null, assembleDescriptor("(I)", itemStack)); if (methods.size() == 1) { addMethodMapping("net/minecraft/inventory/Slot decrStackSize (I)Lnet/minecraft/item/ItemStack;", slot.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public boolean isHere(IInventory, int) methods = getMatchingMethods(slot, null, assembleDescriptor("(", iInventory, "I)Z")); if (methods.size() == 1) { addMethodMapping("net/minecraft/inventory/Slot isHere (Lnet/minecraft/inventory/IInventory;I)Z", slot.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public boolean canTakeStack(EntityPlayer) methods = getMatchingMethods(slot, null, assembleDescriptor("(", entityPlayer, ")Z")); if (methods.size() == 1) { addMethodMapping("net/minecraft/inventory/Slot canTakeStack (Lnet/minecraft/entity/player/EntityPlayer;)Z", slot.name + " " + methods.get(0).name + " " + methods.get(0).desc); } /* TODO: @ClientOnly public String getSlotTexture() @ClientOnly public boolean canBeHovered() */ return true; } @Mapping(provides={ "net/minecraft/item/ItemSword", "net/minecraft/item/ItemSoup", "net/minecraft/item/ItemBanner", "net/minecraft/item/ItemDye", "net/minecraft/item/ItemBow", "net/minecraft/item/ItemRecord", "net/minecraft/item/ItemAxe", "net/minecraft/item/ItemTool", "net/minecraft/item/ItemPickaxe" }, providesMethods={ "net/minecraft/item/Item registerItems ()V" }, depends="net/minecraft/item/Item") public boolean discoverItems() { ClassNode itemClass = getClassNodeFromMapping("net/minecraft/item/Item"); if (itemClass == null) return false; // Find: public static void registerItems() List<MethodNode> methods = removeMethodsWithoutFlags(getMatchingMethods(itemClass, null, "()V"), Opcodes.ACC_STATIC); for (Iterator<MethodNode> it = methods.iterator(); it.hasNext();) { if (it.next().name.contains("<")) it.remove(); } if (methods.size() != 1) return false; MethodNode registerItemsMethod = methods.get(0); addMethodMapping("net/minecraft/item/Item registerItems ()V", itemClass.name + " " + registerItemsMethod.name + " " + registerItemsMethod.desc); Map<String, String> itemClassMap = new HashMap<String, String>(); // Extract a list of classes from item initializations. for (AbstractInsnNode insn = registerItemsMethod.instructions.getFirst(); insn != null; insn = insn.getNext()) { String name = getLdcString(insn); if (name == null || insn.getNext().getOpcode() != Opcodes.NEW) continue; insn = insn.getNext(); TypeInsnNode newNode = (TypeInsnNode)insn; if (!newNode.desc.equals(itemClass.name)) itemClassMap.put(name, newNode.desc); } String className; className = itemClassMap.get("iron_sword"); if (className != null && searchConstantPoolForStrings(className, "Weapon modifier")) { addClassMapping("net/minecraft/item/ItemSword", className); } className = itemClassMap.get("mushroom_stew"); if (className != null && className.equals(itemClassMap.get("rabbit_stew"))) { addClassMapping("net/minecraft/item/ItemSoup", className); } className = itemClassMap.get("banner"); if (className != null && searchConstantPoolForStrings(className, "item.banner.")) { addClassMapping("net/minecraft/item/ItemBanner", className); } className = itemClassMap.get("dye"); if (className != null && searchConstantPoolForStrings(className, ".")) { // TODO - better detection method addClassMapping("net/minecraft/item/ItemDye", className); } // catch match to "random.bow" anymore with 15w43a className = itemClassMap.get("bow"); if (className != null && searchConstantPoolForStrings(className, "pull", "pulling")) { addClassMapping("net/minecraft/item/ItemBow", className); } className = itemClassMap.get("record_13"); if (className != null && searchConstantPoolForStrings(className, "item.record.")) { addClassMapping("net/minecraft/item/ItemRecord", className); } String itemTool = null; className = itemClassMap.get("iron_axe"); if (className != null) { ClassNode axe = getClassNode(className); if (axe != null) { ClassNode tool = getClassNode(axe.superName); if (tool != null) { if (tool.superName.equals(itemClass.name) && searchConstantPoolForStrings(tool.name, "Tool modifier")) { addClassMapping("net/minecraft/item/ItemAxe", axe.name); addClassMapping("net/minecraft/item/ItemTool", tool.name); itemTool = tool.name; } } } } className = itemClassMap.get("iron_pickaxe"); if (className != null && itemTool != null) { ClassNode pickaxe = getClassNode(className); if (pickaxe != null && pickaxe.superName != null && pickaxe.superName.equals(itemTool)) { addClassMapping("net/minecraft/item/ItemPickaxe", pickaxe.name); } } className = itemClassMap.get("iron_pickaxe"); if (className != null) { ClassNode axe = getClassNode(className); if (axe != null) { ClassNode tool = getClassNode(axe.superName); if (tool != null) { if (tool.superName.equals(itemClass.name) && searchConstantPoolForStrings(tool.name, "Tool modifier")) { addClassMapping("net/minecraft/item/ItemPickaxe", axe.name); } } } } return true; } @Mapping(providesFields={ "net/minecraft/item/ItemPickaxe EFFECTIVE_ON Ljava/util/Set;", "net/minecraft/item/ItemTool efficiencyOnProperMaterial F" }, providesMethods={ "net/minecraft/item/Item canHarvestBlock (Lnet/minecraft/block/state/IBlockState;)Z", "net/minecraft/item/ItemTool getStrVsBlock (Lnet/minecraft/item/ItemStack;Lnet/minecraft/block/state/IBlockState;)F" }, depends={ "net/minecraft/item/ItemPickaxe", "net/minecraft/item/Item", "net/minecraft/item/ItemStack", "net/minecraft/block/Block", "net/minecraft/item/ItemTool", "net/minecraft/block/state/IBlockState" }) public boolean processItemPickaxeClass() { ClassNode itemPickaxe = getClassNodeFromMapping("net/minecraft/item/ItemPickaxe"); ClassNode item = getClassNodeFromMapping("net/minecraft/item/Item"); ClassNode itemStack = getClassNodeFromMapping("net/minecraft/item/ItemStack"); ClassNode block = getClassNodeFromMapping("net/minecraft/block/Block"); ClassNode itemTool = getClassNodeFromMapping("net/minecraft/item/ItemTool"); ClassNode iBlockState = getClassNodeFromMapping("net/minecraft/block/state/IBlockState"); if (!MeddleUtil.notNull(itemPickaxe, item, itemStack, block, itemTool, iBlockState)) return false; List<FieldNode> fields = getMatchingFields(itemPickaxe, null, "Ljava/util/Set;"); if (fields.size() == 1) { addFieldMapping("net/minecraft/item/ItemPickaxe EFFECTIVE_ON Ljava/util/Set;", itemPickaxe.name + " " + fields.get(0).name + " " + fields.get(0).desc); } // public boolean canHarvestBlock(Block blockIn) List<MethodNode> methods = getMatchingMethods(itemPickaxe, null, "(L" + iBlockState.name + ";)Z"); if (methods.size() == 1) { addMethodMapping("net/minecraft/item/Item canHarvestBlock (Lnet/minecraft/block/state/IBlockState;)Z", item.name + " " + methods.get(0).name + " " + methods.get(0).desc); // TODO: Get Item.ToolMaterial toolMaterial } // public float getStrVsBlock(ItemStack stack, Block block) methods = getMatchingMethods(itemPickaxe, null, "(L" + itemStack.name + ";L" + iBlockState.name + ";)F"); if (methods.size() == 1) { addMethodMapping("net/minecraft/item/ItemTool getStrVsBlock (Lnet/minecraft/item/ItemStack;Lnet/minecraft/block/state/IBlockState;)F", itemTool.name + " " + methods.get(0).name + " " + methods.get(0).desc); List<FieldInsnNode> nodes = getAllInsnNodesOfType(methods.get(0), FieldInsnNode.class); for (Iterator<FieldInsnNode> it = nodes.iterator(); it.hasNext();) { FieldInsnNode fn = it.next(); if (fn.owner.equals(itemPickaxe.name) && fn.desc.equals("F")) continue; else it.remove(); } if (nodes.size() == 1) { if (getFieldNode(itemTool, "--- " + nodes.get(0).name + " F") != null) { addFieldMapping("net/minecraft/item/ItemTool efficiencyOnProperMaterial F", itemTool.name + " " + nodes.get(0).name + " F"); } } } return true; } @Mapping(provides={ "net/minecraft/util/Sound" }, depends={ "net/minecraft/item/ItemRecord" }) public boolean processItemRecordClass() { ClassNode itemRecord = getClassNodeFromMapping("net/minecraft/item/ItemRecord"); if (itemRecord == null) return false; List<MethodNode> methods = new ArrayList<>(); for (MethodNode method : itemRecord.methods) { if (method.name.equals("<init>") && method.desc.startsWith("(Ljava/lang/String;L")) methods.add(method); } if (methods.size() == 1) { String soundClass = Type.getMethodType(methods.get(0).desc).getArgumentTypes()[1].getClassName(); if (searchConstantPoolForStrings(soundClass, "ambient.cave", "weather.rain")) { addClassMapping("net/minecraft/util/Sound", soundClass); } } return true; } @Mapping(providesMethods={ "net/minecraft/item/Item onPlayerStoppedUsing (Lnet/minecraft/item/ItemStack;Lnet/minecraft/world/World;Lnet/minecraft/entity/EntityLivingBase;I)V", "net/minecraft/item/Item getMaxItemUseDuration (Lnet/minecraft/item/ItemStack;)I", "net/minecraft/item/Item getItemEnchantability ()I", "net/minecraft/item/Item getItemUseAction (Lnet/minecraft/item/ItemStack;)Lnet/minecraft/item/EnumAction;", "net/minecraft/entity/EntityLivingBase setItemInUse (Lnet/minecraft/util/MainOrOffHand;)V" }, provides={ "net/minecraft/item/EnumAction", "net/minecraft/init/Sounds" }, dependsMethods={ "net/minecraft/item/Item onItemRightClick (Lnet/minecraft/world/World;Lnet/minecraft/entity/player/EntityPlayer;Lnet/minecraft/util/MainOrOffHand;)Lnet/minecraft/util/ObjectActionHolder;", }, depends={ "net/minecraft/item/Item", "net/minecraft/item/ItemBow", "net/minecraft/item/ItemStack", "net/minecraft/world/World", "net/minecraft/entity/player/EntityPlayer", "net/minecraft/entity/EntityLivingBase", "net/minecraft/util/MainOrOffHand", "net/minecraft/util/Sound" }) public boolean processItemBowClass() { ClassNode item = getClassNodeFromMapping("net/minecraft/item/Item"); ClassNode itemBow = getClassNodeFromMapping("net/minecraft/item/ItemBow"); ClassNode itemStack = getClassNodeFromMapping("net/minecraft/item/ItemStack"); ClassNode world = getClassNodeFromMapping("net/minecraft/world/World"); ClassNode entityPlayer = getClassNodeFromMapping("net/minecraft/entity/player/EntityPlayer"); ClassNode entityLivingBase = getClassNodeFromMapping("net/minecraft/entity/EntityLivingBase"); ClassNode hand = getClassNodeFromMapping("net/minecraft/util/MainOrOffHand"); ClassNode sound = getClassNodeFromMapping("net/minecraft/util/Sound"); if (!MeddleUtil.notNull(item, itemBow, itemStack, world, entityPlayer, entityLivingBase, hand, sound)) return false; // public void onPlayerStoppedUsing(ItemStack stack, World worldIn, EntityLivingBase playerIn, int timeLeft) List<MethodNode> methods = getMatchingMethods(itemBow, null, assembleDescriptor("(", itemStack, world, entityLivingBase, "I)V")); if (methods.size() == 1) { addMethodMapping("net/minecraft/item/Item onPlayerStoppedUsing (Lnet/minecraft/item/ItemStack;Lnet/minecraft/world/World;Lnet/minecraft/entity/EntityLivingBase;I)V", item.name + " " + methods.get(0).name + " " + methods.get(0).desc); List<FieldInsnNode> nodes = getAllInsnNodesOfType(methods.get(0).instructions.getFirst(), FieldInsnNode.class); for (FieldInsnNode fn : nodes) { if (fn.desc.equals("L" + sound.name + ";")) { if (searchConstantPoolForStrings(fn.owner, "Accessed Sounds before Bootstrap!")) { addClassMapping("net/minecraft/init/Sounds", fn.owner); } } } } // public int getMaxItemUseDuration(ItemStack param0) methods = getMatchingMethods(itemBow, null, assembleDescriptor("(", itemStack, ")I")); if (methods.size() == 1) { addMethodMapping("net/minecraft/item/Item getMaxItemUseDuration (Lnet/minecraft/item/ItemStack;)I", item.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public EnumAction getItemUseAction(ItemStack param0) methods.clear(); for (MethodNode method : itemBow.methods) { if (method.desc.startsWith("(L" + itemStack.name + ";)L")) methods.add(method); } if (methods.size() == 1) { MethodNode method = methods.get(0); Type t = Type.getMethodType(method.desc).getReturnType(); if (searchConstantPoolForStrings(t.getClassName(), "EAT", "DRINK", "BLOCK")) { addClassMapping("net/minecraft/item/EnumAction", t.getClassName()); addMethodMapping("net/minecraft/item/Item getItemUseAction (Lnet/minecraft/item/ItemStack;)Lnet/minecraft/item/EnumAction;", item.name + " " + method.name + " " + method.desc); } } // public int getItemEnchantability() methods = getMatchingMethods(itemBow, null, "()I"); if (methods.size() == 1) { addMethodMapping("net/minecraft/item/Item getItemEnchantability ()I", item.name + " " + methods.get(0).name + " " + methods.get(0).desc); } MethodNode method = getMethodNodeFromMapping(itemBow, "net/minecraft/item/Item onItemRightClick (Lnet/minecraft/world/World;Lnet/minecraft/entity/player/EntityPlayer;Lnet/minecraft/util/MainOrOffHand;)Lnet/minecraft/util/ObjectActionHolder;"); if (method != null) { List<MethodInsnNode> methodNodes = new ArrayList<>(); for (AbstractInsnNode insn = method.instructions.getFirst(); insn != null; insn = insn.getNext()) { if (insn.getOpcode() != Opcodes.INVOKEVIRTUAL) continue; MethodInsnNode mn = (MethodInsnNode)insn; if (mn.owner.equals(entityPlayer.name) && mn.desc.equals("(L" + hand.name + ";)V")) methodNodes.add(mn); } if (methodNodes.size() == 1) { addMethodMapping("net/minecraft/entity/EntityLivingBase setItemInUse (Lnet/minecraft/util/MainOrOffHand;)V", entityLivingBase.name + " " + methodNodes.get(0).name + " " + methodNodes.get(0).desc); } } return true; } @Mapping(providesFields={ "net/minecraft/item/EnumAction NONE Lnet/minecraft/item/EnumAction;", "net/minecraft/item/EnumAction EAT Lnet/minecraft/item/EnumAction;", "net/minecraft/item/EnumAction DRINK Lnet/minecraft/item/EnumAction;", "net/minecraft/item/EnumAction BLOCK Lnet/minecraft/item/EnumAction;", "net/minecraft/item/EnumAction BOW Lnet/minecraft/item/EnumAction;" }, depends={ "net/minecraft/item/EnumAction" }) public boolean processEnumActionClass() { ClassNode enumAction = getClassNodeFromMapping("net/minecraft/item/EnumAction"); if (enumAction == null) return false; List<String> strings = new ArrayList<>(); List<String> fields = new ArrayList<>(); MethodNode init = getMethodNode(enumAction, "--- <clinit> ()V"); if (init == null) return false; for (AbstractInsnNode insn = init.instructions.getFirst(); insn != null; insn = insn.getNext()) { String s = getLdcString(insn); if (s != null) { strings.add(s); continue; } if (insn.getOpcode() == Opcodes.PUTSTATIC) { FieldInsnNode fn = (FieldInsnNode)insn; if (fn.owner.equals(enumAction.name) && fn.desc.equals("L" + enumAction.name + ";")) fields.add(fn.name); } } if (strings.size() == 5 && fields.size() == 5) { for (int n = 0; n < 5; n++) { addFieldMapping("net/minecraft/item/EnumAction " + strings.get(n) + " Lnet/minecraft/item/EnumAction;", enumAction.name + " " + fields.get(n) + " L" + enumAction.name + ";"); } } return true; } @Mapping(providesMethods={ "net/minecraft/item/Item setHasSubtypes (Z)Lnet/minecraft/item/Item;", "net/minecraft/item/ItemStack getMetadata ()I" }, providesFields={ }, dependsMethods={ "net/minecraft/item/Item getUnlocalizedName (Lnet/minecraft/item/ItemStack;)Ljava/lang/String;" }, depends={ "net/minecraft/item/Item", "net/minecraft/item/ItemDye", "net/minecraft/item/ItemStack" }) public boolean processItemDyeClass() { ClassNode item = getClassNodeFromMapping("net/minecraft/item/Item"); ClassNode itemDye = getClassNodeFromMapping("net/minecraft/item/ItemDye"); ClassNode itemStack = getClassNodeFromMapping("net/minecraft/item/ItemStack"); if (!MeddleUtil.notNull(item, itemDye, itemStack)) return false; // protected Item setHasSubtypes(boolean hasSubtypes) List<MethodNode> methods = getMatchingMethods(itemDye, "<init>", "()V"); if (methods.size() == 1) { List<MethodInsnNode> mnodes = getAllInsnNodesOfType(methods.get(0).instructions.getFirst(), MethodInsnNode.class); List<MethodInsnNode> foundnodes = new ArrayList<>(); for (MethodInsnNode mn : mnodes) { if (!mn.owner.equals(itemDye.name)) continue; if (mn.desc.equals("(Z)L" + item.name + ";")) foundnodes.add(mn); } if (foundnodes.size() == 1) { addMethodMapping("net/minecraft/item/Item setHasSubtypes (Z)Lnet/minecraft/item/Item;", item.name + " " + foundnodes.get(0).name + " " + foundnodes.get(0).desc); } } MethodNode method = getMethodNodeFromMapping(itemDye, "net/minecraft/item/Item getUnlocalizedName (Lnet/minecraft/item/ItemStack;)Ljava/lang/String;"); if (method != null) { List<MethodInsnNode> mnodes = getAllInsnNodesOfType(method.instructions.getFirst(), MethodInsnNode.class); for (Iterator<MethodInsnNode> iterator = mnodes.iterator(); iterator.hasNext();) { MethodInsnNode mn = iterator.next(); if (!(mn.owner.equals(itemStack.name) && mn.desc.equals("()I"))) iterator.remove(); } if (mnodes.size() == 1) { addMethodMapping("net/minecraft/item/ItemStack getMetadata ()I", itemStack.name + " " + mnodes.get(0).name + " ()I"); } } return true; } @Mapping(providesMethods={ "net/minecraft/item/Item setMaxDamage (I)Lnet/minecraft/item/Item;", "net/minecraft/item/Item getMaxDamage ()I" }, providesFields={ "net/minecraft/item/Item maxDamage I" }, depends={ "net/minecraft/item/Item", "net/minecraft/item/ItemBanner" }) public boolean getMaxDamageStuff() { ClassNode item = getClassNodeFromMapping("net/minecraft/item/Item"); ClassNode banner = getClassNodeFromMapping("net/minecraft/item/ItemBanner"); if (item == null || banner == null) return false; List<MethodNode> methods = getMatchingMethods(banner, "<init>", "()V"); if (methods.size() != 1) return false; int count = 0; String setMaxDamageName = null; String setMaxDamageDesc = "(I)L" + item.name + ";"; // Locate Item.setMaxDamage used in ItemBanner's constructor for (AbstractInsnNode insn = methods.get(0).instructions.getFirst(); insn != null; insn = insn.getNext()) { if (insn.getOpcode() != Opcodes.INVOKEVIRTUAL) continue; MethodInsnNode mn = (MethodInsnNode)insn; if (!mn.desc.equals(setMaxDamageDesc)) continue; setMaxDamageName = mn.name; count++; } if (count != 1) return false; addMethodMapping("net/minecraft/item/Item setMaxDamage (I)Lnet/minecraft/item/Item;", item.name + " " + setMaxDamageName + " " + setMaxDamageDesc); String maxDamageField = null; methods = getMatchingMethods(item, setMaxDamageName, setMaxDamageDesc); if (methods.size() != 1) return false; // Get Item.maxDamage field from Item.setMaxDamage(I) for (AbstractInsnNode insn = methods.get(0).instructions.getFirst(); insn != null; insn = insn.getNext()) { if (insn.getOpcode() < 0) continue; if (insn.getOpcode() != Opcodes.ALOAD) return false; insn = insn.getNext(); if (insn.getOpcode() != Opcodes.ILOAD) return false; insn = insn.getNext(); if (insn.getOpcode() != Opcodes.PUTFIELD) return false; FieldInsnNode fn = (FieldInsnNode)insn; if (!fn.desc.equals("I")) return false; maxDamageField = fn.name; break; } if (maxDamageField == null) return false; addFieldMapping("net/minecraft/item/Item maxDamage I", item.name + " " + maxDamageField + " I"); // Find Item.getMaxDamage() methods = getMatchingMethods(item, null, "()I"); for (MethodNode method : methods) { for (AbstractInsnNode insn = method.instructions.getFirst(); insn != null; insn = insn.getNext()) { if (insn.getOpcode() < 0) continue; if (insn.getOpcode() != Opcodes.ALOAD) return false; insn = insn.getNext(); if (insn.getOpcode() != Opcodes.GETFIELD) return false; FieldInsnNode fn = (FieldInsnNode)insn; if (fn.name.equals(maxDamageField)) { addMethodMapping("net/minecraft/item/Item getMaxDamage ()I", item.name + " " + method.name + " " + method.desc); return true; } break; } } return false; } @Mapping(provides={ "net/minecraft/util/Vec3", "net/minecraft/block/material/Material", "net/minecraft/block/material/MapColor", "net/minecraft/block/state/BlockState", "net/minecraft/util/RegistryNamespacedDefaultedByKey", "net/minecraft/util/ObjectIntIdentityMap" }, providesFields={ "net/minecraft/block/Block unlocalizedName Ljava/lang/String;", "net/minecraft/block/Block blockRegistry Lnet/minecraft/util/RegistryNamespacedDefaultedByKey;", "net/minecraft/block/Block BLOCK_STATE_IDS Lnet/minecraft/util/ObjectIntIdentityMap;", "net/minecraft/block/Block defaultBlockState Lnet/minecraft/block/state/IBlockState;", "net/minecraft/block/Block translucent Z", "net/minecraft/block/Block useNeighborBrightness Z" }, providesMethods={ "net/minecraft/block/Block getIdFromBlock (Lnet/minecraft/block/Block;)I", "net/minecraft/block/Block onBlockActivated (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;Lnet/minecraft/block/state/IBlockState;Lnet/minecraft/entity/player/EntityPlayer;Lnet/minecraft/util/MainOrOffHand;Lnet/minecraft/util/EnumFacing;FFF)Z", "net/minecraft/block/Block collisionRayTrace (Lnet/minecraft/block/state/IBlockState;Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;Lnet/minecraft/util/Vec3;Lnet/minecraft/util/Vec3;)Lnet/minecraft/util/MovingObjectPosition;", "net/minecraft/block/Block registerBlock (ILnet/minecraft/util/ResourceLocation;Lnet/minecraft/block/Block;)V", "net/minecraft/block/Block registerBlock (ILjava/lang/String;Lnet/minecraft/block/Block;)V", "net/minecraft/block/Block getStateFromMeta (I)Lnet/minecraft/block/state/IBlockState;", "net/minecraft/block/Block getStateById (I)Lnet/minecraft/block/state/IBlockState;", "net/minecraft/block/Block getMetaFromState (Lnet/minecraft/block/state/IBlockState;)I", "net/minecraft/block/Block setDefaultState (Lnet/minecraft/block/state/IBlockState;)V", "net/minecraft/block/Block getDefaultState ()Lnet/minecraft/block/state/IBlockState;", "net/minecraft/block/Block getActualState (Lnet/minecraft/block/state/IBlockState;Lnet/minecraft/world/IBlockAccess;Lnet/minecraft/util/BlockPos;)Lnet/minecraft/block/state/IBlockState;", "net/minecraft/block/Block setUnlocalizedName (Ljava/lang/String;)Lnet/minecraft/block/Block;", "net/minecraft/block/Block getLocalizedName ()Ljava/lang/String;", "net/minecraft/block/Block getUnlocalizedName ()Ljava/lang/String;", "net/minecraft/block/Block onEntityCollidedWithBlock (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;Lnet/minecraft/entity/Entity;)V", "net/minecraft/block/Block onBlockPlaced (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;Lnet/minecraft/util/EnumFacing;FFFILnet/minecraft/entity/EntityLivingBase;)Lnet/minecraft/block/state/IBlockState;", "net/minecraft/block/Block onBlockClicked (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;Lnet/minecraft/entity/player/EntityPlayer;)V", "net/minecraft/block/material/Material getMaterialMapColor ()Lnet/minecraft/block/material/MapColor;", "net/minecraft/block/Block createBlockState ()Lnet/minecraft/block/state/BlockState;", "net/minecraft/block/Block getBlockState ()Lnet/minecraft/block/state/BlockState;", "net/minecraft/block/Block registerBlocks ()V", "net/minecraft/util/ObjectIntIdentityMap put (Ljava/lang/Object;I)V" }, depends={ "net/minecraft/block/Block", "net/minecraft/item/Item", "net/minecraft/item/ItemStack", "net/minecraft/world/World", "net/minecraft/util/BlockPos", "net/minecraft/block/state/IBlockState", "net/minecraft/entity/player/EntityPlayer", "net/minecraft/util/MainOrOffHand", "net/minecraft/util/EnumFacing", "net/minecraft/util/MovingObjectPosition", "net/minecraft/util/ResourceLocation", "net/minecraft/world/IBlockAccess", "net/minecraft/entity/Entity", "net/minecraft/entity/EntityLivingBase" }) public boolean processBlockClass() { ClassNode block = getClassNodeFromMapping("net/minecraft/block/Block"); ClassNode item = getClassNodeFromMapping("net/minecraft/item/Item"); ClassNode itemStack = getClassNodeFromMapping("net/minecraft/item/ItemStack"); ClassNode world = getClassNodeFromMapping("net/minecraft/world/World"); ClassNode blockPos = getClassNodeFromMapping("net/minecraft/util/BlockPos"); ClassNode iBlockState = getClassNodeFromMapping("net/minecraft/block/state/IBlockState"); ClassNode entityPlayer = getClassNodeFromMapping("net/minecraft/entity/player/EntityPlayer"); ClassNode mainOrOffHand = getClassNodeFromMapping("net/minecraft/util/MainOrOffHand"); ClassNode enumFacing = getClassNodeFromMapping("net/minecraft/util/EnumFacing"); ClassNode movingObjectPosition = getClassNodeFromMapping("net/minecraft/util/MovingObjectPosition"); ClassNode resourceLocation = getClassNodeFromMapping("net/minecraft/util/ResourceLocation"); ClassNode iBlockAccess = getClassNodeFromMapping("net/minecraft/world/IBlockAccess"); ClassNode entityLivingBase = getClassNodeFromMapping("net/minecraft/entity/EntityLivingBase"); ClassNode entity = getClassNodeFromMapping("net/minecraft/entity/Entity"); if (!MeddleUtil.notNull(block, item, itemStack, blockPos, world, iBlockState, entityPlayer, mainOrOffHand, enumFacing, movingObjectPosition, resourceLocation, iBlockAccess, entityLivingBase, entity)) return false; List<MethodNode> methods = new ArrayList<MethodNode>(); // public static int getIdFromBlock(Block) methods = getMatchingMethods(block, null, "(L" + block.name + ";)I"); methods = removeMethodsWithoutFlags(methods, Opcodes.ACC_STATIC); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/Block getIdFromBlock (Lnet/minecraft/block/Block;)I", block.name + " " + methods.get(0).name + " " + methods.get(0).desc); for (AbstractInsnNode insn = methods.get(0).instructions.getFirst(); insn != null; insn = insn.getNext()) { if (insn.getOpcode() != Opcodes.GETSTATIC) continue; FieldInsnNode fn = (FieldInsnNode)insn; String registryNamespacedDefaultedByKey = Type.getType(fn.desc).getClassName(); addClassMapping("net/minecraft/util/RegistryNamespacedDefaultedByKey", registryNamespacedDefaultedByKey); addFieldMapping("net/minecraft/block/Block blockRegistry Lnet/minecraft/util/RegistryNamespacedDefaultedByKey;", block.name + " " + fn.name + " " + fn.desc); } } // private static void registerBlock(int, ResourceLocation, Block) methods = getMatchingMethods(block, null, "(IL" + resourceLocation.name + ";L" + block.name + ";)V"); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/Block registerBlock (ILnet/minecraft/util/ResourceLocation;Lnet/minecraft/block/Block;)V", block.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // private static void registerBlock(int, String, Block) methods = getMatchingMethods(block, null, "(ILjava/lang/String;L" + block.name + ";)V"); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/Block registerBlock (ILjava/lang/String;Lnet/minecraft/block/Block;)V", block.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // protected Block(Material) methods.clear(); String materialClass = null; String mapColorClass = null; for (MethodNode method : block.methods) { if (!method.name.equals("<init>")) continue; Type t = Type.getMethodType(method.desc); Type[] args = t.getArgumentTypes(); if (args.length != 1) continue; if (args[0].getSort() != Type.OBJECT) continue; methods.add(method); } if (methods.size() == 1) { materialClass = Type.getMethodType(methods.get(0).desc).getArgumentTypes()[0].getClassName(); addClassMapping("net/minecraft/block/material/Material", materialClass); startloop: for (AbstractInsnNode insn = methods.get(0).instructions.getFirst(); insn != null; insn = insn.getNext()) { if (insn.getOpcode() != Opcodes.INVOKEVIRTUAL) continue; MethodInsnNode mn = (MethodInsnNode)insn; if (!mn.owner.equals(materialClass)) continue; mapColorClass = Type.getMethodType(mn.desc).getReturnType().getClassName(); if (searchConstantPoolForStrings(mapColorClass, "Map colour ID must be between 0 and 63 (inclusive)")) { addClassMapping("net/minecraft/block/material/MapColor", mapColorClass); addMethodMapping("net/minecraft/block/material/Material getMaterialMapColor ()Lnet/minecraft/block/material/MapColor;", materialClass + " " + mn.name + " " + mn.desc); break startloop; } else mapColorClass = null; } } // protected Block(Material, MapColor) String blockStateClass = null; methods.clear(); if (materialClass != null && mapColorClass != null) methods = getMatchingMethods(block, "<init>", "(L" + materialClass + ";L" + mapColorClass + ";)V"); if (methods.size() == 1) { for (AbstractInsnNode insn = methods.get(0).instructions.getFirst(); insn != null; insn = insn.getNext()) { if (insn.getOpcode() != Opcodes.INVOKEVIRTUAL) continue; MethodInsnNode mn = (MethodInsnNode)insn; Type returnType = Type.getMethodType(mn.desc).getReturnType(); if (returnType.getSort() != Type.OBJECT) continue; if (!returnType.getClassName().equals(iBlockState.name)) continue; if (searchConstantPoolForStrings(mn.owner, "block", "properties")) { blockStateClass = mn.owner; addClassMapping("net/minecraft/block/state/BlockState", mn.owner); break; } } } // public boolean onBlockActivated(World, BlockPos, IBlockState, EntityPlayer, MainOrOffHand, ItemStack, EnumFacing, float, float, float) // 16w32a removed itemstack String descriptor = assembleDescriptor("(", world, blockPos, iBlockState, entityPlayer, mainOrOffHand, enumFacing, "FFF)Z"); methods = getMatchingMethods(block, null, descriptor); if (methods.size() == 1) { MethodNode method = methods.get(0); addMethodMapping("net/minecraft/block/Block onBlockActivated (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;Lnet/minecraft/block/state/IBlockState;Lnet/minecraft/entity/player/EntityPlayer;Lnet/minecraft/util/MainOrOffHand;Lnet/minecraft/util/EnumFacing;FFF)Z", block.name + " " + method.name + " " + method.desc); } // (15w37a added IBlockState parm) // public MovingObjectPosition collisionRayTrace(IBlockState param0, World worldIn, BlockPos pos, Vec3 start, Vec3 end) methods.clear(); for (MethodNode method : block.methods) { if (!method.desc.startsWith("(L" + iBlockState.name + ";L" + world.name + ";L" + blockPos.name + ";L")) continue; if (!method.desc.endsWith(";)L" + movingObjectPosition.name + ";")) continue; Type t = Type.getMethodType(method.desc); Type[] args = t.getArgumentTypes(); if (args.length != 5) continue; if (args[3].getSort() != Type.OBJECT) continue; if (!args[3].getClassName().equals(args[4].getClassName())) continue; methods.add(method); } if (methods.size() == 1) { MethodNode method = methods.get(0); String vec3_name = Type.getMethodType(method.desc).getArgumentTypes()[3].getClassName(); addClassMapping("net/minecraft/util/Vec3", vec3_name); addMethodMapping("net/minecraft/block/Block collisionRayTrace (Lnet/minecraft/block/state/IBlockState;Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;Lnet/minecraft/util/Vec3;Lnet/minecraft/util/Vec3;)Lnet/minecraft/util/MovingObjectPosition;", block.name + " " + method.name + " " + method.desc); } methods = getMatchingMethods(block, null, "(I)L" + iBlockState.name + ";"); if (methods.size() == 2) { for (MethodNode method : methods) { // public IBlockState getStateFromMeta(int) if ((method.access & Opcodes.ACC_STATIC) == 0) { addMethodMapping("net/minecraft/block/Block getStateFromMeta (I)Lnet/minecraft/block/state/IBlockState;", block.name + " " + method.name + " " + method.desc); } // public static IBlockState getStateById(int) else { addMethodMapping("net/minecraft/block/Block getStateById (I)Lnet/minecraft/block/state/IBlockState;", block.name + " " + method.name + " " + method.desc); } } } // public int getMetaFromState(IBlockState) methods = getMatchingMethods(block, null, "(L" + iBlockState.name + ";)I"); outerloop: for (MethodNode method : methods) { for (AbstractInsnNode insn = method.instructions.getFirst(); insn != null; insn = insn.getNext()) { if (!isLdcWithString(insn, "Don't know how to convert ")) continue; addMethodMapping("net/minecraft/block/Block getMetaFromState (Lnet/minecraft/block/state/IBlockState;)I", block.name + " " + method.name + " " + method.desc); break outerloop; } } // protected final void setDefaultState(IBlockState state) methods = getMatchingMethods(block, null, "(L" + iBlockState.name + ";)V"); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/Block setDefaultState (Lnet/minecraft/block/state/IBlockState;)V", block.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public final IBlockState getDefaultState() methods = getMatchingMethods(block, null, "()L" + iBlockState.name + ";"); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/Block getDefaultState ()Lnet/minecraft/block/state/IBlockState;", block.name + " " + methods.get(0).name + " " + methods.get(0).desc); List<FieldInsnNode> nodes = getAllInsnNodesOfType(methods.get(0), FieldInsnNode.class); if (nodes.size() == 1 && nodes.get(0).owner.equals(block.name) && nodes.get(0).desc.equals("L" + iBlockState.name + ";")) { addFieldMapping("net/minecraft/block/Block defaultBlockState Lnet/minecraft/block/state/IBlockState;", block.name + " " + nodes.get(0).name + " " + nodes.get(0).desc); } } // public IBlockState getActualState(IBlockState state, IBlockAccess worldIn, BlockPos pos) methods = getMatchingMethods(block, null, "(L" + iBlockState.name + ";L" + iBlockAccess.name + ";L" + blockPos.name + ";)L" + iBlockState.name + ";"); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/Block getActualState (Lnet/minecraft/block/state/IBlockState;Lnet/minecraft/world/IBlockAccess;Lnet/minecraft/util/BlockPos;)Lnet/minecraft/block/state/IBlockState;", block.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public Block setUnlocalizedName(String name) methods = getMatchingMethods(block, null, "(Ljava/lang/String;)L" + block.name + ";"); methods = removeMethodsWithFlags(methods, Opcodes.ACC_STATIC); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/Block setUnlocalizedName (Ljava/lang/String;)Lnet/minecraft/block/Block;", block.name + " " + methods.get(0).name + " " + methods.get(0).desc); for (AbstractInsnNode insn = methods.get(0).instructions.getFirst(); insn != null; insn = insn.getNext()) { if (insn.getOpcode() != Opcodes.PUTFIELD) continue; FieldInsnNode fn = (FieldInsnNode)insn; if (fn.desc.equals("Ljava/lang/String;")) { addFieldMapping("net/minecraft/block/Block unlocalizedName Ljava/lang/String;", block.name + " " + fn.name + " " + fn.desc); } } } methods = getMatchingMethods(block, null, "()Ljava/lang/String;"); for (Iterator<MethodNode> iterator = methods.iterator(); iterator.hasNext();) { MethodNode method = iterator.next(); if (method.name.equals("toString")) iterator.remove(); } if (methods.size() == 2) { for (MethodNode method : methods) { for (AbstractInsnNode insn = method.instructions.getFirst(); insn != null; insn = insn.getNext()) { // public String getLocalizedName() if (isLdcWithString(insn, ".name")) { addMethodMapping("net/minecraft/block/Block getLocalizedName ()Ljava/lang/String;", block.name + " " + method.name + " " + method.desc); } // public String getUnlocalizedName() else if (isLdcWithString(insn, "tile.")) { addMethodMapping("net/minecraft/block/Block getUnlocalizedName ()Ljava/lang/String;", block.name + " " + method.name + " " + method.desc); } } } } // public void onEntityCollidedWithBlock(World, BlockPos, Entity) methods = getMatchingMethods(block, null, assembleDescriptor("(", world, blockPos, entity, ")V")); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/Block onEntityCollidedWithBlock (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;Lnet/minecraft/entity/Entity;)V", block.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public IBlockState onBlockPlaced(World, BlockPos, EnumFacing, float, float, float, int, EntityLivingBase) methods = getMatchingMethods(block, null, assembleDescriptor("(", world, blockPos, enumFacing, "FFFI", entityLivingBase, ")", iBlockState)); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/Block onBlockPlaced (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;Lnet/minecraft/util/EnumFacing;FFFILnet/minecraft/entity/EntityLivingBase;)Lnet/minecraft/block/state/IBlockState;", block.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public void onBlockClicked(World, BlockPos, EntityPlayer) methods = getMatchingMethods(block, null, assembleDescriptor("(", world, blockPos, entityPlayer, ")V")); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/Block onBlockClicked (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;Lnet/minecraft/entity/player/EntityPlayer;)V", block.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // protected BlockState createBlockState() // public BlockState getBlockState() methods.clear(); if (blockStateClass != null) methods = getMatchingMethods(block, null, "()L" + blockStateClass + ";"); if (methods.size() == 2) { MethodNode createBlockState = null; startloop: for (MethodNode method : methods) { for (AbstractInsnNode insn = method.instructions.getFirst(); insn != null; insn = insn.getNext()) { if (insn.getOpcode() != Opcodes.NEW) continue; TypeInsnNode tn = (TypeInsnNode)insn; if (tn.desc.equals(blockStateClass)) { if (createBlockState != null) { createBlockState = null; break startloop; } createBlockState = method; break; } } } if (createBlockState != null) { addMethodMapping("net/minecraft/block/Block createBlockState ()Lnet/minecraft/block/state/BlockState;", block.name + " " + createBlockState.name + " " + createBlockState.desc); methods.remove(createBlockState); addMethodMapping("net/minecraft/block/Block getBlockState ()Lnet/minecraft/block/state/BlockState;", block.name + " " + methods.get(0).name + " " + methods.get(0).desc); } } methods = getMatchingMethods(block, null, "()V"); methods = removeMethodsWithoutFlags(methods, Opcodes.ACC_STATIC); for (Iterator<MethodNode> it = methods.iterator(); it.hasNext();) { if (it.next().name.contains("<")) it.remove(); } String objectIntIdentityMap = null; if (methods.size() == 1) { addMethodMapping("net/minecraft/block/Block registerBlocks ()V", block.name + " " + methods.get(0).name + " ()V"); for (AbstractInsnNode insn = methods.get(0).instructions.getFirst(); insn != null; insn = insn.getNext()) { if (insn.getOpcode() != Opcodes.INVOKEVIRTUAL) continue; MethodInsnNode mn = (MethodInsnNode)insn; if (mn.desc.equals("(Ljava/lang/Object;I)V")) { objectIntIdentityMap = mn.owner; addClassMapping("net/minecraft/util/ObjectIntIdentityMap", mn.owner); addMethodMapping("net/minecraft/util/ObjectIntIdentityMap put (Ljava/lang/Object;I)V", mn.owner + " " + mn.name + " " + mn.desc); } } List<FieldInsnNode> fieldNodes = getAllInsnNodesOfType(methods.get(0), FieldInsnNode.class); List<FieldInsnNode> fieldGets = new ArrayList<FieldInsnNode>(); List<FieldInsnNode> fieldPuts = new ArrayList<FieldInsnNode>(); for (Iterator<FieldInsnNode> it = fieldNodes.iterator(); it.hasNext();) { FieldInsnNode fn = it.next(); if (fn.owner.equals(block.name) && fn.desc.equals("Z")) { if (fn.getOpcode() == Opcodes.GETFIELD) fieldGets.add(fn); else if (fn.getOpcode() == Opcodes.PUTFIELD) fieldPuts.add(fn); } else it.remove(); } if (fieldGets.size() == 1 && fieldPuts.size() == 2 && fieldPuts.get(0).name.equals(fieldPuts.get(1).name)) { addFieldMapping("net/minecraft/block/Block translucent Z", block.name + " " + fieldGets.get(0).name + " Z"); addFieldMapping("net/minecraft/block/Block useNeighborBrightness Z", block.name + " " + fieldPuts.get(0).name + " Z"); } } List<FieldNode> fields = getMatchingFields(block, null, "L" + objectIntIdentityMap + ";"); if (fields.size() == 1) { addFieldMapping("net/minecraft/block/Block BLOCK_STATE_IDS Lnet/minecraft/util/ObjectIntIdentityMap;", block.name + " " + fields.get(0).name + " " + fields.get(0).desc); } return true; } @Mapping(provides={ "net/minecraft/item/ItemBlock", "net/minecraft/util/AxisAlignedBB" }, providesFields={ ////"net/minecraft/block/Block blockBounds Lnet/minecraft/util/AxisAlignedBB;" "net/minecraft/block/Block blockState Lnet/minecraft/block/state/BlockState;", "net/minecraft/block/Block displayOnCreativeTab Lnet/minecraft/creativetab/CreativeTabs;", "net/minecraft/entity/Entity motionY D" }, providesMethods={ "net/minecraft/block/Block getStateId (Lnet/minecraft/block/state/IBlockState;)I", "net/minecraft/block/Block getBlockById (I)Lnet/minecraft/block/Block;", "net/minecraft/block/Block getBlockFromItem (Lnet/minecraft/item/Item;)Lnet/minecraft/block/Block;", "net/minecraft/block/Block getBlockFromName (Ljava/lang/String;)Lnet/minecraft/block/Block;", //"net/minecraft/block/Block setBlockBounds (Lnet/minecraft/util/AxisAlignedBB;)V", //"net/minecraft/block/Block getBlockBounds (Lnet/minecraft/block/state/IBlockState;)Lnet/minecraft/util/AxisAlignedBB;", "net/minecraft/block/Block onNeighborBlockChange (Lnet/minecraft/block/state/IBlockState;Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;Lnet/minecraft/block/Block;Lnet/minecraft/util/BlockPos;)V", //"net/minecraft/block/Block setBlockBoundsBasedOnState (Lnet/minecraft/world/IBlockAccess;Lnet/minecraft/util/BlockPos;)V" "net/minecraft/block/Block setCreativeTab (Lnet/minecraft/creativetab/CreativeTabs;)Lnet/minecraft/block/Block;", "net/minecraft/block/Block dropBlockAsItemWithChance (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;Lnet/minecraft/block/state/IBlockState;FI)V", "net/minecraft/block/Block dropBlockAsItem (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;Lnet/minecraft/block/state/IBlockState;I)V", "net/minecraft/block/Block harvestBlock (Lnet/minecraft/world/World;Lnet/minecraft/entity/player/EntityPlayer;Lnet/minecraft/util/BlockPos;Lnet/minecraft/block/state/IBlockState;Lnet/minecraft/tileentity/TileEntity;Lnet/minecraft/item/ItemStack;)V", "net/minecraft/block/Block onFallenUpon (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;Lnet/minecraft/entity/Entity;F)V", "net/minecraft/entity/Entity fall (FF)V", "net/minecraft/block/Block onLanded (Lnet/minecraft/world/World;Lnet/minecraft/entity/Entity;)V", "net/minecraft/block/Block damageDropped (Lnet/minecraft/block/state/IBlockState;)I", "net/minecraft/block/Block isBlockSolid (Lnet/minecraft/world/IBlockAccess;Lnet/minecraft/util/BlockPos;Lnet/minecraft/util/EnumFacing;)Z" }, depends={ "net/minecraft/block/Block", "net/minecraft/item/Item", "net/minecraft/block/state/IBlockState", "net/minecraft/block/state/BlockState", "net/minecraft/util/BlockPos", "net/minecraft/world/World", "net/minecraft/world/IBlockAccess", "net/minecraft/creativetab/CreativeTabs", "net/minecraft/entity/player/EntityPlayer", "net/minecraft/tileentity/TileEntity", "net/minecraft/item/ItemStack", "net/minecraft/entity/Entity", "net/minecraft/util/EnumFacing" }) public boolean processBlockClass2() { ClassNode block = getClassNodeFromMapping("net/minecraft/block/Block"); ClassNode item = getClassNodeFromMapping("net/minecraft/item/Item"); ClassNode iBlockState = getClassNodeFromMapping("net/minecraft/block/state/IBlockState"); ClassNode blockState = getClassNodeFromMapping("net/minecraft/block/state/BlockState"); ClassNode blockPos = getClassNodeFromMapping("net/minecraft/util/BlockPos"); ClassNode world = getClassNodeFromMapping("net/minecraft/world/World"); ClassNode iBlockAccess = getClassNodeFromMapping("net/minecraft/world/IBlockAccess"); ClassNode creativeTabs = getClassNodeFromMapping("net/minecraft/creativetab/CreativeTabs"); ClassNode entityPlayer = getClassNodeFromMapping("net/minecraft/entity/player/EntityPlayer"); ClassNode tileEntity = getClassNodeFromMapping("net/minecraft/tileentity/TileEntity"); ClassNode itemStack = getClassNodeFromMapping("net/minecraft/item/ItemStack"); ClassNode entity = getClassNodeFromMapping("net/minecraft/entity/Entity"); ClassNode enumFacing = getClassNodeFromMapping("net/minecraft/util/EnumFacing"); if (!MeddleUtil.notNull(block, item, iBlockState, blockState, blockPos, world, iBlockAccess, creativeTabs, entityPlayer, tileEntity, itemStack, entity, enumFacing)) return false; List<MethodNode> methods; String axisAlignedBB_name = null; // net/minecraft/util/AxisAlignedBB // private AxisAlignedBB blockBounds List<FieldNode> fields = getMatchingFields(block, null, null); for (Iterator<FieldNode> it = fields.iterator(); it.hasNext(); ) { FieldNode fn = it.next(); if (!fn.desc.startsWith("L")) { it.remove(); continue; } Type t = Type.getType(fn.desc); if (axisAlignedBB_name == null && searchConstantPoolForStrings(t.getClassName(), "box[")) { ClassNode cn = getClassNode(t.getClassName()); int doubles = 0; for (FieldNode cnfn : cn.fields) { if (cnfn.desc.equals("D")) doubles++; } if (cn.fields.size() == 6 && doubles == 6) { axisAlignedBB_name = t.getClassName(); addClassMapping("net/minecraft/util/AxisAlignedBB", axisAlignedBB_name); } } if (axisAlignedBB_name == null || !t.getClassName().equals(axisAlignedBB_name)) it.remove(); } if (fields.size() == 1) { addFieldMapping("net/minecraft/block/Block blockBounds Lnet/minecraft/util/AxisAlignedBB;", block.name + " " + fields.get(0).name + " " + fields.get(0).desc); } fields = getMatchingFields(block, null, "L" + blockState.name + ";"); if (fields.size() == 1) { addFieldMapping("net/minecraft/block/Block blockState Lnet/minecraft/block/state/BlockState;", block.name + " " + fields.get(0).name + " " + fields.get(0).desc); } // public static int getStateId(IBlockState) methods = getMatchingMethods(block, null, "(L" + iBlockState.name + ";)I"); methods = removeMethodsWithoutFlags(methods, Opcodes.ACC_STATIC); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/Block getStateId (Lnet/minecraft/block/state/IBlockState;)I", block.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public static Block getBlockById(int) methods = getMatchingMethods(block, null, "(I)L" + block.name + ";"); methods = removeMethodsWithoutFlags(methods, Opcodes.ACC_STATIC); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/Block getBlockById (I)Lnet/minecraft/block/Block;", block.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public static Block getBlockFromItem(Item) methods = getMatchingMethods(block, null, "(L" + item.name + ";)L" + block.name + ";"); methods = removeMethodsWithoutFlags(methods, Opcodes.ACC_STATIC); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/Block getBlockFromItem (Lnet/minecraft/item/Item;)Lnet/minecraft/block/Block;", block.name + " " + methods.get(0).name + " " + methods.get(0).desc); for (AbstractInsnNode insn = methods.get(0).instructions.getFirst(); insn != null; insn = insn.getNext()) { if (insn.getOpcode() != Opcodes.INSTANCEOF) continue; TypeInsnNode tn = (TypeInsnNode)insn; if (searchConstantPoolForStrings(tn.desc, "BlockEntityTag")) { addClassMapping("net/minecraft/item/ItemBlock", tn.desc); break; } } } // public static Block getBlockFromName(String) methods = getMatchingMethods(block, null, "(Ljava/lang/String;)L" + block.name + ";"); methods = removeMethodsWithoutFlags(methods, Opcodes.ACC_STATIC); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/Block getBlockFromName (Ljava/lang/String;)Lnet/minecraft/block/Block;", block.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // protected final void setBlockBounds(float, float, float, float, float, float) // CHANGED in 15w37a // public void setBlockBounds(AxisAlignedBB param0) methods = getMatchingMethods(block, null, "(L" + axisAlignedBB_name + ";)V"); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/Block setBlockBounds (Lnet/minecraft/util/AxisAlignedBB;)V", block.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // NEW in 15w37a // public AxisAlignedBB getBlockBounds(IBlockState param0) methods = getMatchingMethods(block, null, "(L" + iBlockState.name + ";)L" + axisAlignedBB_name + ";"); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/Block getBlockBounds (Lnet/minecraft/block/state/IBlockState;)Lnet/minecraft/util/AxisAlignedBB;", block.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public void onNeighborBlockChange(IBlockState, World, BlockPos, Block) methods = getMatchingMethods(block, null, assembleDescriptor("(", iBlockState, world, blockPos, block, blockPos, ")V")); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/Block onNeighborBlockChange (Lnet/minecraft/block/state/IBlockState;Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;Lnet/minecraft/block/Block;Lnet/minecraft/util/BlockPos;)V", block.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public void setBlockBoundsBasedOnState(IBlockAccess param0, BlockPos param1) methods = getMatchingMethods(block, null, assembleDescriptor("(", iBlockAccess, blockPos, ")V")); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/Block setBlockBoundsBasedOnState (Lnet/minecraft/world/IBlockAccess;Lnet/minecraft/util/BlockPos;)V", block.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public Block setCreativeTab(CreativeTabs tab) methods = getMatchingMethods(block, null, assembleDescriptor("(", creativeTabs, ")", block)); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/Block setCreativeTab (Lnet/minecraft/creativetab/CreativeTabs;)Lnet/minecraft/block/Block;", block.name + " " + methods.get(0).name + " " + methods.get(0).desc); List<FieldInsnNode> nodes = getAllInsnNodesOfType(methods.get(0), FieldInsnNode.class); if (nodes.size() == 1 && nodes.get(0).owner.equals(block.name) && nodes.get(0).desc.equals("L" + creativeTabs.name + ";")) { addFieldMapping("net/minecraft/block/Block displayOnCreativeTab Lnet/minecraft/creativetab/CreativeTabs;", block.name + " " + nodes.get(0).name + " " + nodes.get(0).desc); } } // public final void dropBlockAsItem(World worldIn, BlockPos pos, IBlockState state, int forture) methods = getMatchingMethods(block, null, assembleDescriptor("(", world, blockPos, iBlockState, "I)V")); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/Block dropBlockAsItem (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;Lnet/minecraft/block/state/IBlockState;I)V", block.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public void dropBlockAsItemWithChance(World worldIn, BlockPos pos, IBlockState state, float chance, int fortune) // public int damageDropped(IBlockState state) methods = getMatchingMethods(block, null, assembleDescriptor("(", world, blockPos, iBlockState, "FI)V")); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/Block dropBlockAsItemWithChance (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;Lnet/minecraft/block/state/IBlockState;FI)V", block.name + " " + methods.get(0).name + " " + methods.get(0).desc); List<MethodInsnNode> nodes = getAllInsnNodesOfType(methods.get(0), MethodInsnNode.class); for (Iterator<MethodInsnNode> it = nodes.iterator(); it.hasNext();) { MethodInsnNode mn = it.next(); if (mn.owner.equals(block.name) && mn.desc.equals("(L" + iBlockState.name + ";)I")) continue; it.remove(); } if (nodes.size() == 1) { addMethodMapping("net/minecraft/block/Block damageDropped (Lnet/minecraft/block/state/IBlockState;)I", block.name + " " + nodes.get(0).name + " " + nodes.get(0).desc); } } // public void harvestBlock(World param0, EntityPlayer param1, BlockPos param2, IBlockState param3, TileEntity param4, ItemStack param5) methods = getMatchingMethods(block, null, assembleDescriptor("(", world, entityPlayer, blockPos, iBlockState, tileEntity, itemStack, ")V")); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/Block harvestBlock (Lnet/minecraft/world/World;Lnet/minecraft/entity/player/EntityPlayer;Lnet/minecraft/util/BlockPos;Lnet/minecraft/block/state/IBlockState;Lnet/minecraft/tileentity/TileEntity;Lnet/minecraft/item/ItemStack;)V", block.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public void onFallenUpon(World param0, BlockPos param1, Entity param2, float param3) methods = getMatchingMethods(block, null, assembleDescriptor("(", world, blockPos, entity, "F)V")); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/Block onFallenUpon (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;Lnet/minecraft/entity/Entity;F)V", block.name + " " + methods.get(0).name + " " + methods.get(0).desc); List<MethodInsnNode> nodes = getAllInsnNodesOfType(methods.get(0), MethodInsnNode.class); if (nodes.size() == 1) { MethodInsnNode mn = nodes.get(0); if (mn.owner.equals(entity.name) && mn.desc.equals("(FF)V")) { addMethodMapping("net/minecraft/entity/Entity fall (FF)V", entity.name + " " + mn.name + " " + mn.desc); } } } // public void onLanded(World param0, Entity param1) methods = getMatchingMethods(block, null, assembleDescriptor("(", world, entity, ")V")); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/Block onLanded (Lnet/minecraft/world/World;Lnet/minecraft/entity/Entity;)V", block.name + " " + methods.get(0).name + " " + methods.get(0).desc); List<FieldInsnNode> nodes = getAllInsnNodesOfType(methods.get(0), FieldInsnNode.class); if (nodes.size() == 1) { FieldInsnNode fn = nodes.get(0); if (fn.owner.equals(entity.name) && fn.desc.equals("D")) { addFieldMapping("net/minecraft/entity/Entity motionY D", entity.name + " " + fn.name + " " + fn.desc); } } } // public boolean isBlockSolid(IBlockAccess param0, BlockPos param1, EnumFacing param2) methods = getMatchingMethods(block, null, assembleDescriptor("(", iBlockAccess, blockPos, enumFacing, ")Z")); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/Block isBlockSolid (Lnet/minecraft/world/IBlockAccess;Lnet/minecraft/util/BlockPos;Lnet/minecraft/util/EnumFacing;)Z", block.name + " " + methods.get(0).name + " " + methods.get(0).desc); } return true; } @Mapping(provides={ "net/minecraft/block/EnumBlockRotation", "net/minecraft/block/EnumBlockMirroring" }, providesFields={ "net/minecraft/block/Block blockMaterial Lnet/minecraft/block/material/Material;", "net/minecraft/block/Block mapColor Lnet/minecraft/block/material/MapColor;", "net/minecraft/block/Block lightOpacity I", "net/minecraft/block/Block lightValue I", "net/minecraft/block/Block blockResistance F", "net/minecraft/block/Block stepSound Lnet/minecraft/block/BlockSoundType;" }, providesMethods={ "net/minecraft/block/Block getMaterial (Lnet/minecraft/block/state/IBlockState;)Lnet/minecraft/block/material/Material;", "net/minecraft/block/Block getMapColor (Lnet/minecraft/block/state/IBlockState;)Lnet/minecraft/block/material/MapColor;", "net/minecraft/block/Block getStateFromRotation (Lnet/minecraft/block/state/IBlockState;Lnet/minecraft/block/EnumBlockRotation;)Lnet/minecraft/block/state/IBlockState;", "net/minecraft/block/Block getStateFromMirroring (Lnet/minecraft/block/state/IBlockState;Lnet/minecraft/block/EnumBlockMirroring;)Lnet/minecraft/block/state/IBlockState;", "net/minecraft/block/Block setLightOpacity (I)Lnet/minecraft/block/Block;", "net/minecraft/block/Block setLightLevel (F)Lnet/minecraft/block/Block;", "net/minecraft/block/Block setResistance (F)Lnet/minecraft/block/Block;", "net/minecraft/block/Block getStepSound ()Lnet/minecraft/block/BlockSoundType;", "net/minecraft/block/Block getComparatorInputOverride (Lnet/minecraft/block/state/IBlockState;Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;)I", "net/minecraft/block/Block isEqualTo (Lnet/minecraft/block/Block;Lnet/minecraft/block/Block;)Z", "net/minecraft/block/Block isAssociatedBlock (Lnet/minecraft/block/Block;)Z", "net/minecraft/block/Block canDropFromExplosion (Lnet/minecraft/world/Explosion;)Z", "net/minecraft/block/Block fillWithRain (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;)V", "net/minecraft/block/Block onBlockHarvested (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;Lnet/minecraft/block/state/IBlockState;Lnet/minecraft/entity/player/EntityPlayer;)V", "net/minecraft/block/Block onBlockPlacedBy (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;Lnet/minecraft/block/state/IBlockState;Lnet/minecraft/entity/EntityLivingBase;Lnet/minecraft/item/ItemStack;)V", "net/minecraft/block/Block quantityDroppedWithBonus (ILjava/util/Random;)I", "net/minecraft/block/Block quantityDropped (Ljava/util/Random;)I", "net/minecraft/block/Block createStackedBlock (Lnet/minecraft/block/state/IBlockState;)Lnet/minecraft/item/ItemStack;", "net/minecraft/item/Item getHasSubtypes ()Z", "net/minecraft/block/Block modifyAcceleration (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;Lnet/minecraft/entity/Entity;Lnet/minecraft/util/Vec3;)Lnet/minecraft/util/Vec3;", //"net/minecraft/block/Block canReplace (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;Lnet/minecraft/util/EnumFacing;Lnet/minecraft/item/ItemStack;)Z", "net/minecraft/block/Block canPlaceBlockOnSide (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;Lnet/minecraft/util/EnumFacing;)Z", "net/minecraft/block/Block canPlaceBlockAt (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;)Z", "net/minecraft/block/Block onBlockDestroyedByExplosion (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;Lnet/minecraft/world/Explosion;)V", "net/minecraft/block/Block getExplosionResistance (Lnet/minecraft/entity/Entity;)F", "net/minecraft/block/Block dropXpOnBlockBreak (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;I)V", "net/minecraft/block/Block getPlayerRelativeBlockHardness (Lnet/minecraft/block/state/IBlockState;Lnet/minecraft/entity/player/EntityPlayer;Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;)F", "net/minecraft/entity/player/EntityPlayer canHarvestBlock (Lnet/minecraft/block/state/IBlockState;)Z", "net/minecraft/entity/player/EntityPlayer getToolDigEfficiency (Lnet/minecraft/block/state/IBlockState;)F", "net/minecraft/block/Block getItemDropped (Lnet/minecraft/block/state/IBlockState;Ljava/util/Random;I)Lnet/minecraft/item/Item;", "net/minecraft/block/Block randomTick (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;Lnet/minecraft/block/state/IBlockState;Ljava/util/Random;)V", "net/minecraft/block/Block updateTick (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;Lnet/minecraft/block/state/IBlockState;Ljava/util/Random;)V", "net/minecraft/block/Block addCollisionBoxesToList (Lnet/minecraft/block/state/IBlockState;Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;Lnet/minecraft/util/AxisAlignedBB;Ljava/util/List;Lnet/minecraft/entity/Entity;)V", "net/minecraft/block/state/IBlockWrapper getCollisionBoundingBox (Lnet/minecraft/world/IBlockAccess;Lnet/minecraft/util/BlockPos;)Lnet/minecraft/util/AxisAlignedBB;", "net/minecraft/block/Block addCollisionBoxToList (Lnet/minecraft/util/BlockPos;Lnet/minecraft/util/AxisAlignedBB;Ljava/util/List;Lnet/minecraft/util/AxisAlignedBB;)V", "net/minecraft/block/Block rayTrace (Lnet/minecraft/util/BlockPos;Lnet/minecraft/util/Vec3;Lnet/minecraft/util/Vec3;Lnet/minecraft/util/AxisAlignedBB;)Lnet/minecraft/util/MovingObjectPosition;" }, depends={ "net/minecraft/block/Block", "net/minecraft/item/Item", "net/minecraft/block/state/IBlockState", "net/minecraft/block/state/BlockState", "net/minecraft/util/BlockPos", "net/minecraft/world/World", "net/minecraft/world/IBlockAccess", "net/minecraft/creativetab/CreativeTabs", "net/minecraft/entity/player/EntityPlayer", "net/minecraft/tileentity/TileEntity", "net/minecraft/item/ItemStack", "net/minecraft/block/material/Material", "net/minecraft/block/material/MapColor", "net/minecraft/block/BlockSoundType", "net/minecraft/world/Explosion", "net/minecraft/entity/EntityLivingBase", "net/minecraft/util/EnumFacing", "net/minecraft/entity/Entity", "net/minecraft/util/Vec3", "net/minecraft/util/AxisAlignedBB", "net/minecraft/block/state/IBlockWrapper" }) public boolean processBlockClass3() { ClassNode block = getClassNodeFromMapping("net/minecraft/block/Block"); ClassNode item = getClassNodeFromMapping("net/minecraft/item/Item"); ClassNode iBlockState = getClassNodeFromMapping("net/minecraft/block/state/IBlockState"); ClassNode blockState = getClassNodeFromMapping("net/minecraft/block/state/BlockState"); ClassNode blockPos = getClassNodeFromMapping("net/minecraft/util/BlockPos"); ClassNode world = getClassNodeFromMapping("net/minecraft/world/World"); ClassNode iBlockAccess = getClassNodeFromMapping("net/minecraft/world/IBlockAccess"); ClassNode creativeTabs = getClassNodeFromMapping("net/minecraft/creativetab/CreativeTabs"); ClassNode entityPlayer = getClassNodeFromMapping("net/minecraft/entity/player/EntityPlayer"); ClassNode tileEntity = getClassNodeFromMapping("net/minecraft/tileentity/TileEntity"); ClassNode itemStack = getClassNodeFromMapping("net/minecraft/item/ItemStack"); ClassNode material = getClassNodeFromMapping("net/minecraft/block/material/Material"); ClassNode mapColor = getClassNodeFromMapping("net/minecraft/block/material/MapColor"); ClassNode blockSoundType = getClassNodeFromMapping("net/minecraft/block/BlockSoundType"); ClassNode explosion = getClassNodeFromMapping("net/minecraft/world/Explosion"); ClassNode entityLivingBase = getClassNodeFromMapping("net/minecraft/entity/EntityLivingBase"); ClassNode enumFacing = getClassNodeFromMapping("net/minecraft/util/EnumFacing"); ClassNode entity = getClassNodeFromMapping("net/minecraft/entity/Entity"); ClassNode vec3 = getClassNodeFromMapping("net/minecraft/util/Vec3"); ClassNode aabb = getClassNodeFromMapping("net/minecraft/util/AxisAlignedBB"); ClassNode iBlockWrapper = getClassNodeFromMapping("net/minecraft/block/state/IBlockWrapper"); ClassNode mop = getClassNodeFromMapping("net/minecraft/util/MovingObjectPosition"); if (!MeddleUtil.notNull(block, item, iBlockState, blockState, blockPos, world, iBlockAccess, creativeTabs, entityPlayer, tileEntity, itemStack, material, mapColor, blockSoundType, explosion, entityLivingBase, enumFacing, entity, vec3, aabb, iBlockWrapper)) return false; // public Material getMaterial(IBlockState) List<MethodNode> methods = getMatchingMethods(block, null, assembleDescriptor("(", iBlockState, ")", material)); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/Block getMaterial (Lnet/minecraft/block/state/IBlockState;)Lnet/minecraft/block/material/Material;", block.name + " " + methods.get(0).name + " " + methods.get(0).desc); List<FieldInsnNode> nodes = getAllInsnNodesOfType(methods.get(0), FieldInsnNode.class); if (nodes.size() == 1 && nodes.get(0).owner.equals(block.name) && nodes.get(0).desc.equals("L" + material.name + ";")) { addFieldMapping("net/minecraft/block/Block blockMaterial Lnet/minecraft/block/material/Material;", block.name + " " + nodes.get(0).name + " " + nodes.get(0).desc); } } methods = getMatchingMethods(block, null, assembleDescriptor("(", blockPos, vec3, vec3, aabb, ")", mop)); if(methods.size() == 1){ addMethodMapping("net/minecraft/block/Block rayTrace (Lnet/minecraft/util/BlockPos;Lnet/minecraft/util/Vec3;Lnet/minecraft/util/Vec3;Lnet/minecraft/util/AxisAlignedBB;)Lnet/minecraft/util/MovingObjectPosition;", block.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public MapColor getMapColor(IBlockState state) methods = getMatchingMethods(block, null, assembleDescriptor("(", iBlockState, ")", mapColor)); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/Block getMapColor (Lnet/minecraft/block/state/IBlockState;)Lnet/minecraft/block/material/MapColor;", block.name + " " + methods.get(0).name + " " + methods.get(0).desc); List<FieldInsnNode> nodes = getAllInsnNodesOfType(methods.get(0), FieldInsnNode.class); if (nodes.size() == 1 && nodes.get(0).owner.equals(block.name) && nodes.get(0).desc.equals("L" + mapColor.name + ";")) { addFieldMapping("net/minecraft/block/Block mapColor Lnet/minecraft/block/material/MapColor;", block.name + " " + nodes.get(0).name + " " + nodes.get(0).desc); } } // public IBlockState getStateFromRotation(IBlockState param0, EnumBlockRotation param1) // public IBlockState getStateFromMirroring(IBlockState param0, EnumBlockMirroring param1) methods.clear(); for (MethodNode method : block.methods) { if (method.desc.startsWith("(L" + iBlockState.name + ";L") && method.desc.endsWith(";)L" + iBlockState.name + ";") && Type.getMethodType(method.desc).getArgumentTypes().length == 2) methods.add(method); } if (methods.size() == 2 && !methods.get(0).desc.equals(methods.get(1).desc)) { for (MethodNode method : methods) { String className = Type.getMethodType(method.desc).getArgumentTypes()[1].getClassName(); if (searchConstantPoolForStrings(className, "rotate_0", "rotate_90")) { addClassMapping("net/minecraft/block/EnumBlockRotation", className); addMethodMapping("net/minecraft/block/Block getStateFromRotation (Lnet/minecraft/block/state/IBlockState;Lnet/minecraft/block/EnumBlockRotation;)Lnet/minecraft/block/state/IBlockState;", block.name + " " + method.name + " " + method.desc); } else if (searchConstantPoolForStrings(className, "no_mirror", "mirror_left_right")) { addClassMapping("net/minecraft/block/EnumBlockMirroring", className); addMethodMapping("net/minecraft/block/Block getStateFromMirroring (Lnet/minecraft/block/state/IBlockState;Lnet/minecraft/block/EnumBlockMirroring;)Lnet/minecraft/block/state/IBlockState;", block.name + " " + method.name + " " + method.desc); } } } // protected Block setLightOpacity(int opacity) methods = getMatchingMethods(block, null, "(I)L" + block.name + ";"); methods = removeMethodsWithFlags(methods, Opcodes.ACC_STATIC); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/Block setLightOpacity (I)Lnet/minecraft/block/Block;", block.name + " " + methods.get(0).name + " " + methods.get(0).desc); List<FieldInsnNode> nodes = getAllInsnNodesOfType(methods.get(0), FieldInsnNode.class); if (nodes.size() == 1 && nodes.get(0).owner.equals(block.name) && nodes.get(0).desc.equals("I")) { addFieldMapping("net/minecraft/block/Block lightOpacity I", block.name + " " + nodes.get(0).name + " " + nodes.get(0).desc); } } // protected Block setLightLevel(float value) // public Block setResistance(float resistance) methods = getMatchingMethods(block, null, "(F)L" + block.name + ";"); int setLightLevel_num = -1; int setResistance_num = -1; for (int n = 0; n < methods.size(); n++) { MethodNode method = methods.get(n); for (AbstractInsnNode insn = method.instructions.getFirst(); insn != null; insn = insn.getNext()) { if (isLdcWithFloat(insn, 15F)) { if (setLightLevel_num == -1) setLightLevel_num = n; else setLightLevel_num = -2; } else if (isLdcWithFloat(insn, 3F)) { if (setResistance_num == -1) setResistance_num = n; else setResistance_num = -2; } } } if (setLightLevel_num >= 0) { addMethodMapping("net/minecraft/block/Block setLightLevel (F)Lnet/minecraft/block/Block;", block.name + " " + methods.get(setLightLevel_num).name + " " + methods.get(setLightLevel_num).desc); List<FieldInsnNode> nodes = getAllInsnNodesOfType(methods.get(setLightLevel_num), FieldInsnNode.class); if (nodes.size() == 1 && nodes.get(0).owner.equals(block.name) && nodes.get(0).desc.equals("I")) { addFieldMapping("net/minecraft/block/Block lightValue I", block.name + " " + nodes.get(0).name + " " + nodes.get(0).desc); } } if (setResistance_num >= 0) { addMethodMapping("net/minecraft/block/Block setResistance (F)Lnet/minecraft/block/Block;", block.name + " " + methods.get(setResistance_num).name + " " + methods.get(setResistance_num).desc); List<FieldInsnNode> nodes = getAllInsnNodesOfType(methods.get(setResistance_num), FieldInsnNode.class); if (nodes.size() == 1 && nodes.get(0).owner.equals(block.name) && nodes.get(0).desc.equals("F")) { addFieldMapping("net/minecraft/block/Block blockResistance F", block.name + " " + nodes.get(0).name + " " + nodes.get(0).desc); } } // public BlockSoundType getStepSound() methods = getMatchingMethods(block, null, "()L" + blockSoundType.name + ";"); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/Block getStepSound ()Lnet/minecraft/block/BlockSoundType;", block.name + " " + methods.get(0).name + " " + methods.get(0).desc); List<FieldInsnNode> nodes = getAllInsnNodesOfType(methods.get(0), FieldInsnNode.class); if (nodes.size() == 1 && nodes.get(0).owner.equals(block.name) && nodes.get(0).desc.equals("L" + blockSoundType.name + ";")) { addFieldMapping("net/minecraft/block/Block stepSound Lnet/minecraft/block/BlockSoundType;", block.name + " " + nodes.get(0).name + " " + nodes.get(0).desc); } } // public int getComparatorInputOverride(IBlockState param0, World worldIn, BlockPos pos) methods = getMatchingMethods(block, null, assembleDescriptor("(", iBlockState, world, blockPos, ")I")); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/Block getComparatorInputOverride (Lnet/minecraft/block/state/IBlockState;Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;)I", block.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public static boolean isEqualTo(Block blockIn, Block other) methods = getMatchingMethods(block, null, assembleDescriptor("(", block, block, ")Z")); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/Block isEqualTo (Lnet/minecraft/block/Block;Lnet/minecraft/block/Block;)Z", block.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public boolean isAssociatedBlock(Block other) methods = getMatchingMethods(block, null, assembleDescriptor("(", block, ")Z")); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/Block isAssociatedBlock (Lnet/minecraft/block/Block;)Z", block.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public boolean canDropFromExplosion(Explosion explosionIn) methods = getMatchingMethods(block, null, assembleDescriptor("(", explosion, ")Z")); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/Block canDropFromExplosion (Lnet/minecraft/world/Explosion;)Z", block.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public void fillWithRain(World worldIn, BlockPos pos) methods = getMatchingMethods(block, null, assembleDescriptor("(", world, blockPos, ")V")); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/Block fillWithRain (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;)V", block.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public void onBlockHarvested(World worldIn, BlockPos pos, IBlockState state, EntityPlayer player) methods = getMatchingMethods(block, null, assembleDescriptor("(", world, blockPos, iBlockState, entityPlayer, ")V")); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/Block onBlockHarvested (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;Lnet/minecraft/block/state/IBlockState;Lnet/minecraft/entity/player/EntityPlayer;)V", block.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public void onBlockPlacedBy(World param0, BlockPos param1, IBlockState param2, EntityLivingBase param3, ItemStack param4) methods = getMatchingMethods(block, null, assembleDescriptor("(", world, blockPos, iBlockState, entityLivingBase, itemStack, ")V")); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/Block onBlockPlacedBy (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;Lnet/minecraft/block/state/IBlockState;Lnet/minecraft/entity/EntityLivingBase;Lnet/minecraft/item/ItemStack;)V", block.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public int quantityDroppedWithBonus(int fortune, Random random) methods = getMatchingMethods(block, null, "(ILjava/util/Random;)I"); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/Block quantityDroppedWithBonus (ILjava/util/Random;)I", block.name + " " + methods.get(0).name + " " + methods.get(0).desc); List<MethodInsnNode> nodes = getAllInsnNodesOfType(methods.get(0), MethodInsnNode.class); if (nodes.size() == 1 && nodes.get(0).owner.equals(block.name) && nodes.get(0).desc.equals("(Ljava/util/Random;)I")) { addMethodMapping("net/minecraft/block/Block quantityDropped (Ljava/util/Random;)I", block.name + " " + nodes.get(0).name + " " + nodes.get(0).desc); } } // protected ItemStack createStackedBlock(IBlockState param0) methods = getMatchingMethods(block, null, assembleDescriptor("(", iBlockState, ")", itemStack)); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/Block createStackedBlock (Lnet/minecraft/block/state/IBlockState;)Lnet/minecraft/item/ItemStack;", block.name + " " + methods.get(0).name + " " + methods.get(0).desc); List<MethodInsnNode> nodes = getAllInsnNodesOfType(methods.get(0), MethodInsnNode.class); for (Iterator<MethodInsnNode> it = nodes.iterator(); it.hasNext(); ) { MethodInsnNode mn = it.next(); if (mn.owner.equals(item.name) && mn.desc.equals("()Z")) continue; it.remove(); } if (nodes.size() == 1) { addMethodMapping("net/minecraft/item/Item getHasSubtypes ()Z", item.name + " " + nodes.get(0).name + " ()Z"); } } // public Vec3 modifyAcceleration(World worldIn, BlockPos pos, Entity entityIn, Vec3 motion) methods = getMatchingMethods(block, null, assembleDescriptor("(", world, blockPos, entity, vec3, ")", vec3)); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/Block modifyAcceleration (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;Lnet/minecraft/entity/Entity;Lnet/minecraft/util/Vec3;)Lnet/minecraft/util/Vec3;", block.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public boolean canReplace(World worldIn, BlockPos pos, EnumFacing side, ItemStack stack) // Apparently removed in 16w32a //methods = getMatchingMethods(block, null, assembleDescriptor("(", world, blockPos, enumFacing, itemStack, ")Z")); //if (methods.size() == 1) { //addMethodMapping("net/minecraft/block/Block canReplace (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;Lnet/minecraft/util/EnumFacing;Lnet/minecraft/item/ItemStack;)Z", //block.name + " " + methods.get(0).name + " " + methods.get(0).desc); //} // public boolean canPlaceBlockOnSide(World worldIn, BlockPos pos, EnumFacing side) // public boolean canPlaceBlockAt(World worldIn, BlockPos pos) methods = getMatchingMethods(block, null, assembleDescriptor("(", world, blockPos, enumFacing, ")Z")); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/Block canPlaceBlockOnSide (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;Lnet/minecraft/util/EnumFacing;)Z", block.name + " " + methods.get(0).name + " " + methods.get(0).desc); List<MethodInsnNode> nodes = getAllInsnNodesOfType(methods.get(0), MethodInsnNode.class); if (nodes.size() == 1 && nodes.get(0).owner.equals(block.name) && nodes.get(0).desc.equals(assembleDescriptor("(", world, blockPos, ")Z"))) { addMethodMapping("net/minecraft/block/Block canPlaceBlockAt (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;)Z", block.name + " " + nodes.get(0).name + " " + nodes.get(0).desc); } } // public void onBlockDestroyedByExplosion(World worldIn, BlockPos pos, Explosion explosionIn) methods = getMatchingMethods(block, null, assembleDescriptor("(", world, blockPos, explosion, ")V")); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/Block onBlockDestroyedByExplosion (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;Lnet/minecraft/world/Explosion;)V", block.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public float getExplosionResistance(Entity exploder) methods = getMatchingMethods(block, null, assembleDescriptor("(", entity, ")F")); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/Block getExplosionResistance (Lnet/minecraft/entity/Entity;)F", block.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // protected void dropXpOnBlockBreak(World worldIn, BlockPos pos, int amount) methods = getMatchingMethods(block, null, assembleDescriptor("(", world, blockPos, "I)V")); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/Block dropXpOnBlockBreak (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;I)V", block.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public float getPlayerRelativeBlockHardness(IBlockState param0, EntityPlayer playerIn, World worldIn, BlockPos pos) methods = getMatchingMethods(block, null, assembleDescriptor("(", iBlockState, entityPlayer, world, blockPos, ")F")); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/Block getPlayerRelativeBlockHardness (Lnet/minecraft/block/state/IBlockState;Lnet/minecraft/entity/player/EntityPlayer;Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;)F", block.name + " " + methods.get(0).name + " " + methods.get(0).desc); List<MethodInsnNode> nodes = getAllInsnNodesOfType(methods.get(0), MethodInsnNode.class); List<MethodInsnNode> getBlockHardness = new ArrayList<>(); List<MethodInsnNode> canHarvestBlock = new ArrayList<>(); List<MethodInsnNode> getToolDigEfficiency = new ArrayList<>(); for (MethodInsnNode mn : nodes) { //if (mn.owner.equals(iBlockState.name) && mn.desc.equals(assembleDescriptor("(", world, blockPos, ")F"))) getBlockHardness.add(mn); if (mn.owner.equals(entityPlayer.name)) { if (mn.desc.equals(assembleDescriptor("(", iBlockState, ")Z"))) canHarvestBlock.add(mn); else if (mn.desc.equals(assembleDescriptor("(", iBlockState, ")F"))) getToolDigEfficiency.add(mn); } } /*if (getBlockHardness.size() == 1) { addMethodMapping("net/minecraft/block/state/IBlockState getBlockHardness (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;)F", iBlockState.name + " " + getBlockHardness.get(0).name + " " + getBlockHardness.get(0).desc); }*/ if (canHarvestBlock.size() == 1) { addMethodMapping("net/minecraft/entity/player/EntityPlayer canHarvestBlock (Lnet/minecraft/block/state/IBlockState;)Z", entityPlayer.name + " " + canHarvestBlock.get(0).name + " " + canHarvestBlock.get(0).desc); } if (getToolDigEfficiency.size() == 2 && getToolDigEfficiency.get(0).name.equals(getToolDigEfficiency.get(1).name)) { addMethodMapping("net/minecraft/entity/player/EntityPlayer getToolDigEfficiency (Lnet/minecraft/block/state/IBlockState;)F", entityPlayer.name + " " + getToolDigEfficiency.get(0).name + " " + getToolDigEfficiency.get(0).desc); } } // public Item getItemDropped(IBlockState state, Random rand, int fortune) methods = getMatchingMethods(block, null, assembleDescriptor("(", iBlockState, "Ljava/util/Random;I)", item)); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/Block getItemDropped (Lnet/minecraft/block/state/IBlockState;Ljava/util/Random;I)Lnet/minecraft/item/Item;", block.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public void randomTick(World worldIn, BlockPos pos, IBlockState state, Random random) // public void updateTick(World worldIn, BlockPos pos, IBlockState state, Random random) methods = getMatchingMethods(block, null, assembleDescriptor("(", world, blockPos, iBlockState, "Ljava/util/Random;)V")); if (methods.size() == 2) { for (Iterator<MethodNode> it = methods.iterator(); it.hasNext();) { if (getNextRealOpcode(it.next().instructions.getFirst()).getOpcode() == Opcodes.RETURN) it.remove(); } if (methods.size() == 1) { List<MethodInsnNode> nodes = getAllInsnNodesOfType(methods.get(0), MethodInsnNode.class); if (nodes.size() == 1 && nodes.get(0).owner.equals(block.name) && !nodes.get(0).name.equals(methods.get(0).name) && nodes.get(0).desc.equals(methods.get(0).desc)) { addMethodMapping("net/minecraft/block/Block randomTick (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;Lnet/minecraft/block/state/IBlockState;Ljava/util/Random;)V", block.name + " " + methods.get(0).name + " " + methods.get(0).desc); addMethodMapping("net/minecraft/block/Block updateTick (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;Lnet/minecraft/block/state/IBlockState;Ljava/util/Random;)V", block.name + " " + nodes.get(0).name + " " + nodes.get(0).desc); } } } // public void addCollisionBoxesToList(IBlockState param0, World param1, BlockPos param2, AxisAlignedBB param3, List<AxisAlignedBB> param4, Entity param5) methods = getMatchingMethods(block, null, assembleDescriptor("(", iBlockState, world, blockPos, aabb, "Ljava/util/List;", entity, ")V")); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/Block addCollisionBoxesToList (Lnet/minecraft/block/state/IBlockState;Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;Lnet/minecraft/util/AxisAlignedBB;Ljava/util/List;Lnet/minecraft/entity/Entity;)V", block.name + " " + methods.get(0).name + " " + methods.get(0).desc); List<MethodInsnNode> nodes = getAllInsnNodesOfType(methods.get(0), MethodInsnNode.class); List<MethodInsnNode> getCollisionBoundingBox = new ArrayList<>(); List<MethodInsnNode> addCollisionBoxToList = new ArrayList<>(); for (MethodInsnNode mn : nodes) { if (mn.owner.equals(block.name)) { if (mn.desc.equals(assembleDescriptor("(", blockPos, aabb, "Ljava/util/List;", aabb, ")V"))) addCollisionBoxToList.add(mn); } else if (mn.owner.equals(iBlockState.name)) { if (mn.desc.equals(assembleDescriptor("(", iBlockAccess, blockPos, ")", aabb))) getCollisionBoundingBox.add(mn); } } if (getCollisionBoundingBox.size() == 1) { addMethodMapping("net/minecraft/block/state/IBlockWrapper getCollisionBoundingBox (Lnet/minecraft/world/IBlockAccess;Lnet/minecraft/util/BlockPos;)Lnet/minecraft/util/AxisAlignedBB;", iBlockWrapper.name + " " + getCollisionBoundingBox.get(0).name + " " + getCollisionBoundingBox.get(0).desc); } if (addCollisionBoxToList.size() == 1) { addMethodMapping("net/minecraft/block/Block addCollisionBoxToList (Lnet/minecraft/util/BlockPos;Lnet/minecraft/util/AxisAlignedBB;Ljava/util/List;Lnet/minecraft/util/AxisAlignedBB;)V", block.name + " " + addCollisionBoxToList.get(0).name + " " + addCollisionBoxToList.get(0).desc); } } return true; } @Mapping(provides={ "net/minecraft/block/properties/IProperty" }, providesMethods={ "net/minecraft/block/state/BlockState getPropertyValue (Lnet/minecraft/block/Block;Lnet/minecraft/block/properties/IProperty;)Ljava/lang/String;", "net/minecraft/block/state/BlockState getValidStates ()Lcom/google/common/collect/ImmutableList;", "net/minecraft/block/state/BlockState getAllowedValues ()Ljava/util/List;", "net/minecraft/block/state/BlockState getBaseState ()Lnet/minecraft/block/state/IBlockState;", "net/minecraft/block/state/BlockState getBlock ()Lnet/minecraft/block/Block;", "net/minecraft/block/state/BlockState getProperties ()Ljava/util/Collection;" }, depends={ "net/minecraft/block/state/BlockState", "net/minecraft/block/Block", "net/minecraft/block/state/IBlockState" }) public boolean processBlockStateClass() { ClassNode blockState = getClassNodeFromMapping("net/minecraft/block/state/BlockState"); ClassNode iBlockState = getClassNodeFromMapping("net/minecraft/block/state/IBlockState"); ClassNode block = getClassNodeFromMapping("net/minecraft/block/Block"); if (!MeddleUtil.notNull(blockState, iBlockState, block)) return false; List<MethodNode> methods = new ArrayList<MethodNode>(); // public BlockState(Block, IProperty...) String iProperty = null; for (MethodNode method : blockState.methods) { if (!method.name.equals("<init>")) continue; if (!method.desc.startsWith("(L" + block.name + ";[L")) continue; Type t = Type.getMethodType(method.desc); if (t.getArgumentTypes().length != 2) continue; if (t.getArgumentTypes()[1].getSort() != Type.ARRAY) continue; iProperty = t.getArgumentTypes()[1].getElementType().getClassName(); } if (iProperty != null) { addClassMapping("net/minecraft/block/properties/IProperty", iProperty); } // public static String getPropertyValue(Block param0, IProperty param1) // Note: Not an MCP name methods = getMatchingMethods(blockState, null, "(L" + block.name + ";L" + iProperty + ";)Ljava/lang/String;"); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/state/BlockState getPropertyValue (Lnet/minecraft/block/Block;Lnet/minecraft/block/properties/IProperty;)Ljava/lang/String;", blockState.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public com/google/common/collect/ImmutableList getValidStates() methods = getMatchingMethods(blockState, null, "()Lcom/google/common/collect/ImmutableList;"); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/state/BlockState getValidStates ()Lcom/google/common/collect/ImmutableList;", blockState.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // private java/util/List getAllowedValues() methods = getMatchingMethods(blockState, null, "()Ljava/util/List;"); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/state/BlockState getAllowedValues ()Ljava/util/List;", blockState.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public IBlockState getBaseState() methods = getMatchingMethods(blockState, null, "()L" + iBlockState.name + ";"); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/state/BlockState getBaseState ()Lnet/minecraft/block/state/IBlockState;", blockState.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public Block getBlock() methods = getMatchingMethods(blockState, null, "()L" + block.name + ";"); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/state/BlockState getBlock ()Lnet/minecraft/block/Block;", blockState.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public java/util/Collection getProperties() methods = getMatchingMethods(blockState, null, "()Ljava/util/Collection;"); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/state/BlockState getProperties ()Ljava/util/Collection;", blockState.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // getProperty in client mappings return true; } @Mapping(providesFields={ "net/minecraft/creativetab/CreativeTabs tabBlock Lnet/minecraft/creativetab/CreativeTabs;", "net/minecraft/creativetab/CreativeTabs tabDecorations Lnet/minecraft/creativetab/CreativeTabs;", "net/minecraft/creativetab/CreativeTabs tabRedstone Lnet/minecraft/creativetab/CreativeTabs;", "net/minecraft/creativetab/CreativeTabs tabTransport Lnet/minecraft/creativetab/CreativeTabs;", "net/minecraft/creativetab/CreativeTabs tabMisc Lnet/minecraft/creativetab/CreativeTabs;", "net/minecraft/creativetab/CreativeTabs tabAllSearch Lnet/minecraft/creativetab/CreativeTabs;", "net/minecraft/creativetab/CreativeTabs tabFood Lnet/minecraft/creativetab/CreativeTabs;", "net/minecraft/creativetab/CreativeTabs tabTools Lnet/minecraft/creativetab/CreativeTabs;", "net/minecraft/creativetab/CreativeTabs tabCombat Lnet/minecraft/creativetab/CreativeTabs;", "net/minecraft/creativetab/CreativeTabs tabBrewing Lnet/minecraft/creativetab/CreativeTabs;", "net/minecraft/creativetab/CreativeTabs tabMaterials Lnet/minecraft/creativetab/CreativeTabs;", "net/minecraft/creativetab/CreativeTabs tabInventory Lnet/minecraft/creativetab/CreativeTabs;" }, depends="net/minecraft/creativetab/CreativeTabs") public boolean getCreativeTabs() { ClassNode creativeTabs = getClassNodeFromMapping("net/minecraft/creativetab/CreativeTabs"); if (creativeTabs == null) return false; List<MethodNode> methods = getMatchingMethods(creativeTabs, "<clinit>", "()V"); if (methods.size() != 1) return false; Map<String, String> tabMap = new HashMap<String, String>(); String name = null; for (AbstractInsnNode insn = methods.get(0).instructions.getFirst(); insn != null; insn = insn.getNext()) { if (name == null) { name = getLdcString(insn); continue; } if (insn.getOpcode() != Opcodes.PUTSTATIC) continue; FieldInsnNode fn = (FieldInsnNode)insn; if (fn.desc.equals("L" + creativeTabs.name + ";")) { tabMap.put(name, fn.name); name = null; } } Map<String, String> tabToFieldMap = new HashMap<String, String>() {{ put("buildingBlocks", "tabBlock"); put("decorations", "tabDecorations"); put("redstone", "tabRedstone"); put("transportation", "tabTransport"); put("misc", "tabMisc"); put("search", "tabAllSearch"); put("food", "tabFood"); put("tools", "tabTools"); put("combat", "tabCombat"); put("brewing", "tabBrewing"); put("materials", "tabMaterials"); put("inventory", "tabInventory"); }}; for (String key : tabMap.keySet()) { if (tabToFieldMap.containsKey(key)) { String mappedField = tabToFieldMap.get(key); String unmappedField = tabMap.get(key); addFieldMapping("net/minecraft/creativetab/CreativeTabs " + mappedField + " Lnet/minecraft/creativetab/CreativeTabs;", creativeTabs.name + " " + unmappedField + " L" + creativeTabs.name + ";"); } } return true; } @Mapping(provides={ "net/minecraft/util/EnumFacing", "net/minecraft/util/ItemUseResult", // NEW "net/minecraft/util/ObjectActionHolder", // NEW "net/minecraft/util/MainOrOffHand", // NEW "net/minecraft/creativetab/CreativeTabs", "net/minecraft/util/RegistryNamespaced", "net/minecraft/item/state/IItemState", // NEW "net/minecraft/util/MovingObjectPosition", "net/minecraft/util/ResourceLocation"}, providesMethods={ "net/minecraft/item/Item getMaxStackSize ()I", "net/minecraft/item/Item setMaxStackSize (I)Lnet/minecraft/item/Item;", "net/minecraft/item/Item setCreativeTab (Lnet/minecraft/creativetab/CreativeTabs;)Lnet/minecraft/item/Item;", "net/minecraft/item/Item registerItem (ILjava/lang/String;Lnet/minecraft/item/Item;)V", "net/minecraft/item/Item registerItem (ILnet/minecraft/util/ResourceLocation;Lnet/minecraft/item/Item;)V", "net/minecraft/item/Item registerItemBlock (Lnet/minecraft/block/Block;Lnet/minecraft/item/Item;)V", "net/minecraft/item/Item registerItemBlock (Lnet/minecraft/block/Block;)V", "net/minecraft/item/Item onItemRightClick (Lnet/minecraft/world/World;Lnet/minecraft/entity/player/EntityPlayer;Lnet/minecraft/util/MainOrOffHand;)Lnet/minecraft/util/ObjectActionHolder;", "net/minecraft/item/Item onItemUse (Lnet/minecraft/entity/player/EntityPlayer;Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;Lnet/minecraft/util/MainOrOffHand;Lnet/minecraft/util/EnumFacing;FFF)Lnet/minecraft/util/ItemUseResult;", "net/minecraft/item/Item onItemUseFinish (Lnet/minecraft/item/ItemStack;Lnet/minecraft/world/World;Lnet/minecraft/entity/EntityLivingBase;)Lnet/minecraft/item/ItemStack;", "net/minecraft/item/Item onBlockDestroyed (Lnet/minecraft/item/ItemStack;Lnet/minecraft/world/World;Lnet/minecraft/block/state/IBlockState;Lnet/minecraft/util/BlockPos;Lnet/minecraft/entity/EntityLivingBase;)Z", "net/minecraft/item/Item hitEntity (Lnet/minecraft/item/ItemStack;Lnet/minecraft/entity/EntityLivingBase;Lnet/minecraft/entity/EntityLivingBase;)Z", "net/minecraft/item/Item itemInteractionForEntity (Lnet/minecraft/item/ItemStack;Lnet/minecraft/entity/player/EntityPlayer;Lnet/minecraft/entity/EntityLivingBase;Lnet/minecraft/util/MainOrOffHand;)Z" }, providesFields={ "net/minecraft/item/Item maxStackSize I", "net/minecraft/item/Item itemRegistry Lnet/minecraft/util/RegistryNamespaced;" }, depends={ "net/minecraft/item/Item", "net/minecraft/block/Block", "net/minecraft/item/ItemStack", "net/minecraft/world/World", "net/minecraft/util/BlockPos", "net/minecraft/entity/player/EntityPlayer", "net/minecraft/entity/EntityLivingBase", "net/minecraft/block/state/IBlockState" }) public boolean processItemClass() { ClassNode item = getClassNodeFromMapping("net/minecraft/item/Item"); ClassNode block = getClassNodeFromMapping("net/minecraft/block/Block"); ClassNode itemStack = getClassNodeFromMapping("net/minecraft/item/ItemStack"); ClassNode world = getClassNodeFromMapping("net/minecraft/world/World"); ClassNode blockPos = getClassNodeFromMapping("net/minecraft/util/BlockPos"); ClassNode entityPlayer = getClassNodeFromMapping("net/minecraft/entity/player/EntityPlayer"); ClassNode entityLivingBase = getClassNodeFromMapping("net/minecraft/entity/EntityLivingBase"); ClassNode iBlockState = getClassNodeFromMapping("net/minecraft/block/state/IBlockState"); if (!MeddleUtil.notNull(item, block, itemStack, world, blockPos, entityPlayer, entityLivingBase, iBlockState)) return false; String mainOrOffHand = null; String enumFacing = null; String itemUseResult = null; ClassNode objectActionHolder = null; String itemState = null; String resourceLocation = null; // public ItemUseResult onItemUse(ItemStack, EntityPlayer, World, BlockPos, MainOrOffHand, EnumFacing, float, float, float) // NOTE: 16w32a removes ItemStack for (MethodNode method : item.methods) { if (!checkMethodParameters(method, Type.OBJECT, Type.OBJECT, Type.OBJECT, Type.OBJECT, Type.OBJECT, Type.FLOAT, Type.FLOAT, Type.FLOAT)) continue; String test = "(L" + entityPlayer.name + ";L" + world.name + ";L" + blockPos.name + ";L"; if (!method.desc.startsWith(test)) continue; Type t = Type.getMethodType(method.desc); Type[] args = t.getArgumentTypes(); addClassMapping("net/minecraft/util/ItemUseResult", itemUseResult = t.getReturnType().getClassName()); addClassMapping("net/minecraft/util/MainOrOffHand", mainOrOffHand = args[3].getClassName()); addClassMapping("net/minecraft/util/EnumFacing", enumFacing = args[4].getClassName()); addMethodMapping("net/minecraft/item/Item onItemUse (Lnet/minecraft/entity/player/EntityPlayer;Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;Lnet/minecraft/util/MainOrOffHand;Lnet/minecraft/util/EnumFacing;FFF)Lnet/minecraft/util/ItemUseResult;", item.name + " " + method.name + " " + method.desc); } // public ObjectActionHolderThing onItemRightClick(ItemStack, World, EntityPlayer, MainOrOffHand) // NOTE: 16w32a removes ItemStack for (MethodNode method : item.methods) { String test = "(L" + world.name + ";L" + entityPlayer.name + ";L" + mainOrOffHand + ";)"; if (!method.desc.startsWith(test)) continue; Type t = Type.getMethodType(method.desc).getReturnType(); objectActionHolder = getClassNode(t.getClassName()); addClassMapping("net/minecraft/util/ObjectActionHolder", objectActionHolder); addMethodMapping("net/minecraft/item/Item onItemRightClick (Lnet/minecraft/world/World;Lnet/minecraft/entity/player/EntityPlayer;Lnet/minecraft/util/MainOrOffHand;)Lnet/minecraft/util/ObjectActionHolder;", item.name + " " + method.name + " " + method.desc); } List<MethodNode> methods = new ArrayList<MethodNode>(); // private static void registerItem(int, ResourceLocation, Item) // private static void registerItem(int, String, Item) methods.clear(); for (MethodNode method : item.methods) { if ((method.access & Opcodes.ACC_STATIC) == 0) continue; if (!checkMethodParameters(method, Type.INT, Type.OBJECT, Type.OBJECT)) continue; if (!method.desc.startsWith("(IL") || !method.desc.endsWith(";L" + item.name + ";)V")) continue; methods.add(method); } if (methods.size() == 2) { for (MethodNode method : methods) { String className = Type.getMethodType(method.desc).getArgumentTypes()[1].getClassName(); if (className.equals("java.lang.String")) { addMethodMapping("net/minecraft/item/Item registerItem (ILjava/lang/String;Lnet/minecraft/item/Item;)V", item.name + " " + method.name + " " + method.desc); } else { if (searchConstantPoolForStrings(className, "minecraft")) { resourceLocation = className; addClassMapping("net/minecraft/util/ResourceLocation", className); } addMethodMapping("net/minecraft/item/Item registerItem (ILnet/minecraft/util/ResourceLocation;Lnet/minecraft/item/Item;)V", item.name + " " + method.name + " " + method.desc); } } } // protected static void registerItemBlock(Block blockIn, Item itemIn) methods = getMatchingMethods(item, null, "(L" + block.name + ";L" + item.name + ";)V"); methods = removeMethodsWithoutFlags(methods, Opcodes.ACC_STATIC); if (methods.size() == 1) { addMethodMapping("net/minecraft/item/Item registerItemBlock (Lnet/minecraft/block/Block;Lnet/minecraft/item/Item;)V", item.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // private static void registerItemBlock(Block blockIn) methods = getMatchingMethods(item, null, "(L" + block.name + ";)V"); methods = removeMethodsWithoutFlags(methods, Opcodes.ACC_STATIC); if (methods.size() == 1) { addMethodMapping("net/minecraft/item/Item registerItemBlock (Lnet/minecraft/block/Block;)V", item.name + " " + methods.get(0).name + " " + methods.get(0).desc); } for (FieldNode field : item.fields) { if ((field.access & (Opcodes.ACC_FINAL | Opcodes.ACC_STATIC)) != (Opcodes.ACC_FINAL + Opcodes.ACC_STATIC)) continue; String className = Type.getType(field.desc).getClassName(); if (className.contains(".")) continue; // Item.itemRegistry if (searchConstantPoolForClasses(className, "com.google.common.collect.BiMap", "com.google.common.collect.HashBiMap")) { addClassMapping("net/minecraft/util/RegistryNamespaced", className); addFieldMapping("net/minecraft/item/Item itemRegistry Lnet/minecraft/util/RegistryNamespaced;", item.name + " " + field.name + " " + field.desc); continue; } } // public final void addItemState(ResourceLocation, IItemState) for (MethodNode method : item.methods) { Type t = Type.getMethodType(method.desc); Type[] args = t.getArgumentTypes(); if (args.length != 2) continue; if (!args[0].getClassName().equals(resourceLocation)) continue; String className = args[1].getClassName(); ClassNode cn = getClassNode(className); if (cn == null) continue; if ((cn.access & Opcodes.ACC_INTERFACE) == 0) continue; addClassMapping("net/minecraft/item/state/IItemState", className); break; } //protected MovingObjectPosition getMovingObjectPositionFromPlayer(World, EntityPlayer, boolean) for (MethodNode method : item.methods) { if (!method.desc.startsWith("(L" + world.name + ";L" + entityPlayer.name + ";Z)")) continue; Type t = Type.getMethodType(method.desc).getReturnType(); if (t.getSort() != Type.OBJECT) continue; if (searchConstantPoolForStrings(t.getClassName(), "HitResult{type=")) { addClassMapping("net/minecraft/util/MovingObjectPosition", t.getClassName()); break; } } ClassNode creativeTab = null; // Get net.minecraft.creativetab.CreativeTabs for (FieldNode field : item.fields) { Type t = Type.getType(field.desc); if (t.getSort() != Type.OBJECT) continue; String className = t.getClassName(); if (className.contains(".")) continue; if (DynamicMappings.reverseClassMappings.containsKey(className)) continue; if (searchConstantPoolForStrings(className, "buildingBlocks", "decorations", "redstone")) { addClassMapping("net/minecraft/creativetab/CreativeTabs", className); creativeTab = getClassNode(className); } } // Get Item.setCreativeTab() if (creativeTab != null) { String setCreativeTabDesc = "(L" + creativeTab.name + ";)L" + item.name + ";"; methods = getMatchingMethods(item, null, setCreativeTabDesc); if (methods.size() == 1) { addMethodMapping("net/minecraft/item/Item setCreativeTab (Lnet/minecraft/creativetab/CreativeTabs;)Lnet/minecraft/item/Item;", item.name + " " + methods.get(0).name + " " + methods.get(0).desc); } } String maxStackSizeField = null; // Get maxStackSize field List<MethodNode> initMethod = getMatchingMethods(item, "<init>", "()V"); if (initMethod.size() == 1) { for (AbstractInsnNode insn = initMethod.get(0).instructions.getFirst(); insn != null; insn = insn.getNext()) { if (!(insn instanceof IntInsnNode)) continue; IntInsnNode bipush = (IntInsnNode)insn; if (bipush.operand != 64) continue; if (insn.getNext().getOpcode() != Opcodes.PUTFIELD) continue; FieldInsnNode fn = (FieldInsnNode)insn.getNext(); if (!fn.desc.equals("I")) continue; maxStackSizeField = fn.name; addFieldMapping("net/minecraft/item/Item maxStackSize I", item.name + " " + maxStackSizeField + " I"); break; } } // get getMaxStackSize() and setMaxStackSize(I) methods if (maxStackSizeField != null) { boolean foundGetter = false; List<MethodNode> intGetters = getMatchingMethods(item, null, "()I"); for (MethodNode method : intGetters) { for (AbstractInsnNode insn = method.instructions.getFirst(); insn != null; insn = insn.getNext()) { if (insn.getOpcode() < 0) continue; // First real instruction should be ALOAD_0 if (insn.getOpcode() != Opcodes.ALOAD) break; insn = insn.getNext(); // Next should be GETFIELD if (insn.getOpcode() != Opcodes.GETFIELD) break; FieldInsnNode fn = (FieldInsnNode)insn; if (fn.name.equals(maxStackSizeField)) { addMethodMapping("net/minecraft/item/Item getMaxStackSize ()I", item.name + " " + method.name + " " + method.desc); foundGetter = true; break; } } if (foundGetter) break; } boolean foundSetter = false; List<MethodNode> intSetters = getMatchingMethods(item, null, "(I)L" + item.name + ";"); for (MethodNode method : intSetters) { for (AbstractInsnNode insn = method.instructions.getFirst(); insn != null; insn = insn.getNext()) { if (insn.getOpcode() < 0) continue; if (insn.getOpcode() != Opcodes.ALOAD) break; insn = insn.getNext(); if (insn.getOpcode() != Opcodes.ILOAD) break; insn = insn.getNext(); if (insn.getOpcode() != Opcodes.PUTFIELD) break; FieldInsnNode fn = (FieldInsnNode)insn; if (fn.name.equals(maxStackSizeField)) { addMethodMapping("net/minecraft/item/Item setMaxStackSize (I)Lnet/minecraft/item/Item;", item.name + " " + method.name + " " + method.desc); foundSetter = true; break; } } if (foundSetter) break; } } // public ItemStack onItemUseFinish(ItemStack stack, World worldIn, EntityLivingBase playerIn) methods = getMatchingMethods(item, null, assembleDescriptor("(", itemStack, world, entityLivingBase, ")", itemStack)); if (methods.size() == 1) { addMethodMapping("net/minecraft/item/Item onItemUseFinish (Lnet/minecraft/item/ItemStack;Lnet/minecraft/world/World;Lnet/minecraft/entity/EntityLivingBase;)Lnet/minecraft/item/ItemStack;", item.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public boolean onBlockDestroyed(ItemStack param0, World param1, IBlockState param2, BlockPos param3, EntityLivingBase param4) methods = getMatchingMethods(item, null, assembleDescriptor("(", itemStack, world, iBlockState, blockPos, entityLivingBase, ")Z")); if (methods.size() == 1) { addMethodMapping("net/minecraft/item/Item onBlockDestroyed (Lnet/minecraft/item/ItemStack;Lnet/minecraft/world/World;Lnet/minecraft/block/state/IBlockState;Lnet/minecraft/util/BlockPos;Lnet/minecraft/entity/EntityLivingBase;)Z", item.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public boolean hitEntity(ItemStack stack, EntityLivingbase target, EntityLivingBase attacker) methods = getMatchingMethods(item, null, assembleDescriptor("(", itemStack, entityLivingBase, entityLivingBase, ")Z")); if(methods.size() == 1){ addMethodMapping("net/minecraft/item/Item hitEntity (Lnet/minecraft/item/ItemStack;Lnet/minecraft/entity/EntityLivingBase;Lnet/minecraft/entity/EntityLivingBase;)Z", item.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public boolean itemInteractionForEntity(ItemStack stack, EntityPlayer player, EntityLivingBase target, MainOrOffHand hand) ClassNode hand = getClassNodeFromMapping("net/minecraft/util/MainOrOffHand"); methods = getMatchingMethods(item, null, assembleDescriptor("(", itemStack, entityPlayer, entityLivingBase, hand, ")Z")); if(methods.size() == 1){ addMethodMapping("net/minecraft/item/Item itemInteractionForEntity (Lnet/minecraft/item/ItemStack;Lnet/minecraft/entity/player/EntityPlayer;Lnet/minecraft/entity/EntityLivingBase;Lnet/minecraft/util/MainOrOffHand;)Z", item.name + " " + methods.get(0).name + " " + methods.get(0).desc); } return true; } @Mapping(provides={ "net/minecraft/util/EnumFacing$AxisDirection", "net/minecraft/util/EnumFacing$Axis" }, providesFields={ "net/minecraft/util/EnumFacing DOWN Lnet/minecraft/util/EnumFacing;", "net/minecraft/util/EnumFacing UP Lnet/minecraft/util/EnumFacing;", "net/minecraft/util/EnumFacing NORTH Lnet/minecraft/util/EnumFacing;", "net/minecraft/util/EnumFacing SOUTH Lnet/minecraft/util/EnumFacing;", "net/minecraft/util/EnumFacing WEST Lnet/minecraft/util/EnumFacing;", "net/minecraft/util/EnumFacing EAST Lnet/minecraft/util/EnumFacing;" }, depends={ "net/minecraft/util/EnumFacing" }) public boolean processEnumFacingClass() { ClassNode enumFacing = getClassNodeFromMapping("net/minecraft/util/EnumFacing"); if (!MeddleUtil.notNull(enumFacing)) return false; List<FieldNode> fields = getMatchingFields(enumFacing, null, "L" + enumFacing.name + ";"); if (fields.size() == 6) { String[] names = new String[] { "DOWN", "UP", "NORTH", "SOUTH", "WEST", "EAST" }; for (int n = 0; n < 6; n++) { addFieldMapping("net/minecraft/util/EnumFacing " + names[n] + " Lnet/minecraft/util/EnumFacing;", enumFacing.name + " " + fields.get(n).name + " " + fields.get(n).desc); } } // Search fields to identify EnumFacing.AxisDirection and EnumFacing.Axis Set<String> innerClasses = new HashSet<>(); for (FieldNode fn : enumFacing.fields) { if (fn.desc.startsWith("L" + enumFacing.name + "$")) innerClasses.add(fn.desc.substring(1, fn.desc.length() - 1)); } if (innerClasses.size() == 2) { String axisDirection_name = null; String axis_name = null; for (String s : innerClasses) { if (axisDirection_name == null && searchConstantPoolForStrings(s, "POSITIVE", "NEGATIVE")) axisDirection_name = s; else if (axis_name == null && searchConstantPoolForStrings(s, "X", "Y", "Z")) axis_name = s; } // If we found both classes then everything should be as expected if (axisDirection_name != null && axis_name != null) { addClassMapping("net/minecraft/util/EnumFacing$AxisDirection", axisDirection_name); addClassMapping("net/minecraft/util/EnumFacing$Axis", axis_name); } } return true; } @Mapping(providesMethods="net/minecraft/util/EnumFacing$AxisDirection getOffset ()I", providesFields={ "net/minecraft/util/EnumFacing$AxisDirection POSITIVE Lnet/minecraft/util/EnumFacing$AxisDirection;", "net/minecraft/util/EnumFacing$AxisDirection NEGATIVE Lnet/minecraft/util/EnumFacing$AxisDirection;", }, depends={ "net/minecraft/util/EnumFacing$AxisDirection", }) public boolean processEnumFacingAxisDirectionClass() { ClassNode axisDirection = getClassNodeFromMapping("net/minecraft/util/EnumFacing$AxisDirection"); if (!MeddleUtil.notNull(axisDirection)) return false; MethodNode clinit = getMethodNode(axisDirection, "--- <clinit> ()V"); if (clinit != null) { String lastString = null; for (AbstractInsnNode insn = clinit.instructions.getFirst(); insn != null; insn = insn.getNext()) { String string = getLdcString(insn); if (string != null && lastString == null) { lastString = string; continue; } if (insn.getOpcode() != Opcodes.PUTSTATIC) continue; FieldInsnNode fn = (FieldInsnNode)insn; if (!fn.owner.equals(axisDirection.name) || !fn.desc.equals("L" + axisDirection.name + ";")) continue; if (lastString.equals("POSITIVE")) { addFieldMapping("net/minecraft/util/EnumFacing$AxisDirection POSITIVE Lnet/minecraft/util/EnumFacing$AxisDirection;", fn); } else if (lastString.equals("NEGATIVE")) { addFieldMapping("net/minecraft/util/EnumFacing$AxisDirection NEGATIVE Lnet/minecraft/util/EnumFacing$AxisDirection;", fn); } lastString = null; } } List<MethodNode> methods = getMatchingMethods(axisDirection, null, "()I"); if (methods.size() == 1) { addMethodMapping("net/minecraft/util/EnumFacing$AxisDirection getOffset ()I", axisDirection.name + " " + methods.get(0).name + " " + methods.get(0).desc); } return true; } public Map<String, FieldInsnNode> extractEnumFieldsWithNames(ClassNode cn) { Map<String, FieldInsnNode> enumFields = new HashMap<>(); MethodNode clinit = getMethodNode(cn, "--- <clinit> ()V"); if (clinit != null) { String lastString = null; for (AbstractInsnNode insn = clinit.instructions.getFirst(); insn != null; insn = insn.getNext()) { String string = getLdcString(insn); if (string != null && lastString == null) { lastString = string; continue; } if (insn.getOpcode() != Opcodes.PUTSTATIC) continue; FieldInsnNode fn = (FieldInsnNode)insn; if (!fn.owner.equals(cn.name) || !fn.desc.equals("L" + cn.name + ";")) continue; enumFields.put(lastString, fn); lastString = null; } } return enumFields; } @Mapping(provides="net/minecraft/util/EnumFacing$Plane", providesMethods={}, providesFields={ "net/minecraft/util/EnumFacing$Axis X Lnet/minecraft/util/EnumFacing$Axis;", "net/minecraft/util/EnumFacing$Axis Y Lnet/minecraft/util/EnumFacing$Axis;", "net/minecraft/util/EnumFacing$Axis Z Lnet/minecraft/util/EnumFacing$Axis;" }, depends={ "net/minecraft/util/EnumFacing", "net/minecraft/util/EnumFacing$Axis" }) public boolean processEnumFacingAxisClass() { ClassNode enumFacing = getClassNodeFromMapping("net/minecraft/util/EnumFacing"); ClassNode axis = getClassNodeFromMapping("net/minecraft/util/EnumFacing$Axis"); if (!MeddleUtil.notNull(enumFacing, axis)) return false; Map<String, FieldInsnNode> enumFields = extractEnumFieldsWithNames(axis); if (enumFields.keySet().size() == 3) { for (String key : enumFields.keySet()) { if ("X".equals(key) || "Y".equals(key) || "Z".equals(key)) addFieldMapping("net/minecraft/util/EnumFacing$Axis " + key + " Lnet/minecraft/util/EnumFacing$Axis;", axis.name + " " + enumFields.get(key).name + " " + enumFields.get(key).desc); } } List<FieldNode> fields = getMatchingFields(axis, null, null); for (Iterator<FieldNode> it = fields.iterator(); it.hasNext();) { FieldNode field = it.next(); Type t = Type.getType(field.desc); if (t.getSort() != Type.OBJECT) continue; String className = t.getClassName(); if (className.equals(axis.name)) continue; else if (className.equals("java.lang.String")) continue; else if (className.equals("java.util.Map")) continue; else if (!className.startsWith(enumFacing.name)) continue; if (searchConstantPoolForStrings(className, "HORIZONTAL", "VERTICAL")) { addClassMapping("net/minecraft/util/EnumFacing$Plane", className); break; } } // TODO - Methods return true; } @Mapping(providesMethods={ "net/minecraft/util/EnumFacing$Plane facings ()[Lnet/minecraft/util/EnumFacing;", "net/minecraft/util/EnumFacing$Plane random (Ljava/util/Random;)Lnet/minecraft/util/EnumFacing;", "net/minecraft/util/EnumFacing$Plane apply (Lnet/minecraft/util/EnumFacing;)Z" }, providesFields={ "net/minecraft/util/EnumFacing$Plane HORIZONTAL Lnet/minecraft/util/EnumFacing$Plane;", "net/minecraft/util/EnumFacing$Plane VERTICAL Lnet/minecraft/util/EnumFacing$Plane;" }, depends={ "net/minecraft/util/EnumFacing", "net/minecraft/util/EnumFacing$Plane" }) public boolean processEnumFacingPlaneClass() { ClassNode enumFacing = getClassNodeFromMapping("net/minecraft/util/EnumFacing"); ClassNode plane = getClassNodeFromMapping("net/minecraft/util/EnumFacing$Plane"); if (!MeddleUtil.notNull(enumFacing)) return false; // Map enum fields Map<String, FieldInsnNode> enumFields = extractEnumFieldsWithNames(plane); if (enumFields.keySet().size() == 2) { for (String key : enumFields.keySet()) { if ("HORIZONTAL".equals(key) || "VERTICAL".equals(key)) addFieldMapping("net/minecraft/util/EnumFacing$Plane " + key + " Lnet/minecraft/util/EnumFacing$Plane;", plane.name + " " + enumFields.get(key).name + " " + enumFields.get(key).desc); } } // public EnumFacing[] facings() List<MethodNode> methods = getMatchingMethods(plane, null, "()[L" + enumFacing.name + ";"); if (methods.size() == 1) { addMethodMapping("net/minecraft/util/EnumFacing$Plane facings ()[Lnet/minecraft/util/EnumFacing;", plane.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public EnumFacing random(Random rand) methods = getMatchingMethods(plane, null, "(Ljava/util/Random;)L" + enumFacing.name + ";"); if (methods.size() == 1) { addMethodMapping("net/minecraft/util/EnumFacing$Plane random (Ljava/util/Random;)Lnet/minecraft/util/EnumFacing;", plane.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public boolean apply(EnumFacing facing) methods = getMatchingMethods(plane, null, "(L" + enumFacing.name + ";)Z"); if (methods.size() == 1) { addMethodMapping("net/minecraft/util/EnumFacing$Plane apply (Lnet/minecraft/util/EnumFacing;)Z", plane.name + " " + methods.get(0).name + " " + methods.get(0).desc); } return true; } @Mapping(providesFields={ "net/minecraft/util/EnumFacing index I", "net/minecraft/util/EnumFacing opposite I", "net/minecraft/util/EnumFacing horizontalIndex I", "net/minecraft/util/EnumFacing name Ljava/lang/String;", "net/minecraft/util/EnumFacing axisDirection Lnet/minecraft/util/EnumFacing$AxisDirection;", "net/minecraft/util/EnumFacing axis Lnet/minecraft/util/EnumFacing$Axis;", "net/minecraft/util/EnumFacing directionVec Lnet/minecraft/util/Vec3i;" }, providesMethods={ "net/minecraft/util/EnumFacing getIndex ()I", "net/minecraft/util/EnumFacing getHorizontalIndex ()I" }, depends={ "net/minecraft/util/EnumFacing", "net/minecraft/util/EnumFacing$AxisDirection", "net/minecraft/util/EnumFacing$Axis", "net/minecraft/util/Vec3i" }) public boolean processEnumFacingClass2() { // Using a second method to process EnumFacing since processBlockPosClass needs // EnumFacing fields, but processBlockPosClass produces Vec3i, which we need to // process <init> ClassNode enumFacing = getClassNodeFromMapping("net/minecraft/util/EnumFacing"); ClassNode axis = getClassNodeFromMapping("net/minecraft/util/EnumFacing$Axis"); ClassNode axisDirection = getClassNodeFromMapping("net/minecraft/util/EnumFacing$AxisDirection"); ClassNode vec3i = getClassNodeFromMapping("net/minecraft/util/Vec3i"); if (!MeddleUtil.notNull(enumFacing, vec3i, axis, axisDirection)) return false; // Map of obfuscated to deobfuscated Map<String, String> fieldMap = new HashMap<>(); // private EnumFacing(int indexIn, int oppositeIn, int horizontalIndexIn, String nameIn, EnumFacing.AxisDirection axisDirectionIn, EnumFacing.Axis axisIn, Vec3i directionVecIn) List<MethodNode> methods = getMatchingMethods(enumFacing, "<init>", assembleDescriptor("(Ljava/lang/String;IIIILjava/lang/String;", axisDirection, axis, vec3i, ")V")); if (methods.size() == 1) { MethodNode method = methods.get(0); List<AbstractInsnNode[]> inits = new ArrayList<>(); // Extract all ALOAD_0, ALOAD/ILOAD, PUTFIELD sequences for (AbstractInsnNode insn = method.instructions.getFirst(); insn != null; insn = insn.getNext()) { AbstractInsnNode[] nodes = getInsnNodeSequenceArray(insn, VarInsnNode.class, VarInsnNode.class, FieldInsnNode.class); if (nodes != null) { FieldInsnNode fn = (FieldInsnNode)nodes[2]; if (((VarInsnNode)nodes[0]).var == 0 && fn.getOpcode() == Opcodes.PUTFIELD && fn.owner.equals(enumFacing.name)) { inits.add(nodes); insn = nodes[2]; } } } // <init> should be setting 7 variables if (inits.size() == 7) { for (AbstractInsnNode[] nodes : inits) { FieldInsnNode fn = (FieldInsnNode)nodes[2]; int var = ((VarInsnNode)nodes[1]).var; switch (var) { // index case 3: if (fn.desc.equals("I")) addFieldMapping("net/minecraft/util/EnumFacing index I", fn); fieldMap.put(fn.name, "index"); break; // opposite case 4: if (fn.desc.equals("I")) addFieldMapping("net/minecraft/util/EnumFacing opposite I", fn); fieldMap.put(fn.name, "opposite"); break; // horizontalIndex case 5: if (fn.desc.equals("I")) addFieldMapping("net/minecraft/util/EnumFacing horizontalIndex I", fn); fieldMap.put(fn.name, "horizontalIndex"); break; // name case 6: if (fn.desc.equals("Ljava/lang/String;")) addFieldMapping("net/minecraft/util/EnumFacing name Ljava/lang/String;", fn); fieldMap.put(fn.name, "name"); break; // axisDirection case 7: if (fn.desc.equals("L" + axisDirection.name + ";")) addFieldMapping("net/minecraft/util/EnumFacing axisDirection Lnet/minecraft/util/EnumFacing$AxisDirection;", fn); fieldMap.put(fn.name, "axisDirection"); break; // axis case 8: if (fn.desc.equals("L" + axis.name + ";")) addFieldMapping("net/minecraft/util/EnumFacing axis Lnet/minecraft/util/EnumFacing$Axis;", fn); fieldMap.put(fn.name, "axis"); break; // directionVec case 9: if (fn.desc.equals("L" + vec3i.name + ";")) addFieldMapping("net/minecraft/util/EnumFacing directionVec Lnet/minecraft/util/Vec3i;", fn); fieldMap.put(fn.name, "directionVec"); break; } } } } // public int getIndex() // public int getHorizontalIndex() methods = getMatchingMethods(enumFacing, null, "()I"); for (MethodNode method : methods) { AbstractInsnNode[] nodes = getOpcodeSequenceArray(method.instructions.getFirst(), Opcodes.ALOAD, Opcodes.GETFIELD, Opcodes.IRETURN); if (nodes != null) { if (((VarInsnNode)nodes[0]).var != 0) continue; FieldInsnNode fn = (FieldInsnNode)nodes[1]; if (!fn.owner.equals(enumFacing.name) || !fn.desc.equals("I")) continue; String field = fieldMap.get(fn.name); if (field == null) continue; if (field.equals("index")) { addMethodMapping("net/minecraft/util/EnumFacing getIndex ()I", enumFacing.name + " " + method.name + " ()I"); } else if (field.equals("horizontalIndex")) { addMethodMapping("net/minecraft/util/EnumFacing getHorizontalIndex ()I", enumFacing.name + " " + method.name + " ()I"); } } } return true; } @Mapping(provides={ "net/minecraft/util/SoundCategory" }, providesFields={ "net/minecraft/world/World isRemote Z" }, providesMethods={ "net/minecraft/world/World setBlockState (Lnet/minecraft/util/BlockPos;Lnet/minecraft/block/state/IBlockState;I)Z", "net/minecraft/world/World markBlockForUpdate (Lnet/minecraft/util/BlockPos;Lnet/minecraft/block/state/IBlockState;Lnet/minecraft/block/state/IBlockState;I)V", "net/minecraft/world/World markBlockRangeForRenderUpdate (Lnet/minecraft/util/BlockPos;Lnet/minecraft/util/BlockPos;)V", "net/minecraft/world/World playAuxSFXAtEntity (Lnet/minecraft/entity/player/EntityPlayer;ILnet/minecraft/util/BlockPos;I)V", "net/minecraft/world/World addBlockEvent (Lnet/minecraft/util/BlockPos;Lnet/minecraft/block/Block;II)V", "net/minecraft/world/World setTileEntity (Lnet/minecraft/util/BlockPos;Lnet/minecraft/tileentity/TileEntity;)V", "net/minecraft/world/World markChunkDirty (Lnet/minecraft/util/BlockPos;Lnet/minecraft/tileentity/TileEntity;)V", "net/minecraft/world/World playSoundEffect (Lnet/minecraft/entity/player/EntityPlayer;DDDLnet/minecraft/util/Sound;Lnet/minecraft/util/SoundCategory;FF)V", "net/minecraft/world/World getEntitiesInAABBexcluding (Lnet/minecraft/entity/Entity;Lnet/minecraft/util/AxisAlignedBB;Lcom/google/common/base/Predicate;)Ljava/util/List;", "net/minecraft/world/World getEntitiesWithinAABBExcludingEntity (Lnet/minecraft/entity/Entity;Lnet/minecraft/util/AxisAlignedBB;)Ljava/util/List;", "net/minecraft/world/World getCollidingBoundingBoxes (Lnet/minecraft/entity/Entity;Lnet/minecraft/util/AxisAlignedBB;)Ljava/util/List;" }, depends={ "net/minecraft/world/World", "net/minecraft/util/BlockPos", "net/minecraft/block/state/IBlockState", "net/minecraft/entity/player/EntityPlayer", "net/minecraft/block/Block", "net/minecraft/tileentity/TileEntity", "net/minecraft/util/AxisAlignedBB", "net/minecraft/entity/Entity", "net/minecraft/util/Sound", }) public boolean processWorldClass() { ClassNode world = getClassNodeFromMapping("net/minecraft/world/World"); ClassNode blockPos = getClassNodeFromMapping("net/minecraft/util/BlockPos"); ClassNode iBlockState = getClassNodeFromMapping("net/minecraft/block/state/IBlockState"); ClassNode entityPlayer = getClassNodeFromMapping("net/minecraft/entity/player/EntityPlayer"); ClassNode block = getClassNodeFromMapping("net/minecraft/block/Block"); ClassNode tileEntity = getClassNodeFromMapping("net/minecraft/tileentity/TileEntity"); ClassNode aabb = getClassNodeFromMapping("net/minecraft/util/AxisAlignedBB"); ClassNode entity = getClassNodeFromMapping("net/minecraft/entity/Entity"); ClassNode sound = getClassNodeFromMapping("net/minecraft/util/Sound"); if (!MeddleUtil.notNull(world, blockPos, iBlockState, entityPlayer, block, tileEntity, aabb, entity, sound)) return false; int count = 0; String isRemote = null; for (FieldNode fn : world.fields) { if ((fn.access & Opcodes.ACC_FINAL) == 0 || !fn.desc.equals("Z")) continue; isRemote = fn.name; count++; } if (count == 1) addFieldMapping("net/minecraft/world/World isRemote Z", world.name + " " + isRemote + " Z"); else isRemote = null; // public boolean setBlockState(BlockPos pos, IBlockState newState, int flags) List<MethodNode> methods = getMatchingMethods(world, null, assembleDescriptor("(", blockPos, iBlockState, "I)Z")); //System.out.println(methods.size()); if (methods.size() == 1) { addMethodMapping("net/minecraft/world/World setBlockState (Lnet/minecraft/util/BlockPos;Lnet/minecraft/block/state/IBlockState;I)Z", world.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public void markBlockForUpdate(BlockPos, IBlockState, IBlockState, int) methods = getMatchingMethods(world, null, assembleDescriptor("(", blockPos, iBlockState, iBlockState, "I)V")); if (methods.size() == 1) { addMethodMapping("net/minecraft/world/World markBlockForUpdate (Lnet/minecraft/util/BlockPos;Lnet/minecraft/block/state/IBlockState;Lnet/minecraft/block/state/IBlockState;I)V", world.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public void markBlockRangeForRenderUpdate(BlockPos rangeMin, BlockPos rangeMax) methods = getMatchingMethods(world, null, assembleDescriptor("(", blockPos, blockPos, ")V")); if (methods.size() == 1) { addMethodMapping("net/minecraft/world/World markBlockRangeForRenderUpdate (Lnet/minecraft/util/BlockPos;Lnet/minecraft/util/BlockPos;)V", world.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public void playAuxSFXAtEntity(EntityPlayer player, int sfxType, BlockPos pos, int p_180498_4_) methods = getMatchingMethods(world, null, assembleDescriptor("(", entityPlayer, "I", blockPos, "I)V")); if (methods.size() == 1) { addMethodMapping("net/minecraft/world/World playAuxSFXAtEntity (Lnet/minecraft/entity/player/EntityPlayer;ILnet/minecraft/util/BlockPos;I)V", world.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public void addBlockEvent(BlockPos pos, Block blockIn, int eventID, int eventParam) methods = getMatchingMethods(world, null, assembleDescriptor("(", blockPos, block, "II)V")); for (Iterator<MethodNode> it = methods.iterator(); it.hasNext();) { MethodNode method = it.next(); // Filter out methods that are empty AbstractInsnNode insn = getNextRealOpcode(method.instructions.getFirst()); if (insn != null && insn.getOpcode() == Opcodes.RETURN) it.remove(); } if (methods.size() == 1) { addMethodMapping("net/minecraft/world/World addBlockEvent (Lnet/minecraft/util/BlockPos;Lnet/minecraft/block/Block;II)V", world.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public void setTileEntity(BlockPos pos, TileEntity tileEntityIn) // public void markChunkDirty(BlockPos pos, TileEntity unusedTileEntity) methods = getMatchingMethods(world, null, assembleDescriptor("(", blockPos, tileEntity, ")V")); if (methods.size() == 2) { List<VarInsnNode> vars1 = getAllInsnNodesOfType(methods.get(0).instructions.getFirst(), VarInsnNode.class); List<VarInsnNode> vars2 = getAllInsnNodesOfType(methods.get(1).instructions.getFirst(), VarInsnNode.class); // Remove any ALOADs that don't refer to variable 2 for (Iterator<VarInsnNode> it = vars1.iterator(); it.hasNext();) { if (it.next().var != 2) it.remove(); } for (Iterator<VarInsnNode> it = vars2.iterator(); it.hasNext();) { if (it.next().var != 2) it.remove(); } MethodNode setTileEntity = null; MethodNode markChunkDirty = null; if (vars1.size() > 0 && vars2.size() == 0) { setTileEntity = methods.get(0); markChunkDirty = methods.get(1); } else if (vars1.size() == 0 && vars2.size() > 0) { setTileEntity = methods.get(1); markChunkDirty = methods.get(0); } if (setTileEntity != null && markChunkDirty != null) { addMethodMapping("net/minecraft/world/World setTileEntity (Lnet/minecraft/util/BlockPos;Lnet/minecraft/tileentity/TileEntity;)V", world.name + " " + setTileEntity.name + " " + setTileEntity.desc); addMethodMapping("net/minecraft/world/World markChunkDirty (Lnet/minecraft/util/BlockPos;Lnet/minecraft/tileentity/TileEntity;)V", world.name + " " + markChunkDirty.name + " " + markChunkDirty.desc); } } // public void playSoundEffect(double x, double y, double z, Sound sound, float volume, float pitch) // As of 15w49a: // public void playSoundEffect(EntityPlayer player, double x, double y, double z, Sound sound, float volume, float pitch) // As of 16w02a: // public void playSoundEffect(EntityPlayer player, double x, double y, double z, Sound sound, SoundCategory, float volume, float pitch) methods = getMatchingMethods(world, null, null); for (Iterator<MethodNode> it = methods.iterator(); it.hasNext();) { MethodNode method = it.next(); if (!method.desc.startsWith("(L" + entityPlayer.name + ";DDDL" + sound.name + ";") || !method.desc.endsWith("FF)V")) it.remove(); } if (methods.size() == 1) { Type t = Type.getMethodType(methods.get(0).desc); Type soundType = t.getArgumentTypes()[5]; String soundCategory_name = soundType.getClassName(); if (soundType.getSort() == Type.OBJECT && searchConstantPoolForStrings(soundCategory_name, "MASTER", "MUSIC", "RECORDS")) { addClassMapping("net/minecraft/util/SoundCategory", soundCategory_name); addMethodMapping("net/minecraft/world/World playSoundEffect (Lnet/minecraft/entity/player/EntityPlayer;DDDLnet/minecraft/util/Sound;Lnet/minecraft/util/SoundCategory;FF)V", world.name + " " + methods.get(0).name + " " + methods.get(0).desc); } } // public List getEntitiesInAABBexcluding(Entity entityIn, AxisAlignedBB boundingBox, Predicate predicate) MethodNode getEntitiesInAABBexcluding = null; methods = getMatchingMethods(world, null, assembleDescriptor("(", entity, aabb, "Lcom/google/common/base/Predicate;)Ljava/util/List;")); if (methods.size() == 1) { getEntitiesInAABBexcluding = methods.get(0); addMethodMapping("net/minecraft/world/World getEntitiesInAABBexcluding (Lnet/minecraft/entity/Entity;Lnet/minecraft/util/AxisAlignedBB;Lcom/google/common/base/Predicate;)Ljava/util/List;", world.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public List getEntitiesWithinAABBExcludingEntity(Entity entityIn, AxisAlignedBB bb) // public List getCollidingBoundingBoxes(Entity entityIn, AxisAlignedBB bb) methods = getMatchingMethods(world, null, assembleDescriptor("(", entity, aabb, ")Ljava/util/List;")); if (methods.size() == 2 && getEntitiesInAABBexcluding != null) { startLoop: for (Iterator<MethodNode> it = methods.iterator(); it.hasNext();) { MethodNode method = it.next(); AbstractInsnNode[] nodes = null; if ((nodes = getOpcodeSequenceArray(method.instructions.getFirst(), Opcodes.ALOAD, Opcodes.ALOAD, Opcodes.ALOAD, Opcodes.GETSTATIC, Opcodes.INVOKEVIRTUAL, Opcodes.ARETURN)) != null) { MethodInsnNode mn = (MethodInsnNode)nodes[4]; if (mn.owner.equals(world.name) && mn.name.equals(getEntitiesInAABBexcluding.name) && mn.desc.equals(getEntitiesInAABBexcluding.desc)) { it.remove(); addMethodMapping("net/minecraft/world/World getEntitiesWithinAABBExcludingEntity (Lnet/minecraft/entity/Entity;Lnet/minecraft/util/AxisAlignedBB;)Ljava/util/List;", world.name + " " + method.name + " " + method.desc); break startLoop; } } } if (methods.size() == 1) { addMethodMapping("net/minecraft/world/World getCollidingBoundingBoxes (Lnet/minecraft/entity/Entity;Lnet/minecraft/util/AxisAlignedBB;)Ljava/util/List;", world.name + " " + methods.get(0).name + " " + methods.get(0).desc); } } return true; } @Mapping(provides={ "net/minecraft/inventory/IInventory" }, providesMethods={ "net/minecraft/entity/player/EntityPlayer displayGUIChest (Lnet/minecraft/inventory/IInventory;)V", "net/minecraft/block/BlockChest isOcelotSittingOnChest (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;)Z", "net/minecraft/block/BlockChest isBlocked (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;)Z", "net/minecraft/block/BlockChest isBelowSolidBlock (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;)Z", "net/minecraft/block/state/IBlockWrapper isNormalCube ()Z" }, dependsMethods={ "net/minecraft/block/Block onBlockActivated (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;Lnet/minecraft/block/state/IBlockState;Lnet/minecraft/entity/player/EntityPlayer;Lnet/minecraft/util/MainOrOffHand;Lnet/minecraft/util/EnumFacing;FFF)Z" }, depends={ "net/minecraft/block/BlockChest", "net/minecraft/entity/player/EntityPlayer", "net/minecraft/world/World", "net/minecraft/util/BlockPos", "net/minecraft/entity/passive/EntityOcelot", "net/minecraft/block/state/IBlockState", "net/minecraft/block/state/IBlockWrapper" }) public boolean processBlockChestClass() { ClassNode blockChest = getClassNodeFromMapping("net/minecraft/block/BlockChest"); ClassNode entityPlayer = getClassNodeFromMapping("net/minecraft/entity/player/EntityPlayer"); ClassNode world = getClassNodeFromMapping("net/minecraft/world/World"); ClassNode blockPos = getClassNodeFromMapping("net/minecraft/util/BlockPos"); ClassNode ocelot = getClassNodeFromMapping("net/minecraft/entity/passive/EntityOcelot"); ClassNode iBlockState = getClassNodeFromMapping("net/minecraft/block/state/IBlockState"); ClassNode iBlockWrapper = getClassNodeFromMapping("net/minecraft/block/state/IBlockWrapper"); if (!MeddleUtil.notNull(blockChest, entityPlayer, world, blockPos, ocelot, iBlockState, iBlockWrapper)) return false; MethodNode onBlockActivated = getMethodNodeFromMapping(blockChest, "net/minecraft/block/Block onBlockActivated (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;Lnet/minecraft/block/state/IBlockState;Lnet/minecraft/entity/player/EntityPlayer;Lnet/minecraft/util/MainOrOffHand;Lnet/minecraft/util/EnumFacing;FFF)Z"); if (onBlockActivated == null) return false; for (AbstractInsnNode insn = onBlockActivated.instructions.getFirst(); insn != null; insn = insn.getNext()) { if (!(insn instanceof MethodInsnNode)) continue; MethodInsnNode mn = (MethodInsnNode)insn; if (!mn.owner.equals(entityPlayer.name)) continue; Type t = Type.getMethodType(mn.desc); Type[] args = t.getArgumentTypes(); if (args.length < 1 || args[0].getSort() != Type.OBJECT) continue; String className = args[0].getClassName(); ClassNode cn = getClassNode(className); if ((cn.access & Opcodes.ACC_INTERFACE) == 0) continue; addClassMapping("net/minecraft/inventory/IInventory", className); addMethodMapping("net/minecraft/entity/player/EntityPlayer displayGUIChest (Lnet/minecraft/inventory/IInventory;)V", entityPlayer.name + " " + mn.name + " " + mn.desc); break; } MethodNode isOcelotSittingOnChest = null; // private boolean isOcelotSittingOnChest(World worldIn, BlockPos pos) List<MethodNode> methods = getMatchingMethods(blockChest, null, assembleDescriptor("(", world, blockPos, ")Z")); for (Iterator<MethodNode> it = methods.iterator(); it.hasNext(); ) { MethodNode method = it.next(); // Find methods that refer to EntityOcelot List<TypeInsnNode> nodes = getAllInsnNodesOfType(method, TypeInsnNode.class); boolean hasIt = false; for (TypeInsnNode node: nodes) { if (node.desc.equals(ocelot.name)) hasIt = true; } if (!hasIt) it.remove(); } if (methods.size() == 1) { addMethodMapping("net/minecraft/block/BlockChest isOcelotSittingOnChest (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;)Z", blockChest.name + " " + methods.get(0).name + " " + methods.get(0).desc); isOcelotSittingOnChest = methods.get(0); } MethodNode isBlocked = null; // private boolean isBlocked(World worldIn, BlockPos pos) if (isOcelotSittingOnChest != null) { methods = getMatchingMethods(blockChest, null, assembleDescriptor("(", world, blockPos, ")Z")); for (Iterator<MethodNode> it = methods.iterator(); it.hasNext(); ) { MethodNode method = it.next(); List<MethodInsnNode> nodes = getAllInsnNodesOfType(method, MethodInsnNode.class); if (filterMethodInsnNodes(nodes, blockChest.name, isOcelotSittingOnChest).size() == 0) it.remove(); } if (methods.size() == 1) { addMethodMapping("net/minecraft/block/BlockChest isBlocked (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;)Z", blockChest.name + " " + methods.get(0).name + " " + methods.get(0).desc); isBlocked = methods.get(0); } } MethodInsnNode isBelowSolidBlockInsnNode = null; // private boolean isBelowSolidBlock(World worldIn, BlockPos pos) if (isBlocked != null) { List<MethodInsnNode> nodes = getAllInsnNodesOfType(isBlocked, MethodInsnNode.class); // Only two methods should be called in this, one is isOcelotSittingOnChest, so filter that out for (Iterator<MethodInsnNode> it = nodes.iterator(); it.hasNext(); ) { MethodInsnNode mn = it.next(); if (!mn.desc.equals(isOcelotSittingOnChest.desc)) { it.remove(); continue; } if (mn.owner.equals(blockChest.name)) { if (mn.name.equals(isBlocked.name) || mn.name.equals(isOcelotSittingOnChest.name)) it.remove(); } } if (nodes.size() == 1) { addMethodMapping("net/minecraft/block/BlockChest isBelowSolidBlock (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;)Z", blockChest.name + " " + nodes.get(0).name + " " + nodes.get(0).desc); isBelowSolidBlockInsnNode = nodes.get(0); } } MethodNode isBelowSolidBlock = getMethodNode(blockChest, isBelowSolidBlockInsnNode); if (isBelowSolidBlock != null) { List<MethodInsnNode> nodes = getAllInsnNodesOfType(isBelowSolidBlock, MethodInsnNode.class); nodes = filterMethodInsnNodes(nodes, iBlockState.name, "()Z"); if (nodes.size() == 1) { addMethodMapping("net/minecraft/block/state/IBlockWrapper isNormalCube ()Z", iBlockWrapper.name + " " + nodes.get(0).name + " ()Z"); } } return true; } @Mapping(provides={ "net/minecraft/world/IWorldNameable", "net/minecraft/util/IChatComponent" }, providesMethods={ "net/minecraft/world/IWorldNameable hasCustomName ()Z", "net/minecraft/world/IWorldNameable getName ()Ljava/lang/String;", "net/minecraft/world/IWorldNameable getDisplayName ()Lnet/minecraft/util/IChatComponent;" }, depends={ "net/minecraft/inventory/IInventory" }) public boolean processIWorldNameable() { ClassNode inventory = getClassNodeFromMapping("net/minecraft/inventory/IInventory"); if (inventory == null) return false; if (inventory.interfaces.size() != 1) return false; String className = inventory.interfaces.get(0); addClassMapping("net/minecraft/world/IWorldNameable", className); ClassNode worldNameable = getClassNode(className); if (worldNameable == null) return false; if (worldNameable.methods.size() != 3) return false; for (MethodNode method : worldNameable.methods) { Type t = Type.getMethodType(method.desc); Type returnType = t.getReturnType(); if (returnType.getSort() == Type.BOOLEAN) { addMethodMapping("net/minecraft/world/IWorldNameable hasCustomName ()Z", worldNameable.name + " " + method.name + " ()Z"); continue; } if (returnType.getSort() == Type.OBJECT) { if (returnType.getClassName().equals("java.lang.String")) { addMethodMapping("net/minecraft/world/IWorldNameable getName ()Ljava/lang/String;", worldNameable.name + " " + method.name + " " + method.desc); continue; } addClassMapping("net/minecraft/util/IChatComponent", returnType.getClassName()); addMethodMapping("net/minecraft/world/IWorldNameable getDisplayName ()Lnet/minecraft/util/IChatComponent;", worldNameable.name + " " + method.name + " " + method.desc); } } return true; } @Mapping(provides="net/minecraft/util/ChatComponentText", depends="net/minecraft/server/MinecraftServer") public boolean getChatComponentTextClass() { ClassNode server = getClassNode("net/minecraft/server/MinecraftServer"); if (server == null) return false; List<MethodNode> methods = getMatchingMethods(server, "run", "()V"); if (methods.size() != 1) return false; for (AbstractInsnNode insn = methods.get(0).instructions.getFirst(); insn != null; insn = insn.getNext()) { if (insn.getOpcode() != Opcodes.NEW) continue; TypeInsnNode tn = (TypeInsnNode)insn; if (searchConstantPoolForStrings(tn.desc, "TextComponent{text=\'")) { addClassMapping("net/minecraft/util/ChatComponentText", tn.desc); return true; } } return false; } @Mapping(provides={ "net/minecraft/inventory/InventoryBasic" }, depends={ "net/minecraft/entity/passive/EntityVillager", "net/minecraft/inventory/IInventory" }) public boolean processEntityVillagerClass() { ClassNode villager = getClassNodeFromMapping("net/minecraft/entity/passive/EntityVillager"); ClassNode inventory = getClassNodeFromMapping("net/minecraft/inventory/IInventory"); if (villager == null || inventory == null) return false; for (MethodNode method : villager.methods) { if (!method.name.equals("<init>")) continue; for (AbstractInsnNode insn = method.instructions.getFirst(); insn != null; insn = insn.getNext()) { if (insn.getOpcode() != Opcodes.NEW) continue; TypeInsnNode tn = (TypeInsnNode)insn; ClassNode node = getClassNode(tn.desc); if (node == null) continue; boolean isInventory = false; for (String iface : node.interfaces) { if (inventory.name.equals(iface)) isInventory = true; } if (!isInventory) continue; // TODO - Find more accurate way of detecting this class addClassMapping("net/minecraft/inventory/InventoryBasic", node.name); return true; } } return false; } @Mapping(provides = { "net/minecraft/util/DamageSource" }, providesFields={ "net/minecraft/entity/player/EntityPlayer inventory Lnet/minecraft/entity/player/InventoryPlayer;" }, providesMethods={ "net/minecraft/entity/EntityLivingBase damageEntity (Lnet/minecraft/util/DamageSource;F)V" }, depends={ "net/minecraft/entity/player/EntityPlayer", "net/minecraft/entity/player/InventoryPlayer", "net/minecraft/entity/EntityLivingBase" }) public boolean processEntityPlayerClass() { ClassNode entityPlayer = getClassNodeFromMapping("net/minecraft/entity/player/EntityPlayer"); ClassNode inventoryPlayer = getClassNodeFromMapping("net/minecraft/entity/player/InventoryPlayer"); ClassNode entityLivingBase = getClassNodeFromMapping("net/minecraft/entity/EntityLivingBase"); if (!MeddleUtil.notNull(entityPlayer, inventoryPlayer, entityLivingBase)) return false; for (MethodNode method : entityPlayer.methods) { Type t = Type.getMethodType(method.desc); Type[] args = t.getArgumentTypes(); if (args.length != 1 || args[0].getSort() != Type.OBJECT || t.getReturnType().getSort() != Type.VOID) continue; //System.out.println(method.name + " " + method.desc); } List<FieldNode> fields = getMatchingFields(entityPlayer, null, "L" + inventoryPlayer.name + ";"); if (fields.size() == 1) { addFieldMapping("net/minecraft/entity/player/EntityPlayer inventory Lnet/minecraft/entity/player/InventoryPlayer;", entityPlayer.name + " " + fields.get(0).name + " " + fields.get(0).desc); } List<MethodNode> methods = getMatchingMethods(entityPlayer, null, null); String damageSource = null; for (Iterator<MethodNode> it = methods.iterator(); it.hasNext();) { MethodNode methodNode = it.next(); Type[] params = Type.getArgumentTypes(methodNode.desc); if(params.length == 2) { if(methodNode.access == Opcodes.ACC_PROTECTED && params[0].getSort() == Type.OBJECT && params[1].getSort() == Type.FLOAT && Type.getReturnType(methodNode.desc).getSort() == Type.VOID) { damageSource = params[0].getClassName(); continue; } } it.remove(); } if (methods.size() == 1 && damageSource != null && searchConstantPoolForStrings(damageSource, "starve")) { addClassMapping("net/minecraft/util/DamageSource", damageSource); addMethodMapping("net/minecraft/entity/EntityLivingBase damageEntity (Lnet/minecraft/util/DamageSource;F)V", entityLivingBase.name + " " + methods.get(0).name + " " + methods.get(0).desc); } return true; } @Mapping(depends = { "net/minecraft/util/DamageSource", "net/minecraft/entity/EntityLivingBase", "net/minecraft/util/IChatComponent" }, providesFields = { "net/minecraft/util/DamageSource inFire Lnet/minecraft/util/DamageSource;", "net/minecraft/util/DamageSource lightningBolt Lnet/minecraft/util/DamageSource;", "net/minecraft/util/DamageSource onFire Lnet/minecraft/util/DamageSource;", "net/minecraft/util/DamageSource lava Lnet/minecraft/util/DamageSource;", "net/minecraft/util/DamageSource hotFloor Lnet/minecraft/util/DamageSource;", "net/minecraft/util/DamageSource inWall Lnet/minecraft/util/DamageSource;", "net/minecraft/util/DamageSource drown Lnet/minecraft/util/DamageSource;", "net/minecraft/util/DamageSource starve Lnet/minecraft/util/DamageSource;", "net/minecraft/util/DamageSource cactus Lnet/minecraft/util/DamageSource;", "net/minecraft/util/DamageSource fall Lnet/minecraft/util/DamageSource;", "net/minecraft/util/DamageSource flyIntoWall Lnet/minecraft/util/DamageSource;", "net/minecraft/util/DamageSource outOfWorld Lnet/minecraft/util/DamageSource;", "net/minecraft/util/DamageSource generic Lnet/minecraft/util/DamageSource;", "net/minecraft/util/DamageSource magic Lnet/minecraft/util/DamageSource;", "net/minecraft/util/DamageSource wither Lnet/minecraft/util/DamageSource;", "net/minecraft/util/DamageSource anvil Lnet/minecraft/util/DamageSource;", "net/minecraft/util/DamageSource fallingBlock Lnet/minecraft/util/DamageSource;", "net/minecraft/util/DamageSource dragonBreath Lnet/minecraft/util/DamageSource;", }, providesMethods = { "net/minecraft/util/DamageSource getDeathMessage (Lnet/minecraft/entity/EntityLivingBase;)Lnet/minecraft/util/IChatComponent;" }) public boolean processDamageSourceClass(){ ClassNode damageSource = getClassNodeFromMapping("net/minecraft/util/DamageSource"); ClassNode livingBase = getClassNodeFromMapping("net/minecraft/entity/EntityLivingBase"); ClassNode iChatComponent = getClassNodeFromMapping("net/minecraft/util/IChatComponent"); if(MeddleUtil.notNull(damageSource, livingBase, iChatComponent)){ List<MethodNode> methods = damageSource.methods; List<String> sourceStrings = new ArrayList<>(); for(MethodNode method : methods){ if(method.name.equals("<clinit>")){ MethodCallVisitor visitor = new MethodCallVisitor(method, false); for(MethodCall call : visitor){ MethodInsnNode node = call.methodNode; if(node.name.equals("<init>") && call.args.length == 2){ String name = (String) call.args[1]; if(name != null){ sourceStrings.add(name); } } } } } List<FieldNode> possibleFields = new ArrayList<>(); for(FieldNode field : damageSource.fields){ if((field.access & Opcodes.ACC_PUBLIC) != 0 && (field.access & Opcodes.ACC_STATIC) != 0){ possibleFields.add(field); } } if(possibleFields.size() == sourceStrings.size()){ for(String fieldName : sourceStrings){ FieldNode node = possibleFields.get(sourceStrings.indexOf(fieldName)); addFieldMapping("net/minecraft/util/DamageSource " + fieldName + " Lnet/minecraft/util/DamageSource;", damageSource.name + " " + node.name + " " + node.desc); } } // getDeathMessage methods = getMatchingMethods(damageSource, null, assembleDescriptor("(", livingBase, ")", iChatComponent)); if(methods.size() == 1){ addMethodMapping("net/minecraft/util/DamageSource getDeathMessage (Lnet/minecraft/entity/EntityLivingBase;)Lnet/minecraft/util/IChatComponent;", damageSource.name + " " + methods.get(0).name + " " + methods.get(0).desc); } } return true; } @Mapping(provides={ "net/minecraft/nbt/NBTTagCompound", "net/minecraft/nbt/NBTBase", "net/minecraft/nbt/NBTTagEnd", "net/minecraft/nbt/NBTTagByte", "net/minecraft/nbt/NBTTagShort", "net/minecraft/nbt/NBTTagInt", "net/minecraft/nbt/NBTTagLong", "net/minecraft/nbt/NBTTagFloat", "net/minecraft/nbt/NBTTagDouble", "net/minecraft/nbt/NBTTagByteArray", "net/minecraft/nbt/NBTTagString", "net/minecraft/nbt/NBTTagList", "net/minecraft/nbt/NBTTagIntArray" }, providesMethods={ "net/minecraft/item/ItemStack writeToNBT (Lnet/minecraft/nbt/NBTTagCompound;)Lnet/minecraft/nbt/NBTTagCompound;", "net/minecraft/nbt/NBTBase createNewByType (B)Lnet/minecraft/nbt/NBTBase;" }, depends={ "net/minecraft/item/ItemStack" }) public boolean getNBTClasses() { ClassNode itemStack = getClassNodeFromMapping("net/minecraft/item/ItemStack"); if (itemStack == null) return false; String tagCompoundName = null; // Find: public NBTTagCompound writeToNBT(NBTTagCompound) for (MethodNode method : itemStack.methods) { Type t = Type.getMethodType(method.desc); Type[] args = t.getArgumentTypes(); Type returnType = t.getReturnType(); if (args.length != 1) continue; if (args[0].getSort() != Type.OBJECT || returnType.getSort() != Type.OBJECT) continue; if (!args[0].getClassName().equals(returnType.getClassName())) continue; tagCompoundName = returnType.getClassName(); if (searchConstantPoolForStrings(tagCompoundName, "Tried to read NBT tag with too high complexity, depth > 512")) { addClassMapping("net/minecraft/nbt/NBTTagCompound", tagCompoundName); addMethodMapping("net/minecraft/item/ItemStack writeToNBT (Lnet/minecraft/nbt/NBTTagCompound;)Lnet/minecraft/nbt/NBTTagCompound;", itemStack.name + " " + method.name + " " + method.desc); break; } tagCompoundName = null; } if (tagCompoundName == null) return false; ClassNode tagCompound = getClassNode(tagCompoundName); if (tagCompound == null) return false; ClassNode tagBase = getClassNode(tagCompound.superName); if (tagBase == null) return false; if (!searchConstantPoolForStrings(tagBase.name, "END", "BYTE", "SHORT")) return false; addClassMapping("net/minecraft/nbt/NBTBase", tagBase.name); Map<Integer, String> nbtClassesMap = new HashMap<Integer, String>(); // We want: protected static NBTBase createNewByType(byte id) for (MethodNode method : tagBase.methods) { Type t = Type.getMethodType(method.desc); Type[] args = t.getArgumentTypes(); Type returnType = t.getReturnType(); if (args.length != 1) continue; if (args[0].getSort() != Type.BYTE) continue; if (!returnType.getClassName().equals(tagBase.name)) continue; addMethodMapping("net/minecraft/nbt/NBTBase createNewByType (B)Lnet/minecraft/nbt/NBTBase;", tagBase.name + " " + method.name + " " + method.desc); // Find the tableswitch to parse for (AbstractInsnNode insn = method.instructions.getFirst(); insn != null; insn = insn.getNext()) { if (insn.getOpcode() != Opcodes.TABLESWITCH) continue; TableSwitchInsnNode table = (TableSwitchInsnNode)insn; // There's 12 NBT types, otherwise this table isn't reliable if (table.labels.size() != 12) continue; for (int n = 0; n < 12; n++) { AbstractInsnNode destInsn = table.labels.get(n); AbstractInsnNode nextReal = getNextRealOpcode(destInsn); // Every jump target should be creating a new instance of an NBT type if (nextReal.getOpcode() != Opcodes.NEW) return false; nbtClassesMap.put(n, ((TypeInsnNode)nextReal).desc); } } } for (Integer key : nbtClassesMap.keySet()) { String className = nbtClassesMap.get(key); if (className == null) continue; switch (key) { case 0: addClassMapping("net/minecraft/nbt/NBTTagEnd", className); continue; case 1: addClassMapping("net/minecraft/nbt/NBTTagByte", className); continue; case 2: addClassMapping("net/minecraft/nbt/NBTTagShort", className); continue; case 3: addClassMapping("net/minecraft/nbt/NBTTagInt", className); continue; case 4: addClassMapping("net/minecraft/nbt/NBTTagLong", className); continue; case 5: addClassMapping("net/minecraft/nbt/NBTTagFloat", className); continue; case 6: addClassMapping("net/minecraft/nbt/NBTTagDouble", className); continue; case 7: addClassMapping("net/minecraft/nbt/NBTTagByteArray", className); continue; case 8: addClassMapping("net/minecraft/nbt/NBTTagString", className); continue; case 9: addClassMapping("net/minecraft/nbt/NBTTagList", className); continue; case 10: // Already added this earlier continue; case 11: addClassMapping("net/minecraft/nbt/NBTTagIntArray", className); continue; } } return true; } @Mapping(provides={ "net/minecraft/nbt/NBTPrimitive" }, providesMethods={ "net/minecraft/nbt/NBTTagCompound getTagList (Ljava/lang/String;I)Lnet/minecraft/nbt/NBTTagList;", "net/minecraft/nbt/NBTBase hashCode ()I", "net/minecraft/nbt/NBTTagCompound tagCount ()I", "net/minecraft/nbt/NBTTagList tagCount ()I", "net/minecraft/nbt/NBTTagList getTagType ()I", "net/minecraft/nbt/NBTTagList getCompoundTagAt (I)Lnet/minecraft/nbt/NBTTagCompound;", "net/minecraft/nbt/NBTTagCompound getByte (Ljava/lang/String;)B", "net/minecraft/nbt/NBTTagCompound setByte (Ljava/lang/String;B)V", "net/minecraft/nbt/NBTTagCompound hasKey (Ljava/lang/String;I)Z", "net/minecraft/nbt/NBTTagCompound getTagType (Ljava/lang/String;)B", "net/minecraft/nbt/NBTTagList appendTag (Lnet/minecraft/nbt/NBTBase;)V", "net/minecraft/nbt/NBTTagCompound setTag (Ljava/lang/String;Lnet/minecraft/nbt/NBTBase;)V", "net/minecraft/nbt/NBTTagCompound getString (Ljava/lang/String;)Ljava/lang/String;", "net/minecraft/nbt/NBTTagCompound setString (Ljava/lang/String;Ljava/lang/String;)V", "net/minecraft/nbt/NBTTagCompound getInteger (Ljava/lang/String;)I", "net/minecraft/nbt/NBTTagCompound setInteger (Ljava/lang/String;I)V", "net/minecraft/nbt/NBTTagCompound removeTag (Ljava/lang/String;)V" }, providesFields={ "net/minecraft/nbt/NBTTagList tagType B" }, depends={ "net/minecraft/nbt/NBTTagCompound", "net/minecraft/nbt/NBTTagList", "net/minecraft/nbt/NBTBase" }) public boolean processNBTTagCompound() { ClassNode tagCompound = getClassNodeFromMapping("net/minecraft/nbt/NBTTagCompound"); ClassNode tagList = getClassNodeFromMapping("net/minecraft/nbt/NBTTagList"); ClassNode tagBase = getClassNodeFromMapping("net/minecraft/nbt/NBTBase"); if (tagCompound == null || tagList == null || tagBase == null) return false; // public NBTTagList getTagList(String, int) List<MethodNode> methods = getMatchingMethods(tagCompound, null, "(Ljava/lang/String;I)L" + tagList.name + ";"); if (methods.size() == 1) { addMethodMapping("net/minecraft/nbt/NBTTagCompound getTagList (Ljava/lang/String;I)Lnet/minecraft/nbt/NBTTagList;", tagCompound.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public int hashCode() String hashCode_name = null; methods = getMatchingMethods(tagBase, null, "()I"); if (methods.size() == 1) { hashCode_name = methods.get(0).name; addMethodMapping("net/minecraft/nbt/NBTBase hashCode ()I", tagBase.name + " " + hashCode_name + " ()I"); } // public NBTTagCompound.tagCount()I methods = getMatchingMethods(tagCompound, null, "()I"); for (Iterator<MethodNode> iterator = methods.iterator(); iterator.hasNext();) { if (iterator.next().name.equals(hashCode_name)) iterator.remove(); } if (methods.size() == 1) { addMethodMapping("net/minecraft/nbt/NBTTagCompound tagCount ()I", tagCompound.name + " " + methods.get(0).name + " ()I"); } // public NBTTagList.getTagType()I methods = getMatchingMethods(tagList, null, "()I"); for (Iterator<MethodNode> iterator = methods.iterator(); iterator.hasNext();) { MethodNode method = iterator.next(); if (method.name.equals(hashCode_name)) { iterator.remove(); continue; } for (AbstractInsnNode insn = method.instructions.getFirst(); insn != null; insn = insn.getNext()) { if (insn.getOpcode() != Opcodes.GETFIELD) continue; FieldInsnNode fn = (FieldInsnNode)insn; if (fn.owner.equals(tagList.name) && fn.desc.equals("B")) { addFieldMapping("net/minecraft/nbt/NBTTagList tagType B", tagList.name + " " + fn.name + " B"); addMethodMapping("net/minecraft/nbt/NBTTagList getTagType ()I", tagList.name + " " + method.name + " ()I"); iterator.remove(); break; } } } // public NBTTagList.tagCount()I if (methods.size() == 1) { addMethodMapping("net/minecraft/nbt/NBTTagList tagCount ()I", tagList.name + " " + methods.get(0).name + " ()I"); } // public NBTTagList.getCompoundTagAt(I)Lnet/minecraft/nbt/NBTTagCompound; methods = getMatchingMethods(tagList, null, "(I)L" + tagCompound.name + ";"); if (methods.size() == 1) { addMethodMapping("net/minecraft/nbt/NBTTagList getCompoundTagAt (I)Lnet/minecraft/nbt/NBTTagCompound;", tagList.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public boolean hasKey(String key, int type) methods = getMatchingMethods(tagCompound, null, "(Ljava/lang/String;I)Z"); if (methods.size() == 1) { addMethodMapping("net/minecraft/nbt/NBTTagCompound hasKey (Ljava/lang/String;I)Z", tagCompound.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // Find getByte and getTagType methods = getMatchingMethods(tagCompound, null, "(Ljava/lang/String;)B"); if (methods.size() == 2) { for (MethodNode method : methods) { boolean hasBase = false; boolean hasPrimitive = false; for (AbstractInsnNode insn = method.instructions.getFirst(); insn != null; insn = insn.getNext()) { if (insn.getOpcode() != Opcodes.CHECKCAST) continue; TypeInsnNode tn = (TypeInsnNode)insn; if (tn.desc.equals(tagBase.name)) hasBase = true; // NBTBase$NBTPrimitive changed to standalone class in 1.10 else //if (tn.desc.startsWith(tagBase.name + "$")) { { hasPrimitive = true; addClassMapping("net/minecraft/nbt/NBTPrimitive", tn.desc); } } // public byte getByte(String key) if (hasPrimitive && !hasBase) { addMethodMapping("net/minecraft/nbt/NBTTagCompound getByte (Ljava/lang/String;)B", tagCompound.name + " " + method.name + " " + method.desc); } // public byte getTagType(String key) else if (!hasPrimitive && hasBase) { addMethodMapping("net/minecraft/nbt/NBTTagCompound getTagType (Ljava/lang/String;)B", tagCompound.name + " " + method.name + " " + method.desc); } } } // public void setByte(String key, byte value) methods = getMatchingMethods(tagCompound, null, "(Ljava/lang/String;B)V"); if (methods.size() == 1) { addMethodMapping("net/minecraft/nbt/NBTTagCompound setByte (Ljava/lang/String;B)V", tagCompound.name + " " + methods.get(0).name + " (Ljava/lang/String;B)V"); } // public void appendTag(NBTBase nbt) methods = getMatchingMethods(tagList, null, "(L" + tagBase.name + ";)V"); if (methods.size() == 1) { addMethodMapping("net/minecraft/nbt/NBTTagList appendTag (Lnet/minecraft/nbt/NBTBase;)V", tagList.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public void setTag(String key, NBTBase value) methods = getMatchingMethods(tagCompound, null, "(Ljava/lang/String;L" + tagBase.name + ";)V"); if (methods.size() == 1) { addMethodMapping("net/minecraft/nbt/NBTTagCompound setTag (Ljava/lang/String;Lnet/minecraft/nbt/NBTBase;)V", tagCompound.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public String getString(String key) methods = getMatchingMethods(tagCompound, null, "(Ljava/lang/String;)Ljava/lang/String;"); if (methods.size() == 1) { addMethodMapping("net/minecraft/nbt/NBTTagCompound getString (Ljava/lang/String;)Ljava/lang/String;", tagCompound.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public void setString(String key, String value) methods = getMatchingMethods(tagCompound, null, "(Ljava/lang/String;Ljava/lang/String;)V"); if (methods.size() == 1) { addMethodMapping("net/minecraft/nbt/NBTTagCompound setString (Ljava/lang/String;Ljava/lang/String;)V", tagCompound.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public int getInteger(String key) methods = getMatchingMethods(tagCompound, null, "(Ljava/lang/String;)I"); if (methods.size() == 1) { addMethodMapping("net/minecraft/nbt/NBTTagCompound getInteger (Ljava/lang/String;)I", tagCompound.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public void setInteger(String key, int value) methods = getMatchingMethods(tagCompound, null, "(Ljava/lang/String;I)V"); if (methods.size() == 1) { addMethodMapping("net/minecraft/nbt/NBTTagCompound setInteger (Ljava/lang/String;I)V", tagCompound.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public void removeTag(String key) methods = getMatchingMethods(tagCompound, null, "(Ljava/lang/String;)V"); if (methods.size() == 1) { addMethodMapping("net/minecraft/nbt/NBTTagCompound removeTag (Ljava/lang/String;)V", tagCompound.name + " " + methods.get(0).name + " " + methods.get(0).desc); } return true; } @Mapping(providesFields={ "net/minecraft/inventory/InventoryBasic slotsCount I", "net/minecraft/inventory/InventoryBasic inventoryTitle Ljava/lang/String;", "net/minecraft/inventory/InventoryBasic hasCustomName Z", "net/minecraft/inventory/InventoryBasic inventoryContent Lnet/minecraft/util/MCList;" }, providesMethods={ "net/minecraft/inventory/IInventory getSizeInventory ()I", "net/minecraft/inventory/IInventory getInventoryStackLimit ()I", "net/minecraft/inventory/IInventory getFieldCount ()I", "net/minecraft/inventory/IInventory setInventorySlotContents (ILnet/minecraft/item/ItemStack;)V", "net/minecraft/inventory/IInventory getStackInSlot (I)Lnet/minecraft/item/ItemStack;", "net/minecraft/inventory/IInventory getStackInSlotOnClosing (I)Lnet/minecraft/item/ItemStack;", "net/minecraft/inventory/IInventory markDirty ()V", "net/minecraft/inventory/IInventory clear ()V", "net/minecraft/inventory/IInventory decrStackSize (II)Lnet/minecraft/item/ItemStack;", "net/minecraft/inventory/IInventory isUseableByPlayer (Lnet/minecraft/entity/player/EntityPlayer;)Z", "net/minecraft/inventory/IInventory isItemValidForSlot (ILnet/minecraft/item/ItemStack;)Z", "net/minecraft/inventory/IInventory getField (I)I", "net/minecraft/inventory/IInventory setField (II)V" }, depends={ "net/minecraft/inventory/IInventory", "net/minecraft/inventory/InventoryBasic", "net/minecraft/item/ItemStack", "net/minecraft/entity/player/EntityPlayer", "net/minecraft/util/MCList" }) public boolean processInventoryBasicClass() { ClassNode iInventory = getClassNodeFromMapping("net/minecraft/inventory/IInventory"); ClassNode inventoryBasic = getClassNodeFromMapping("net/minecraft/inventory/InventoryBasic"); ClassNode itemStack = getClassNodeFromMapping("net/minecraft/item/ItemStack"); ClassNode entityPlayer = getClassNodeFromMapping("net/minecraft/entity/player/EntityPlayer"); ClassNode mcList = getClassNodeFromMapping("net/minecraft/util/MCList"); if (!MeddleUtil.notNull(iInventory, inventoryBasic, itemStack, entityPlayer, mcList)) return false; String slotsCountField = null; String inventoryTitleField = null; String inventoryContentsField = null; String hasCustomNameField = null; List<FieldNode> fields = getMatchingFields(inventoryBasic, null, "I"); if (fields.size() == 1) { slotsCountField = fields.get(0).name; addFieldMapping("net/minecraft/inventory/InventoryBasic slotsCount I", inventoryBasic.name + " " + slotsCountField + " I"); } fields = getMatchingFields(inventoryBasic, null, "Ljava/lang/String;"); if (fields.size() == 1) { inventoryTitleField = fields.get(0).name; addFieldMapping("net/minecraft/inventory/InventoryBasic inventoryTitle Ljava/lang/String;", inventoryBasic.name + " " + inventoryTitleField + " Ljava/lang/String;"); } fields = getMatchingFields(inventoryBasic, null, "Z"); if (fields.size() == 1) { hasCustomNameField = fields.get(0).name; addFieldMapping("net/minecraft/inventory/InventoryBasic hasCustomName Z", inventoryBasic.name + " " + hasCustomNameField + " Z"); } // 16w32? changed java list to MCList fields = getMatchingFields(inventoryBasic, null, "L" + mcList.name + ";"); if (fields.size() == 1) { addFieldMapping("net/minecraft/inventory/InventoryBasic inventoryContent Lnet/minecraft/util/MCList;", inventoryBasic.name + " " + fields.get(0).name + " " + fields.get(0).desc); } // changeListener fields = getMatchingFields(inventoryBasic, null, "Ljava/util/List;"); if(fields.size() == 1){ addFieldMapping("net/minecraft/inventory/InventoryBasic changeListener Ljava/util/List;", inventoryBasic.name + " " + fields.get(0).name + " " + fields.get(0).desc); } // Parse methods that only return an int. // There should only be three. List<MethodNode> methods = getMatchingMethods(inventoryBasic, null, "()I"); if (methods.size() != 3) return false; for (MethodNode method : methods) { AbstractInsnNode firstReal = getNextRealOpcode(method.instructions.getFirst()); // Find IInventory.getSizeInventory()I if (firstReal.getOpcode() == Opcodes.ALOAD) { AbstractInsnNode nextNode = firstReal.getNext(); if (nextNode != null && nextNode.getOpcode() == Opcodes.GETFIELD) { FieldInsnNode fn = (FieldInsnNode)nextNode; if (fn.owner.equals(inventoryBasic.name) && fn.name.equals(slotsCountField)) { addMethodMapping("net/minecraft/inventory/IInventory getSizeInventory ()I", iInventory.name + " " + method.name + " " + method.desc); continue; } } } // Find IInventory.getInventoryStackLimit()I if (firstReal instanceof IntInsnNode) { IntInsnNode in = (IntInsnNode)firstReal; if (in.operand == 64) { addMethodMapping("net/minecraft/inventory/IInventory getInventoryStackLimit ()I", iInventory.name + " " + method.name + " " + method.desc); continue; } } // Find IInventory.getFieldCount()I if (firstReal.getOpcode() == Opcodes.ICONST_0) { AbstractInsnNode nextNode = firstReal.getNext(); if (nextNode != null && nextNode.getOpcode() == Opcodes.IRETURN) { addMethodMapping("net/minecraft/inventory/IInventory getFieldCount ()I", iInventory.name + " " + method.name + " " + method.desc); continue; } } } // public void setInventorySlotContents(int index, ItemStack stack) methods = getMatchingMethods(inventoryBasic, null, "(IL" + itemStack.name + ";)V"); if (methods.size() == 1) { addMethodMapping("net/minecraft/inventory/IInventory setInventorySlotContents (ILnet/minecraft/item/ItemStack;)V", iInventory.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // Get the two methods with decriptor (I)Lnet/minecraft/item/ItemStack; methods = getMatchingMethods(inventoryBasic, null, "(I)L" + itemStack.name + ";"); if (methods.size() != 2) return false; for (MethodNode method : methods) { short iLoadCounter = 0; for (AbstractInsnNode insn = method.instructions.getFirst(); insn != null; insn = insn.getNext()) { if(insn.getOpcode() == Opcodes.ILOAD) iLoadCounter++; } if(iLoadCounter == 3){ // public ItemStack getStackInSlot(int) addMethodMapping("net/minecraft/inventory/IInventory getStackInSlot (I)Lnet/minecraft/item/ItemStack;", iInventory.name + " " + method.name + " " + method.desc); } if(iLoadCounter == 2){ // ItemStack getStackInSlotOnClosing(int) addMethodMapping("net/minecraft/inventory/IInventory getStackInSlotOnClosing (I)Lnet/minecraft/item/ItemStack;", iInventory.name + " " + method.name + " " + method.desc); } } methods = getMatchingMethods(inventoryBasic, null, "()V"); if (methods.size() != 2) return false; for (MethodNode method : methods) { boolean hasList = false; boolean hasArray = false; for (AbstractInsnNode insn = method.instructions.getFirst(); insn != null; insn = insn.getNext()) { if (insn.getOpcode() == Opcodes.GETFIELD) { FieldInsnNode fn = (FieldInsnNode)insn; if (fn.owner.equals(inventoryBasic.name) && fn.desc.equals("Ljava/util/List;")) hasList = true; if (fn.owner.equals(inventoryBasic.name) && fn.desc.equals("L" + mcList.name + ";")) hasArray = true; } } // public void markDirty() if (hasList && !hasArray) { addMethodMapping("net/minecraft/inventory/IInventory markDirty ()V", iInventory.name + " " + method.name + " " + method.desc); } // public void clear() else if (!hasList && hasArray) { addMethodMapping("net/minecraft/inventory/IInventory clear ()V", iInventory.name + " " + method.name + " " + method.desc); } } // public ItemStack decrStackSize(int index, int count) methods = getMatchingMethods(inventoryBasic, null, "(II)L" + itemStack.name + ";"); if (methods.size() == 1) { addMethodMapping("net/minecraft/inventory/IInventory decrStackSize (II)Lnet/minecraft/item/ItemStack;", iInventory.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // boolean isUseableByPlayer(EntityPlayer player) methods = getMatchingMethods(inventoryBasic, null, "(L" + entityPlayer.name + ";)Z"); if (methods.size() == 1) { addMethodMapping("net/minecraft/inventory/IInventory isUseableByPlayer (Lnet/minecraft/entity/player/EntityPlayer;)Z", iInventory.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // boolean isItemValidForSlot(int index, ItemStack stack) methods = getMatchingMethods(inventoryBasic, null, "(IL" + itemStack.name + ";)Z"); if (methods.size() == 1) { addMethodMapping("net/minecraft/inventory/IInventory isItemValidForSlot (ILnet/minecraft/item/ItemStack;)Z", iInventory.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // int getField(int id) methods = getMatchingMethods(inventoryBasic, null, "(I)I"); if (methods.size() == 1) { addMethodMapping("net/minecraft/inventory/IInventory getField (I)I", iInventory.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // void setField(int id, int value) methods = getMatchingMethods(inventoryBasic, null, "(II)V"); if (methods.size() == 1) { addMethodMapping("net/minecraft/inventory/IInventory setField (II)V", iInventory.name + " " + methods.get(0).name + " " + methods.get(0).desc); } return true; } @Mapping(providesFields={ "net/minecraft/item/Item unlocalizedName Ljava/lang/String;" }, providesMethods={ "net/minecraft/item/Item getIdFromItem (Lnet/minecraft/item/Item;)I", "net/minecraft/item/Item getItemById (I)Lnet/minecraft/item/Item;", "net/minecraft/item/Item getItemFromBlock (Lnet/minecraft/block/Block;)Lnet/minecraft/item/Item;", "net/minecraft/item/Item getByNameOrId (Ljava/lang/String;)Lnet/minecraft/item/Item;", "net/minecraft/item/Item setUnlocalizedName (Ljava/lang/String;)Lnet/minecraft/item/Item;", "net/minecraft/item/Item getItemStackDisplayName (Lnet/minecraft/item/ItemStack;)Ljava/lang/String;", "net/minecraft/item/Item getUnlocalizedNameInefficiently (Lnet/minecraft/item/ItemStack;)Ljava/lang/String;", "net/minecraft/item/Item getUnlocalizedName (Lnet/minecraft/item/ItemStack;)Ljava/lang/String;", "net/minecraft/item/Item getUnlocalizedName ()Ljava/lang/String;" }, dependsMethods={ "net/minecraft/item/ItemStack getDisplayName ()Ljava/lang/String;" }, depends={ "net/minecraft/item/Item", "net/minecraft/block/Block", "net/minecraft/item/ItemStack" }) public boolean getItemClassMethods() { ClassNode item = getClassNode(getClassMapping("net/minecraft/item/Item")); ClassNode block = getClassNode(getClassMapping("net/minecraft/block/Block")); ClassNode itemStack = getClassNode(getClassMapping("net/minecraft/item/ItemStack")); if (!MeddleUtil.notNull(item, block, itemStack)) return false; // Keep a local list because we'll remove them as we go to improve detection List<MethodNode> itemMethods = new ArrayList<MethodNode>(); itemMethods.addAll(item.methods); List<MethodNode> methods; //public static int getIdFromItem(Item itemIn) methods = getMethodsWithDescriptor(itemMethods, "(L" + item.name + ";)I"); methods = removeMethodsWithoutFlags(methods, Opcodes.ACC_STATIC); //for (MethodNode mn : methods) System.out.println(mn.name + " " + mn.desc); if (methods.size() == 1) { MethodNode mn = methods.get(0); itemMethods.remove(mn); addMethodMapping("net/minecraft/item/Item getIdFromItem (Lnet/minecraft/item/Item;)I", item.name + " " + mn.name + " " + mn.desc); } // A hack since 15w34c duplicated the method for seemingly no reason else if (methods.size() == 2) { MethodNode mn1 = methods.get(0); MethodNode mn2 = methods.get(1); if (mn1.instructions.size() == mn2.instructions.size()) { int size = mn1.instructions.size(); boolean nomatch = false; for (int n = 0; n < size; n++) { if (mn1.instructions.get(n).getOpcode() != mn2.instructions.get(n).getOpcode()) { nomatch = true; break; } } if (!nomatch) { // Use the second one, since it seems to be the original addMethodMapping("net/minecraft/item/Item getIdFromItem (Lnet/minecraft/item/Item;)I", item.name + " " + mn2.name + " " + mn2.desc); // Not going to put this in the 'provides' list in case it's removed, but we'll map it addMethodMapping("net/minecraft/item/Item getIdFromItem2 (Lnet/minecraft/item/Item;)I", item.name + " " + mn1.name + " " + mn1.desc); } } } //public static Item getItemById(int id) methods = getMethodsWithDescriptor(itemMethods, "(I)L" + item.name + ";"); methods = removeMethodsWithoutFlags(methods, Opcodes.ACC_STATIC); if (methods.size() == 1) { MethodNode mn = methods.get(0); itemMethods.remove(mn); addMethodMapping("net/minecraft/item/Item getItemById (I)Lnet/minecraft/item/Item;", item.name + " " + mn.name + " " + mn.desc); } //public static Item getItemFromBlock(Block blockIn) methods = getMethodsWithDescriptor(itemMethods, "(L" + block.name + ";)L" + item.name + ";"); methods = removeMethodsWithoutFlags(methods, Opcodes.ACC_STATIC); if (methods.size() == 1) { MethodNode mn = methods.get(0); itemMethods.remove(mn); addMethodMapping("net/minecraft/item/Item getItemFromBlock (Lnet/minecraft/block/Block;)Lnet/minecraft/item/Item;", item.name + " " + mn.name + " " + mn.desc); } //public static Item getByNameOrId(String id) methods = getMethodsWithDescriptor(itemMethods, "(Ljava/lang/String;)L" + item.name + ";"); methods = removeMethodsWithoutFlags(methods, Opcodes.ACC_STATIC); if (methods.size() == 1) { MethodNode mn = methods.get(0); itemMethods.remove(mn); addMethodMapping("net/minecraft/item/Item getByNameOrId (Ljava/lang/String;)Lnet/minecraft/item/Item;", item.name + " " + mn.name + " " + mn.desc); } // Item setUnlocalizedName(String) methods = getMethodsWithDescriptor(itemMethods, "(Ljava/lang/String;)L" + item.name + ";"); methods = removeMethodsWithFlags(methods, Opcodes.ACC_STATIC); if (methods.size() == 1) { MethodNode mn = methods.get(0); itemMethods.remove(mn); addMethodMapping("net/minecraft/item/Item setUnlocalizedName (Ljava/lang/String;)Lnet/minecraft/item/Item;", item.name + " " + mn.name + " " + mn.desc); for (AbstractInsnNode insn = mn.instructions.getFirst(); insn != null; insn = insn.getNext()) { if (insn.getOpcode() == Opcodes.PUTFIELD) { FieldInsnNode fn = (FieldInsnNode)insn; if (fn.desc.equals("Ljava/lang/String;")) { addFieldMapping("net/minecraft/item/Item unlocalizedName Ljava/lang/String;", item.name + " " + fn.name + " " + fn.desc); break; } } } } MethodNode itemStack_getDisplayName = getMethodNodeFromMapping(itemStack, "net/minecraft/item/ItemStack getDisplayName ()Ljava/lang/String;"); if (itemStack_getDisplayName == null) return false; String getItemStackDisplayName_name = null; String getItemStackDisplayName_desc = "(L" + itemStack.name + ";)Ljava/lang/String;"; // public String getItemStackDisplayName(ItemStack param0) for (AbstractInsnNode insn = itemStack_getDisplayName.instructions.getFirst(); insn != null; insn = insn.getNext()) { if (insn.getOpcode() != Opcodes.INVOKEVIRTUAL) continue; MethodInsnNode mn = (MethodInsnNode)insn; if (mn.owner.equals(item.name) && mn.desc.equals(getItemStackDisplayName_desc)) { getItemStackDisplayName_name = mn.name; break; } } if (getItemStackDisplayName_name == null) return false; MethodNode getItemStackDisplayName = getMethodNode(item, item.name + " " + getItemStackDisplayName_name + " " + getItemStackDisplayName_desc); if (getItemStackDisplayName == null) return false; addMethodMapping("net/minecraft/item/Item getItemStackDisplayName (Lnet/minecraft/item/ItemStack;)Ljava/lang/String;", item.name + " " + getItemStackDisplayName.name + " " + getItemStackDisplayName.desc); //public String getUnlocalizedNameInefficiently(ItemStack param0) String getUnlocalizedNameInefficiently_name = null; for (AbstractInsnNode insn = getItemStackDisplayName.instructions.getFirst(); insn != null; insn = insn.getNext()) { if (insn.getOpcode() != Opcodes.INVOKEVIRTUAL) continue; MethodInsnNode mn = (MethodInsnNode)insn; if (mn.owner.equals(item.name) && mn.desc.equals(getItemStackDisplayName_desc)) { getUnlocalizedNameInefficiently_name = mn.name; break; } } if (getUnlocalizedNameInefficiently_name == null) return false; addMethodMapping("net/minecraft/item/Item getUnlocalizedNameInefficiently (Lnet/minecraft/item/ItemStack;)Ljava/lang/String;", item.name + " " + getUnlocalizedNameInefficiently_name + " " + getItemStackDisplayName_desc); // public String getUnlocalizedName(ItemStack param0) methods = getMatchingMethods(item, null, "(L" + itemStack.name + ";)Ljava/lang/String;"); if (methods.size() == 3) { for (Iterator<MethodNode> iterator = methods.iterator(); iterator.hasNext();) { MethodNode mn = iterator.next(); if (mn.name.equals(getItemStackDisplayName_name) || mn.name.equals(getUnlocalizedNameInefficiently_name)) { iterator.remove(); } } if (methods.size() == 1) { addMethodMapping("net/minecraft/item/Item getUnlocalizedName (Lnet/minecraft/item/ItemStack;)Ljava/lang/String;", item.name + " " + methods.get(0).name + " " + methods.get(0).desc); } } // public String getUnlocalizedName() methods = getMatchingMethods(item, null, "()Ljava/lang/String;"); if (methods.size() == 1) { addMethodMapping("net/minecraft/item/Item getUnlocalizedName ()Ljava/lang/String;", item.name + " " + methods.get(0).name + " " + methods.get(0).desc); } return true; } @Mapping(providesFields={ "net/minecraft/item/ItemStack stackTagCompound Lnet/minecraft/nbt/NBTTagCompound;", "net/minecraft/item/ItemStack stackSize I", "net/minecraft/item/ItemStack itemDamage I" }, providesMethods={ //"net/minecraft/item/ItemStack loadItemStackFromNBT (Lnet/minecraft/nbt/NBTTagCompound;)Lnet/minecraft/item/ItemStack;", "net/minecraft/item/ItemStack setTagCompound (Lnet/minecraft/nbt/NBTTagCompound;)V", "net/minecraft/item/ItemStack readFromNBT (Lnet/minecraft/nbt/NBTTagCompound;)V", "net/minecraft/item/ItemStack isItemEnchanted ()Z", "net/minecraft/item/ItemStack hasTagCompound ()Z", "net/minecraft/item/ItemStack getItem ()Lnet/minecraft/item/Item;", "net/minecraft/item/ItemStack getTagCompound ()Lnet/minecraft/nbt/NBTTagCompound;", "net/minecraft/item/ItemStack getDisplayName ()Ljava/lang/String;", "net/minecraft/item/ItemStack getUnlocalizedName ()Ljava/lang/String;", "net/minecraft/item/ItemStack copy ()Lnet/minecraft/item/ItemStack;", "net/minecraft/item/ItemStack isItemEqual (Lnet/minecraft/item/ItemStack;)Z", "net/minecraft/item/ItemStack isItemStackEqual (Lnet/minecraft/item/ItemStack;)Z", "net/minecraft/item/ItemStack isDamageableItemEqual (Lnet/minecraft/item/ItemStack;)Z", // NEW "net/minecraft/item/ItemStack isItemStackDamageable ()Z", "net/minecraft/item/ItemStack splitStack (I)Lnet/minecraft/item/ItemStack;", "net/minecraft/item/ItemStack setTagInfo (Ljava/lang/String;Lnet/minecraft/nbt/NBTBase;)V" }, depends={ "net/minecraft/item/ItemStack", "net/minecraft/item/Item", "net/minecraft/nbt/NBTTagCompound", "net/minecraft/nbt/NBTBase" }) public boolean processItemStackClass() { ClassNode itemStack = getClassNodeFromMapping("net/minecraft/item/ItemStack"); ClassNode tagCompound = getClassNodeFromMapping("net/minecraft/nbt/NBTTagCompound"); ClassNode item = getClassNodeFromMapping("net/minecraft/item/Item"); ClassNode nbtbase = getClassNodeFromMapping("net/minecraft/nbt/NBTBase"); if (!MeddleUtil.notNull(itemStack, tagCompound, item, nbtbase)) return false; // public static ItemStack loadItemStackFromNBT(NBTTagCompound nbt) // No longer exists in 16w32a //List<MethodNode> methods = getMatchingMethods(itemStack, null, "(L" + tagCompound.name + ";)L" + itemStack.name + ";"); //if (methods.size() != 1) return false; //addMethodMapping("net/minecraft/item/ItemStack loadItemStackFromNBT (Lnet/minecraft/nbt/NBTTagCompound;)Lnet/minecraft/item/ItemStack;", //itemStack.name + " " + methods.get(0).name + " " + methods.get(0).desc); String stackTagCompoundField = null; List<MethodNode> methods = getMatchingMethods(itemStack, null, "(L" + tagCompound.name + ";)V"); if (methods.size() != 2) return false; for (MethodNode method : methods) { // public void setTagCompound(NBTTagCompound nbt) AbstractInsnNode firstReal = getNextRealOpcode(method.instructions.getFirst()); if (firstReal.getOpcode() == Opcodes.ALOAD) { AbstractInsnNode nextNode = firstReal.getNext(); if (nextNode != null && nextNode.getOpcode() == Opcodes.ALOAD) { nextNode = nextNode.getNext(); if (nextNode != null && nextNode.getOpcode() == Opcodes.PUTFIELD) { FieldInsnNode fn = (FieldInsnNode)nextNode; if (fn.owner.equals(itemStack.name) && fn.desc.equals("L" + tagCompound.name + ";")) { stackTagCompoundField = fn.name; addFieldMapping("net/minecraft/item/ItemStack stackTagCompound Lnet/minecraft/nbt/NBTTagCompound;", itemStack.name + " " + fn.name + " " + fn.desc); addMethodMapping("net/minecraft/item/ItemStack setTagCompound (Lnet/minecraft/nbt/NBTTagCompound;)V", itemStack.name + " " + method.name + " " + method.desc); continue; } } } } // public void readFromNBT(NBTTagCompound nbt) boolean isReadNBT = false; for (AbstractInsnNode insn = firstReal; insn != null; insn = insn.getNext()) { if (!isLdcWithString(insn, "id")) continue; isReadNBT = true; addMethodMapping("net/minecraft/item/ItemStack readFromNBT (Lnet/minecraft/nbt/NBTTagCompound;)V", itemStack.name + " " + method.name + " " + method.desc); break; } if (isReadNBT) { boolean foundCount = false; boolean foundDamage = false; boolean foundstackSize = false; boolean founditemDamage = false; for (AbstractInsnNode insn = firstReal; insn != null; insn = insn.getNext()) { String s = getLdcString(insn); if (s != null) { foundCount = false; foundDamage = false; if (s.equals("Count")) foundCount = true; else if (s.equals("Damage")) foundDamage = true; } if (insn.getOpcode() != Opcodes.PUTFIELD) continue; FieldInsnNode fn = (FieldInsnNode)insn; if (!fn.owner.equals(itemStack.name)) continue; if (foundCount && !foundstackSize) { addFieldMapping("net/minecraft/item/ItemStack stackSize I", itemStack.name + " " + fn.name + " I"); foundCount = false; foundstackSize = true; } else if (foundDamage) { addFieldMapping("net/minecraft/item/ItemStack itemDamage I", itemStack.name + " " + fn.name + " I"); foundDamage = false; founditemDamage = true; } if (foundstackSize && founditemDamage) break; } } } if (stackTagCompoundField == null) return false; // Find isItemEnchanted()Z and hasTagCompound()Z methods = getMatchingMethods(itemStack, null, "()Z"); for (Iterator<MethodNode> iterator = methods.iterator(); iterator.hasNext();) { MethodNode method = iterator.next(); /*if (!matchOpcodeSequence(method.instructions.getFirst(), Opcodes.ALOAD, Opcodes.GETFIELD, Opcodes.IFNULL)) { iterator.remove(); continue; }*/ boolean correctField = false; boolean correctSequence = false; for (AbstractInsnNode insn = method.instructions.getFirst(); insn != null; insn = insn.getNext()) { if (matchOpcodeSequence(insn, Opcodes.ALOAD, Opcodes.GETFIELD, Opcodes.IFNULL)) correctSequence = true; if (insn.getOpcode() != Opcodes.GETFIELD) continue; FieldInsnNode fn = (FieldInsnNode)insn; if (fn.owner.equals(itemStack.name) && fn.name.equals(stackTagCompoundField)) { correctField = true; break; } } if (!correctSequence || !correctField) { iterator.remove(); continue; } } if (methods.size() == 2) { for (MethodNode method : methods) { boolean isEnchant = false; for (AbstractInsnNode insn = method.instructions.getFirst(); insn != null; insn = insn.getNext()) { if (isLdcWithString(insn, "ench")) { isEnchant = true; break; } } // public boolean isItemEnchanted() if (isEnchant) { addMethodMapping("net/minecraft/item/ItemStack isItemEnchanted ()Z", itemStack.name + " " + method.name + " ()Z"); } // public boolean hasTagCompound() else { addMethodMapping("net/minecraft/item/ItemStack hasTagCompound ()Z", itemStack.name + " " + method.name + " ()Z"); } } } // public Item getItem() methods = getMatchingMethods(itemStack, null, "()L" + item.name + ";"); if (methods.size() == 1) { addMethodMapping("net/minecraft/item/ItemStack getItem ()Lnet/minecraft/item/Item;", itemStack.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public NBTTagCompound getTagCompound() methods = getMatchingMethods(itemStack, null, "()L" + tagCompound.name + ";"); if (methods.size() == 1) { addMethodMapping("net/minecraft/item/ItemStack getTagCompound ()Lnet/minecraft/nbt/NBTTagCompound;", itemStack.name + " " + methods.get(0).name + " " + methods.get(0).desc); } methods = getMatchingMethods(itemStack, null, "()Ljava/lang/String;"); if (methods.size() == 3) { for (MethodNode method : methods) { if (method.name.equals("toString")) continue; boolean isDisplayName = false; for (AbstractInsnNode insn = method.instructions.getFirst(); insn != null; insn = insn.getNext()) { if (isLdcWithString(insn, "display")) { isDisplayName = true; break; } } // public String getDisplayName() if (isDisplayName) { addMethodMapping("net/minecraft/item/ItemStack getDisplayName ()Ljava/lang/String;", itemStack.name + " " + method.name + " " + method.desc); } // public String getUnlocalizedName() else { addMethodMapping("net/minecraft/item/ItemStack getUnlocalizedName ()Ljava/lang/String;", itemStack.name + " " + method.name + " " + method.desc); } } } // public ItemStack copy() methods = getMatchingMethods(itemStack, null, "()L" + itemStack.name + ";"); if (methods.size() == 1) { addMethodMapping("net/minecraft/item/ItemStack copy ()Lnet/minecraft/item/ItemStack;", itemStack.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public boolean isItemStackDamageable() methods = getMatchingMethods(itemStack, null, "()Z"); methods = removeMethodsWithoutFlags(methods, Opcodes.ACC_PUBLIC); for (Iterator<MethodNode> it = methods.iterator(); it.hasNext(); ) { MethodNode method = it.next(); boolean found = false; for (AbstractInsnNode insn : method.instructions.toArray()) { if (isLdcWithString(insn, "Unbreakable")) found = true; } if (!found) it.remove(); } String itemStackDamageable = null; if (methods.size() == 1) { addMethodMapping("net/minecraft/item/ItemStack isItemStackDamageable ()Z", itemStack.name + " " + methods.get(0).name + " " + methods.get(0).desc); itemStackDamageable = methods.get(0).name; } // public boolean isItemEqual(ItemStack other) // public boolean isDamageableItemEqual(ItemStack other) methods = getMatchingMethods(itemStack, null, "(L" + itemStack.name + ";)Z"); methods = removeMethodsWithoutFlags(methods, Opcodes.ACC_PUBLIC); if (methods.size() == 2) { MethodNode isItemEqualMethod = null; MethodNode isDamageableItemEqual = null; for (MethodNode method : methods) { List<MethodInsnNode> list = getAllInsnNodesOfType(method.instructions.getFirst(), MethodInsnNode.class); list = filterMethodInsnNodes(list, itemStack.name, itemStackDamageable, "()Z"); if (list.size() != 0) isDamageableItemEqual = method; else isItemEqualMethod = method; } if (isItemEqualMethod != null && isDamageableItemEqual != null) { addMethodMapping("net/minecraft/item/ItemStack isItemEqual (Lnet/minecraft/item/ItemStack;)Z", itemStack.name + " " + isItemEqualMethod.name + " " + isItemEqualMethod.desc); addMethodMapping("net/minecraft/item/ItemStack isDamageableItemEqual (Lnet/minecraft/item/ItemStack;)Z", itemStack.name + " " + isDamageableItemEqual.name + " " + isDamageableItemEqual.desc); } } // private boolean isItemStackEqual(ItemStack other) methods = getMatchingMethods(itemStack, null, "(L" + itemStack.name + ";)Z"); methods = removeMethodsWithoutFlags(methods, Opcodes.ACC_PRIVATE); if (methods.size() == 1) { addMethodMapping("net/minecraft/item/ItemStack isItemStackEqual (Lnet/minecraft/item/ItemStack;)Z", itemStack.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public ItemStack splitStack(int amount) methods = getMatchingMethods(itemStack, null, "(I)L" + itemStack.name + ";"); if (methods.size() == 1) { addMethodMapping("net/minecraft/item/ItemStack splitStack (I)Lnet/minecraft/item/ItemStack;", itemStack.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public void setTagInfo(String key, NBTBase value) methods = getMatchingMethods(itemStack, null, "(Ljava/lang/String;L" + nbtbase.name + ";)V"); if (methods.size() == 1) { addMethodMapping("net/minecraft/item/ItemStack setTagInfo (Ljava/lang/String;Lnet/minecraft/nbt/NBTBase;)V", itemStack.name + " " + methods.get(0).name + " " + methods.get(0).desc); } return true; } @Mapping(providesMethods={ "net/minecraft/item/ItemStack getItemDamage ()I", "net/minecraft/item/ItemStack setItemDamage (I)V", "net/minecraft/item/ItemStack damageItem (ILnet/minecraft/entity/EntityLivingBase;)V", "net/minecraft/item/ItemStack getMaxDamage ()I", "net/minecraft/item/ItemStack updateAnimation (Lnet/minecraft/world/World;Lnet/minecraft/entity/Entity;IZ)V", "net/minecraft/item/ItemStack getAnimationsToGo ()I", "net/minecraft/item/ItemStack getStackSize ()I", "net/minecraft/item/ItemStack setStackSize (I)V", "net/minecraft/item/ItemStack increaseStackSize (I)V", "net/minecraft/item/ItemStack decreaseStackSize (I)V", "net/minecraft/item/ItemStack isValid ()Z", "net/minecraft/item/ItemStack validate ()V", "net/minecraft/item/ItemStack getMaxStackSize ()I" }, providesFields={ "net/minecraft/item/ItemStack item Lnet/minecraft/item/Item;", "net/minecraft/item/ItemStack animationsToGo I", "net/minecraft/item/ItemStack NULL_STACK Lnet/minecraft/item/ItemStack;", "net/minecraft/item/ItemStack validStack Z" }, dependsMethods={ "net/minecraft/item/ItemStack getMetadata ()I", "net/minecraft/item/Item getMaxDamage ()I", "net/minecraft/item/Item getMaxStackSize ()I" }, dependsFields={ "net/minecraft/item/ItemStack itemDamage I", "net/minecraft/item/ItemStack stackSize I", "net/minecraft/init/Blocks air Lnet/minecraft/block/Block;" }, depends={ "net/minecraft/item/ItemStack", "net/minecraft/entity/EntityLivingBase", "net/minecraft/item/Item", "net/minecraft/entity/Entity", "net/minecraft/world/World" }) public boolean processItemStackClass2() { ClassNode itemStack = getClassNodeFromMapping("net/minecraft/item/ItemStack"); ClassNode entityLivingBase = getClassNodeFromMapping("net/minecraft/entity/EntityLivingBase"); ClassNode item = getClassNodeFromMapping("net/minecraft/item/Item"); ClassNode entity = getClassNodeFromMapping("net/minecraft/entity/Entity"); ClassNode world = getClassNodeFromMapping("net/minecraft/world/World"); ClassNode blocks = getClassNodeFromMapping("net/minecraft/init/Blocks"); if (!MeddleUtil.notNull(itemStack, entityLivingBase, item, entity, world, blocks)) return false; FieldNode itemDamage = getFieldNodeFromMapping(itemStack, "net/minecraft/item/ItemStack itemDamage I"); FieldNode stackSize = getFieldNodeFromMapping(itemStack, "net/minecraft/item/ItemStack stackSize I"); FieldNode air = getFieldNodeFromMapping(blocks, "net/minecraft/init/Blocks air Lnet/minecraft/block/Block;"); MethodNode getMetadata = getMethodNodeFromMapping(itemStack, "net/minecraft/item/ItemStack getMetadata ()I"); if (itemDamage == null || stackSize == null || getMetadata == null) return false; String animationsToGo = null; // public void updateAnimation(World worldIn, Entity entityIn, int inventorySlot, boolean isCurrentItem) List<MethodNode> methods = getMatchingMethods(itemStack, null, assembleDescriptor("(", world, entity, "IZ)V")); if (methods.size() == 1) { addMethodMapping("net/minecraft/item/ItemStack updateAnimation (Lnet/minecraft/world/World;Lnet/minecraft/entity/Entity;IZ)V", itemStack.name + " " + methods.get(0).name + " " + methods.get(0).desc); // Find all integer variables used List<FieldInsnNode> nodes = getAllInsnNodesOfType(methods.get(0), FieldInsnNode.class); List<String> fieldNames = new ArrayList<>(); for (FieldInsnNode f : nodes) { if (f.owner.equals(itemStack.name) && f.desc.equals("I")) { if (!fieldNames.contains(f.name)) fieldNames.add(f.name); } } // Should only be the one if (fieldNames.size() == 1) { addFieldMapping("net/minecraft/item/ItemStack animationsToGo I", itemStack.name + " " + fieldNames.get(0) + " I"); animationsToGo = fieldNames.get(0); } } List<MethodNode> getStackSize_list = new ArrayList<>(); List<MethodNode> getItemDamage_list = new ArrayList<>(); List<MethodNode> getAnimationsToGo_list = new ArrayList<>(); // public int getItemDamage() // public int getAnimationsToGo() // public int getStackSize() methods = getMatchingMethods(itemStack, null, "()I"); for (Iterator<MethodNode> it = methods.iterator(); it.hasNext();) { MethodNode method = it.next(); AbstractInsnNode[] nodes = getOpcodeSequenceArray(method.instructions.getFirst(), Opcodes.ALOAD, Opcodes.GETFIELD, Opcodes.IRETURN); if (nodes != null && !method.name.equals(getMetadata.name)) { FieldInsnNode fn = (FieldInsnNode)nodes[1]; if (fn.owner.equals(itemStack.name)) { if (fn.desc.equals("I")) { if (fn.name.equals(itemDamage.name)) getItemDamage_list.add(method); else if (fn.name.equals(animationsToGo)) getAnimationsToGo_list.add(method); } } } else if (doesMethodUseField(method, itemStack.name, stackSize.name, stackSize.desc)) { getStackSize_list.add(method); } } if (getItemDamage_list.size() == 1) { addMethodMapping("net/minecraft/item/ItemStack getItemDamage ()I", itemStack.name + " " + getItemDamage_list.get(0).name + " ()I"); } if (getAnimationsToGo_list.size() == 1) { addMethodMapping("net/minecraft/item/ItemStack getAnimationsToGo ()I", itemStack.name + " " + getAnimationsToGo_list.get(0).name + " ()I"); } if (getStackSize_list.size() == 1) { addMethodMapping("net/minecraft/item/ItemStack getStackSize ()I", itemStack.name + " " + getStackSize_list.get(0).name + " ()I"); } // public void setItemDamage(int meta) methods = getMatchingMethods(itemStack, null, "(I)V"); for (Iterator<MethodNode> it = methods.iterator(); it.hasNext();) { MethodNode method = it.next(); if (!doesMethodUseField(method, itemStack.name, itemDamage.name, "I")) it.remove(); } if (methods.size() == 1) { addMethodMapping("net/minecraft/item/ItemStack setItemDamage (I)V", itemStack.name + " " + methods.get(0).name + " (I)V"); } // public void setStackSize(int size) String setStackSize_name = null; methods = getMatchingMethods(itemStack, null, "(I)V"); for (Iterator<MethodNode> it = methods.iterator(); it.hasNext();) { MethodNode method = it.next(); if (!matchOpcodeSequence(method.instructions.getFirst(), Opcodes.ALOAD, Opcodes.ILOAD, Opcodes.PUTFIELD)) { it.remove(); continue; } if (!doesMethodUseField(method, itemStack.name, stackSize.name, "I")) it.remove(); } if (methods.size() == 1) { addMethodMapping("net/minecraft/item/ItemStack setStackSize (I)V", itemStack.name + " " + methods.get(0).name + " (I)V"); setStackSize_name = methods.get(0).name; } // public void increaseStackSize(int size) String increaseStackSize_name = null; if (setStackSize_name != null) { methods = getMatchingMethods(itemStack, null, "(I)V"); for (Iterator<MethodNode> it = methods.iterator(); it.hasNext();) { MethodNode method = it.next(); if (!doesMethodUseMethod(method, itemStack.name, setStackSize_name, "(I)V")) it.remove(); } if (methods.size() == 1) { addMethodMapping("net/minecraft/item/ItemStack increaseStackSize (I)V", itemStack.name + " " + methods.get(0).name + " (I)V"); increaseStackSize_name = methods.get(0).name; } } // public void decreaseStackSize(int size) if (increaseStackSize_name != null) { methods = getMatchingMethods(itemStack, null, "(I)V"); for (Iterator<MethodNode> it = methods.iterator(); it.hasNext();) { MethodNode method = it.next(); if (!doesMethodUseMethod(method, itemStack.name, increaseStackSize_name, "(I)V")) it.remove(); } if (methods.size() == 1) { addMethodMapping("net/minecraft/item/ItemStack decreaseStackSize (I)V", itemStack.name + " " + methods.get(0).name + " (I)V"); } } // public void damageItem(int amount, EntityLivingBase entityIn) methods = getMatchingMethods(itemStack, null, "(IL" + entityLivingBase.name + ";)V"); if (methods.size() == 1) { addMethodMapping("net/minecraft/item/ItemStack damageItem (ILnet/minecraft/entity/EntityLivingBase;)V", itemStack.name + " " + methods.get(0).name + " " + methods.get(0).desc); } MethodNode getMaxDamage = getMethodNodeFromMapping(item, "net/minecraft/item/Item getMaxDamage ()I"); if (getMaxDamage != null) { methods = getMatchingMethods(itemStack, null, "()I"); for (Iterator<MethodNode> it = methods.iterator(); it.hasNext();) { MethodNode method = it.next(); List<MethodInsnNode> nodes = getAllInsnNodesOfType(method, MethodInsnNode.class); boolean hasIt = false; for (MethodInsnNode mn : nodes) { if (mn.owner.equals(item.name) && mn.name.equals(getMaxDamage.name) && mn.desc.equals("()I")) hasIt = true; } if (!hasIt) it.remove(); } if (methods.size() == 1) { addMethodMapping("net/minecraft/item/ItemStack getMaxDamage ()I", itemStack.name + " " + methods.get(0).name + " ()I"); } } methods = getMatchingMethods(itemStack, null, "()Z"); methods = filterMethodsUsingField(methods, blocks.name, air.name, air.desc); String isValid_name = null; if (methods.size() == 1 && doesMethodContainInteger(methods.get(0), 65535)) { addMethodMapping("net/minecraft/item/ItemStack isValid ()Z", itemStack.name + " " + methods.get(0).name + " " + methods.get(0).desc); isValid_name = methods.get(0).name; } if (isValid_name != null) { methods = getMatchingMethods(itemStack, null, "()V"); for (MethodNode method : methods) { AbstractInsnNode[] nodes = getOpcodeSequenceArray(method.instructions.getFirst(), Opcodes.ALOAD, Opcodes.ALOAD, Opcodes.INVOKEVIRTUAL, Opcodes.PUTFIELD, Opcodes.RETURN); if (nodes != null) { MethodInsnNode mn = (MethodInsnNode)nodes[2]; if (mn.owner.equals(itemStack.name) && mn.name.equals(isValid_name) && mn.desc.equals("()Z")) { FieldInsnNode fn = (FieldInsnNode)nodes[3]; addMethodMapping("net/minecraft/item/ItemStack validate ()V", itemStack.name + " " + method.name + " " + method.desc); addFieldMapping("net/minecraft/item/ItemStack validStack Z", itemStack.name + " " + fn.name + " Z"); break; } } } } // public int getMaxStackSize() MethodNode getMaxStackSize = getMethodNodeFromMapping(item, "net/minecraft/item/Item getMaxStackSize ()I"); if (getMaxStackSize != null) { methods = getMatchingMethods(itemStack, null, "()I"); methods = filterMethodsUsingMethod(methods, item.name, getMaxStackSize.name, getMaxStackSize.desc); if (methods.size() == 1) { addMethodMapping("net/minecraft/item/ItemStack getMaxStackSize ()I", itemStack.name + " " + methods.get(0).name + " " + methods.get(0).desc); } } List<FieldNode> fields = getMatchingFields(itemStack, null, "L" + item.name + ";"); if (fields.size() == 1) { addFieldMapping("net/minecraft/item/ItemStack item Lnet/minecraft/item/Item;", itemStack.name + " " + fields.get(0).name + " " + fields.get(0).desc); } fields = getMatchingFields(itemStack, null, "L" + itemStack.name + ";"); if (fields.size() == 1) { addFieldMapping("net/minecraft/item/ItemStack NULL_STACK Lnet/minecraft/item/ItemStack;", itemStack.name + " " + fields.get(0).name + " " + fields.get(0).desc); } return true; } @Mapping(providesFields={ "net/minecraft/util/ItemUseResult SUCCESS Lnet/minecraft/util/ItemUseResult;", "net/minecraft/util/ItemUseResult PASS Lnet/minecraft/util/ItemUseResult;", "net/minecraft/util/ItemUseResult FAIL Lnet/minecraft/util/ItemUseResult;" }, depends={ "net/minecraft/util/ItemUseResult" }) public boolean processItemUseResultClass() { ClassNode itemUseResult = getClassNodeFromMapping("net/minecraft/util/ItemUseResult"); if (itemUseResult == null) return false; List<FieldNode> fields = getMatchingFields(itemUseResult, null, "L" + itemUseResult.name + ";"); if (fields.size() == 3) { addFieldMapping("net/minecraft/util/ItemUseResult SUCCESS Lnet/minecraft/util/ItemUseResult;", itemUseResult.name + " " + fields.get(0).name + " " + fields.get(0).desc); addFieldMapping("net/minecraft/util/ItemUseResult PASS Lnet/minecraft/util/ItemUseResult;", itemUseResult.name + " " + fields.get(1).name + " " + fields.get(1).desc); addFieldMapping("net/minecraft/util/ItemUseResult FAIL Lnet/minecraft/util/ItemUseResult;", itemUseResult.name + " " + fields.get(2).name + " " + fields.get(2).desc); } return true; } @Mapping(provides={ "net/minecraft/item/crafting/CraftingManager", "net/minecraft/entity/passive/EntityAnimal", "net/minecraft/item/EnumDyeColor" }, depends={ "net/minecraft/entity/passive/EntitySheep" }) public boolean getCraftingManagerClass() { ClassNode entitySheep = getClassNodeFromMapping("net/minecraft/entity/passive/EntitySheep"); if (entitySheep == null) return false; List<MethodNode> methods = new ArrayList<MethodNode>(); // Looking for: private EnumDyeColor func_175511_a(EntityAnimal, EntityAnimal) for (MethodNode method : entitySheep.methods) { if (!checkMethodParameters(method, Type.OBJECT, Type.OBJECT)) continue; Type t = Type.getMethodType(method.desc); Type[] args = t.getArgumentTypes(); String className = args[0].getClassName(); if (className.equals(args[1].getClassName()) && className.equals(entitySheep.superName)) methods.add(method); } MethodNode func_175511_a = null; if (methods.size() == 1) func_175511_a = methods.get(0); else return false; if (searchConstantPoolForStrings(entitySheep.superName, "InLove")) addClassMapping("net/minecraft/entity/passive/EntityAnimal", entitySheep.superName); String enumDyeColor_name = Type.getMethodType(func_175511_a.desc).getReturnType().getClassName(); if (searchConstantPoolForStrings(enumDyeColor_name, "white", "lime")) addClassMapping("net/minecraft/item/EnumDyeColor", enumDyeColor_name); for (AbstractInsnNode insn = func_175511_a.instructions.getFirst(); insn != null; insn = insn.getNext()) { if (insn.getOpcode() != Opcodes.INVOKESTATIC) continue; MethodInsnNode mn = (MethodInsnNode)insn; if (mn.desc.equals("()L" + mn.owner + ";")) { if (searchConstantPoolForStrings(mn.owner, "###", "AAA")) { addClassMapping("net/minecraft/item/crafting/CraftingManager", mn.owner); return true; } } } return false; } @Mapping(provides={ "net/minecraft/item/crafting/ShapedRecipes", "net/minecraft/item/crafting/IRecipe", "net/minecraft/item/crafting/ShapelessRecipes" }, providesMethods={ "net/minecraft/item/crafting/CraftingManager addRecipe (Lnet/minecraft/item/ItemStack;[Ljava/lang/Object;)Lnet/minecraft/item/crafting/ShapedRecipes;", "net/minecraft/item/crafting/CraftingManager addShapelessRecipe (Lnet/minecraft/item/ItemStack;[Ljava/lang/Object;)V", "net/minecraft/item/crafting/CraftingManager getInstance ()Lnet/minecraft/item/crafting/CraftingManager;", "net/minecraft/item/crafting/CraftingManager getRecipeList ()Ljava/util/List;", "net/minecraft/item/crafting/CraftingManager addRecipe (Lnet/minecraft/item/crafting/IRecipe;)V" }, depends={ "net/minecraft/item/crafting/CraftingManager", "net/minecraft/item/ItemStack" }) public boolean processCraftingManagerClass() { ClassNode craftingManager = getClassNodeFromMapping("net/minecraft/item/crafting/CraftingManager"); ClassNode itemStack = getClassNodeFromMapping("net/minecraft/item/ItemStack"); if (craftingManager == null || itemStack == null) return false; List<MethodNode> methods = new ArrayList<MethodNode>(); // public ShapedRecipes addRecipe(ItemStack param0, Object... param1) for (MethodNode method : craftingManager.methods) { if (method.desc.startsWith("(L" + itemStack.name + ";[Ljava/lang/Object;)L")) methods.add(method); } if (methods.size() != 1) return false; String shapedRecipes_className = Type.getMethodType(methods.get(0).desc).getReturnType().getClassName(); addClassMapping("net/minecraft/item/crafting/ShapedRecipes", shapedRecipes_className); addMethodMapping("net/minecraft/item/crafting/CraftingManager addRecipe (Lnet/minecraft/item/ItemStack;[Ljava/lang/Object;)Lnet/minecraft/item/crafting/ShapedRecipes;", craftingManager.name + " " + methods.get(0).name + " " + methods.get(0).desc); // public static CraftingManager getInstance() methods = getMatchingMethods(craftingManager, null, "()L" + craftingManager.name + ";"); if (methods.size() == 1) { addMethodMapping("net/minecraft/item/crafting/CraftingManager getInstance ()Lnet/minecraft/item/crafting/CraftingManager;", craftingManager.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public List getRecipeList() methods = getMatchingMethods(craftingManager, null, "()Ljava/util/List;"); if (methods.size() == 1) { addMethodMapping("net/minecraft/item/crafting/CraftingManager getRecipeList ()Ljava/util/List;", craftingManager.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public void addRecipe(IRecipe recipe) // net/minecraft/item/crafting/IRecipe String iRecipe_name = null; methods.clear(); for (MethodNode method : craftingManager.methods) { if (!method.desc.startsWith("(L") || !method.desc.endsWith(";)V")) continue; Type[] args = Type.getMethodType(method.desc).getArgumentTypes(); if (args.length != 1) continue; methods.add(method); } if (methods.size() == 1) { MethodNode method = methods.get(0); iRecipe_name = Type.getMethodType(method.desc).getArgumentTypes()[0].getClassName(); ClassNode iRecipe = getClassNode(iRecipe_name); if ((iRecipe.access & Opcodes.ACC_INTERFACE) != 0) { // TODO: Better detection couldn't hurt addClassMapping("net/minecraft/item/crafting/IRecipe", iRecipe_name); addMethodMapping("net/minecraft/item/crafting/CraftingManager addRecipe (Lnet/minecraft/item/crafting/IRecipe;)V", craftingManager.name + " " + method.name + " " + method.desc); } else iRecipe_name = null; } // public void addShapelessRecipe(ItemStack param0, Object... param1) // net/minecraft/item/crafting/ShapelessRecipes methods = getMatchingMethods(craftingManager, null, "(L" + itemStack.name + ";[Ljava/lang/Object;)V"); if (methods.size() == 1) { addMethodMapping("net/minecraft/item/crafting/CraftingManager addShapelessRecipe (Lnet/minecraft/item/ItemStack;[Ljava/lang/Object;)V", craftingManager.name + " " + methods.get(0).name + " " + methods.get(0).desc); if (iRecipe_name != null) { List<TypeInsnNode> nodes = getAllInsnNodesOfType(methods.get(0).instructions.getFirst(), TypeInsnNode.class); for (Iterator<TypeInsnNode> it = nodes.iterator(); it.hasNext();) { TypeInsnNode tn = it.next(); if (tn.getOpcode() != Opcodes.NEW || tn.desc.startsWith("java/") || tn.desc.equals(itemStack.name)) { it.remove(); continue; } ClassNode cn = getClassNode(tn.desc); if (!classHasInterfaces(cn, iRecipe_name)) { it.remove(); continue; } } if (nodes.size() == 1) { addClassMapping("net/minecraft/item/crafting/ShapelessRecipes", nodes.get(0).desc); } } } return true; } @Mapping(providesFields={ "net/minecraft/item/crafting/ShapedRecipes recipeWidth I", "net/minecraft/item/crafting/ShapedRecipes recipeHeight I", "net/minecraft/item/crafting/ShapedRecipes recipeItems [Lnet/minecraft/item/ItemStack;", "net/minecraft/item/crafting/ShapedRecipes recipeOutput Lnet/minecraft/item/ItemStack;", "net/minecraft/item/crafting/ShapedRecipes copyIngredientNBT Z" }, depends={ "net/minecraft/item/crafting/ShapedRecipes", "net/minecraft/item/ItemStack" }) public boolean processShapedRecipesClass() { ClassNode shapedRecipes = getClassNodeFromMapping("net/minecraft/item/crafting/ShapedRecipes"); ClassNode itemStack = getClassNodeFromMapping("net/minecraft/item/ItemStack"); if (!MeddleUtil.notNull(shapedRecipes, itemStack)) return false; List<FieldNode> fields = getMatchingFields(shapedRecipes, null, "I"); if (fields.size() == 2) { addFieldMapping("net/minecraft/item/crafting/ShapedRecipes recipeWidth I", shapedRecipes.name + " " + fields.get(0).name + " I"); addFieldMapping("net/minecraft/item/crafting/ShapedRecipes recipeHeight I", shapedRecipes.name + " " + fields.get(1).name + " I"); } fields = getMatchingFields(shapedRecipes, null, "[L" + itemStack.name + ";"); if (fields.size() == 1) { addFieldMapping("net/minecraft/item/crafting/ShapedRecipes recipeItems [Lnet/minecraft/item/ItemStack;", shapedRecipes.name + " " + fields.get(0).name + " " + fields.get(0).desc); } fields = getMatchingFields(shapedRecipes, null, "L" + itemStack.name + ";"); if (fields.size() == 1) { addFieldMapping("net/minecraft/item/crafting/ShapedRecipes recipeOutput Lnet/minecraft/item/ItemStack;", shapedRecipes.name + " " + fields.get(0).name + " " + fields.get(0).desc); } fields = getMatchingFields(shapedRecipes, null, "Z"); if (fields.size() == 1) { addFieldMapping("net/minecraft/item/crafting/ShapedRecipes copyIngredientNBT Z", shapedRecipes.name + " " + fields.get(0).name + " " + fields.get(0).desc); } return true; } @Mapping(providesFields={ "net/minecraft/item/crafting/ShapelessRecipes recipeOutput Lnet/minecraft/item/ItemStack;", "net/minecraft/item/crafting/ShapelessRecipes recipeItems Ljava/util/List;" }, depends={ "net/minecraft/item/crafting/ShapelessRecipes", "net/minecraft/item/ItemStack" }) public boolean processShapelessRecipesClass() { ClassNode shapelessRecipes = getClassNodeFromMapping("net/minecraft/item/crafting/ShapelessRecipes"); ClassNode itemStack = getClassNodeFromMapping("net/minecraft/item/ItemStack"); if (!MeddleUtil.notNull(shapelessRecipes, itemStack)) return false; // private final ItemStack recipeOutput; List<FieldNode> fields = getMatchingFields(shapelessRecipes, null, "L" + itemStack.name + ";"); if (fields.size() == 1) { addFieldMapping("net/minecraft/item/crafting/ShapelessRecipes recipeOutput Lnet/minecraft/item/ItemStack;", shapelessRecipes.name + " " + fields.get(0).name + " " + fields.get(0).desc); } // private final List recipeItems; fields = getMatchingFields(shapelessRecipes, null, "Ljava/util/List;"); if (fields.size() == 1) { addFieldMapping("net/minecraft/item/crafting/ShapelessRecipes recipeItems Ljava/util/List;", shapelessRecipes.name + " " + fields.get(0).name + " " + fields.get(0).desc); } return true; } @Mapping(provides={ "net/minecraft/inventory/InventoryCrafting", "net/minecraft/util/MCList" }, providesMethods={ "net/minecraft/item/crafting/IRecipe getRecipeSize ()I", "net/minecraft/item/crafting/IRecipe getRecipeOutput ()Lnet/minecraft/item/ItemStack;", "net/minecraft/item/crafting/IRecipe matches (Lnet/minecraft/inventory/InventoryCrafting;Lnet/minecraft/world/World;)Z", "net/minecraft/item/crafting/IRecipe getCraftingResult (Lnet/minecraft/inventory/InventoryCrafting;)Lnet/minecraft/item/ItemStack;", "net/minecraft/item/crafting/IRecipe getRemainingItems (Lnet/minecraft/inventory/InventoryCrafting;)Lnet/minecraft/util/MCList;" }, depends={ "net/minecraft/item/crafting/IRecipe", "net/minecraft/item/ItemStack", "net/minecraft/world/World" }) public boolean processIRecipeClass() { ClassNode iRecipe = getClassNodeFromMapping("net/minecraft/item/crafting/IRecipe"); ClassNode itemStack = getClassNodeFromMapping("net/minecraft/item/ItemStack"); ClassNode world = getClassNodeFromMapping("net/minecraft/world/World"); if (!MeddleUtil.notNull(iRecipe, itemStack, world)) return false; // int getRecipeSize(); List<MethodNode> methods = getMatchingMethods(iRecipe, null, "()I"); if (methods.size() == 1) { addMethodMapping("net/minecraft/item/crafting/IRecipe getRecipeSize ()I", iRecipe.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // ItemStack getRecipeOutput(); methods = getMatchingMethods(iRecipe, null, "()L" + itemStack.name + ";"); if (methods.size() == 1) { addMethodMapping("net/minecraft/item/crafting/IRecipe getRecipeOutput ()Lnet/minecraft/item/ItemStack;", iRecipe.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // boolean matches(InventoryCrafting inv, World worldIn); // net/minecraft/inventory/InventoryCrafting methods.clear(); for (MethodNode method : iRecipe.methods) { if (method.desc.startsWith("(L") && method.desc.endsWith(";L" + world.name + ";)Z") && Type.getMethodType(method.desc).getArgumentTypes().length == 2) methods.add(method); } String inventoryCrafting_name = null; if (methods.size() == 1) { MethodNode method = methods.get(0); Type t = Type.getMethodType(method.desc); inventoryCrafting_name = t.getArgumentTypes()[0].getClassName(); if (searchConstantPoolForStrings(inventoryCrafting_name, "container.crafting")) { addClassMapping("net/minecraft/inventory/InventoryCrafting", inventoryCrafting_name); addMethodMapping("net/minecraft/item/crafting/IRecipe matches (Lnet/minecraft/inventory/InventoryCrafting;Lnet/minecraft/world/World;)Z", iRecipe.name + " " + method.name + " " + method.desc); } else inventoryCrafting_name = null; } if (inventoryCrafting_name == null) return false; // ItemStack getCraftingResult(InventoryCrafting inv); methods = getMatchingMethods(iRecipe, null, "(L" + inventoryCrafting_name + ";)L" + itemStack.name + ";"); if (methods.size() == 1) { addMethodMapping("net/minecraft/item/crafting/IRecipe getCraftingResult (Lnet/minecraft/inventory/InventoryCrafting;)Lnet/minecraft/item/ItemStack;", iRecipe.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public MCList<ItemStack> getRemainingItems(InventoryCrafting paramInventoryCrafting); // 16w32a changed output array to new "MCList" class for some reason methods = getMatchingMethods(iRecipe, null, null); for(Iterator<MethodNode> it = methods.iterator(); it.hasNext();) { MethodNode method = it.next(); if(method.desc.startsWith("(L" + inventoryCrafting_name + ";)") && !method.desc.endsWith(itemStack.name + ";")) {} else it.remove(); } if (methods.size() == 1) { String returnType = Type.getReturnType(methods.get(0).desc).getClassName(); addClassMapping("net/minecraft/util/MCList", returnType); addMethodMapping("net/minecraft/item/crafting/IRecipe getRemainingItems (Lnet/minecraft/inventory/InventoryCrafting;)Lnet/minecraft/util/MCList;", iRecipe.name + " " + methods.get(0).name + " " + methods.get(0).desc); } return true; } @Mapping(provides={ "net/minecraft/init/Items" }, providesMethods={ }, depends={ "net/minecraft/entity/passive/EntityVillager", "net/minecraft/item/Item" }) public boolean getInitItemsClass() { ClassNode entityVillager = getClassNodeFromMapping("net/minecraft/entity/passive/EntityVillager"); ClassNode item = getClassNodeFromMapping("net/minecraft/item/Item"); if (entityVillager == null || item == null) return false; List<MethodNode> methods = getMatchingMethods(entityVillager, null, "(L" + item.name + ";)Z"); if (methods.size() != 1) return false; for (AbstractInsnNode insn = methods.get(0).instructions.getFirst(); insn != null; insn = insn.getNext()) { if (insn.getOpcode() != Opcodes.GETSTATIC) continue; FieldInsnNode fn = (FieldInsnNode)insn; if (!fn.desc.equals("L" + item.name + ";")) continue; if (searchConstantPoolForStrings(fn.owner, "Accessed Items before Bootstrap!", "coal")) { addClassMapping("net/minecraft/init/Items", fn.owner); return true; } } return false; } @Mapping(providesFields={ "net/minecraft/init/Items leather Lnet/minecraft/item/Item;", "net/minecraft/init/Items redstone Lnet/minecraft/item/Item;", "net/minecraft/init/Items ender_pearl Lnet/minecraft/item/Item;", "net/minecraft/init/Items iron_ingot Lnet/minecraft/item/Item;", "net/minecraft/init/Items stick Lnet/minecraft/item/Item;", "net/minecraft/init/Items iron_axe Lnet/minecraft/item/Item;", "net/minecraft/init/Items iron_pickaxe Lnet/minecraft/item/Item;" }, depends={ "net/minecraft/init/Items", "net/minecraft/item/Item" }) public boolean discoverItemsFields() { Map<String, String> itemsClassFields = new HashMap<String, String>(); Map<String, String> itemsFields = new HashMap<String, String>(); ClassNode itemsClass = getClassNode(getClassMapping("net/minecraft/init/Items")); ClassNode itemClass = getClassNode(getClassMapping("net/minecraft/item/Item")); if (itemsClass == null || itemClass == null) return false; // Generate list for (MethodNode method : itemsClass.methods) { if (!method.name.equals("<clinit>")) continue; String lastString = null; for (AbstractInsnNode insn = method.instructions.getFirst(); insn != null; insn = insn.getNext()) { String s = getLdcString(insn); if (s != null) lastString = s; // Avoid any strings that definitely aren't block names if (lastString == null || lastString.contains(" ")) continue; if (insn.getOpcode() != Opcodes.PUTSTATIC) continue; FieldInsnNode fieldNode = (FieldInsnNode)insn; // Filter out non-objects and packaged classes, just in case if (!fieldNode.desc.startsWith("L") || fieldNode.desc.contains("/")) continue; itemsFields.put(lastString, fieldNode.name); // Filter out generic ones extending just the block class if (fieldNode.desc.equals("L" + itemClass.name + ";")) continue; itemsClassFields.put(lastString, fieldNode.desc.substring(1, fieldNode.desc.length() - 1)); } } String fieldName; String className; fieldName = itemsFields.get("leather"); if (fieldName != null) addFieldMapping("net/minecraft/init/Items leather Lnet/minecraft/item/Item;", itemsClass.name + " " + fieldName + " L" + itemClass.name + ";"); fieldName = itemsFields.get("redstone"); if (fieldName != null) addFieldMapping("net/minecraft/init/Items redstone Lnet/minecraft/item/Item;", itemsClass.name + " " + fieldName + " L" + itemClass.name + ";"); fieldName = itemsFields.get("ender_pearl"); if (fieldName != null) addFieldMapping("net/minecraft/init/Items ender_pearl Lnet/minecraft/item/Item;", itemsClass.name + " " + fieldName + " L" + itemClass.name + ";"); fieldName = itemsFields.get("iron_ingot"); if (fieldName != null) addFieldMapping("net/minecraft/init/Items iron_ingot Lnet/minecraft/item/Item;", itemsClass.name + " " + fieldName + " L" + itemClass.name + ";"); fieldName = itemsFields.get("stick"); if (fieldName != null) addFieldMapping("net/minecraft/init/Items stick Lnet/minecraft/item/Item;", itemsClass.name + " " + fieldName + " L" + itemClass.name + ";"); fieldName = itemsFields.get("iron_axe"); if (fieldName != null) addFieldMapping("net/minecraft/init/Items iron_axe Lnet/minecraft/item/Item;", itemsClass.name + " " + fieldName + " L" + itemClass.name + ";"); fieldName = itemsFields.get("iron_pickaxe"); if (fieldName != null) addFieldMapping("net/minecraft/init/Items iron_pickaxe Lnet/minecraft/item/Item;", itemsClass.name + " " + fieldName + " L" + itemClass.name + ";"); // TODO - Other items return true; } @Mapping(provides={ "net/minecraft/command/ServerCommandManager", "net/minecraft/util/DataVersionManager", "net/minecraft/network/NetworkSystem", "net/minecraft/server/management/PlayerProfileCache" }, providesFields={ // No longer exists in 15w36a, uses the commandManager instead //"net/minecraft/server/MinecraftServer mcServer Lnet/minecraft/server/MinecraftServer;" }, providesMethods={ "net/minecraft/server/MinecraftServer createNewCommandManager ()Lnet/minecraft/command/ServerCommandManager;" }, depends={ "net/minecraft/server/MinecraftServer" }) public boolean findServerCommandManagerClass() { ClassNode minecraftServer = getClassNode("net/minecraft/server/MinecraftServer"); if (minecraftServer == null) return false; String serverCommandManager_name = null; // public MinecraftServer(File, Proxy, File, DataVersionManager) for (MethodNode method : minecraftServer.methods) { if (serverCommandManager_name != null && method.desc.equals("()L" + serverCommandManager_name + ";")) { // TODO continue; } if (!method.name.equals("<init>")) continue; //if (!method.desc.startsWith("(Ljava/io/File;Ljava/net/Proxy;Ljava/io/File;")) continue; Type t = Type.getMethodType(method.desc); Type[] args = t.getArgumentTypes(); // was 4 pre-15w36a if (args.length != 7) continue; // was 3 pre-15w36a String className = args[2].getClassName(); if (searchConstantPoolForStrings(className, "DataVersion")) { addClassMapping("net/minecraft/util/DataVersionManager", className); } for (AbstractInsnNode insn = method.instructions.getFirst(); insn != null; insn = insn.getNext()) { if (insn instanceof MethodInsnNode) { MethodInsnNode mn = (MethodInsnNode)insn; if (mn.name.equals("<init>")) continue; Type mt = Type.getMethodType(mn.desc); Type returnType = mt.getReturnType(); if (returnType.getSort() != Type.OBJECT || returnType.getClassName().contains(".")) continue; if (searchConstantPoolForStrings(returnType.getClassName(), "chat.type.admin", "logAdminCommands")) { serverCommandManager_name = returnType.getClassName(); addClassMapping("net/minecraft/command/ServerCommandManager", returnType.getClassName()); addMethodMapping("net/minecraft/server/MinecraftServer createNewCommandManager ()Lnet/minecraft/command/ServerCommandManager;", minecraftServer.name + " " + mn.name + " " + mn.desc); continue; } } if (!(insn instanceof FieldInsnNode)) continue; FieldInsnNode fn = (FieldInsnNode)insn; // No longer exists in 15w36a, uses the commandManager var instead /*if (fn.getOpcode() == Opcodes.PUTSTATIC && fn.desc.equals("Lnet/minecraft/server/MinecraftServer;")) { addFieldMapping("net/minecraft/server/MinecraftServer mcServer Lnet/minecraft/server/MinecraftServer;", "net/minecraft/server/MinecraftServer " + fn.name + " " + fn.desc); continue; }*/ Type ft = Type.getType(fn.desc); if (ft.getSort() != Type.OBJECT) continue; className = ft.getClassName(); if (className.contains(".")) continue; if (searchConstantPoolForStrings(className, "Ticking memory connection", "Failed to handle packet for {}")) { addClassMapping("net/minecraft/network/NetworkSystem", className); continue; } if (searchConstantPoolForStrings(className, "yyyy-MM-dd HH:mm:ss Z")) { addClassMapping("net/minecraft/server/management/PlayerProfileCache", className); continue; } // TODO - Do other fields from constructor //System.out.println(ft.getClassName()); } } return true; } @Mapping(provides={ "net/minecraft/command/CommandHandler", "net/minecraft/command/ICommandManager" }, providesMethods={ "net/minecraft/server/MinecraftServer getCommandManager ()Lnet/minecraft/command/ICommandManager;" }, depends={ "net/minecraft/command/ServerCommandManager", "net/minecraft/server/MinecraftServer" }) public boolean processServerCommandManagerClass() { ClassNode serverCommandManager = getClassNodeFromMapping("net/minecraft/command/ServerCommandManager"); ClassNode minecraftServer = getClassNodeFromMapping("net/minecraft/server/MinecraftServer"); if (serverCommandManager == null || minecraftServer == null) return false; if (serverCommandManager.superName == null) return false; if (searchConstantPoolForStrings(serverCommandManager.superName, "commands.generic.notFound", "commands.generic.usage")) { addClassMapping("net/minecraft/command/CommandHandler", serverCommandManager.superName); } else return false; ClassNode commandHandler = getClassNode(serverCommandManager.superName); if (commandHandler.interfaces.size() != 1) return false; String iCommandManager_name = commandHandler.interfaces.get(0); addClassMapping("net/minecraft/command/ICommandManager", iCommandManager_name); List<MethodNode> methods = getMatchingMethods(minecraftServer, null, "()L" + iCommandManager_name + ";"); if (methods.size() == 1) { addMethodMapping("net/minecraft/server/MinecraftServer getCommandManager ()Lnet/minecraft/command/ICommandManager;", minecraftServer.name + " " + methods.get(0).name + " " + methods.get(0).desc); } return true; } @Mapping(provides={ "net/minecraft/command/ICommand" }, providesMethods={ "net/minecraft/command/CommandHandler registerCommand (Lnet/minecraft/command/ICommand;)Lnet/minecraft/command/ICommand;" }, depends={ "net/minecraft/command/CommandHandler" }) public boolean processCommandHandlerClass() { ClassNode commandHandler = getClassNodeFromMapping("net/minecraft/command/CommandHandler"); if (commandHandler == null) return false; List<MethodNode> methods = new ArrayList<MethodNode>(); String className = null; // Find: public ICommand registerCommand(ICommand) for (MethodNode method : commandHandler.methods) { Type t = Type.getMethodType(method.desc); Type[] args = t.getArgumentTypes(); Type returnType = t.getReturnType(); if (args.length != 1) continue; if (args[0].getSort() != Type.OBJECT || returnType.getSort() != Type.OBJECT) continue; if (!args[0].getClassName().equals(returnType.getClassName())) continue; methods.add(method); className = returnType.getClassName(); } if (methods.size() != 1 || className == null) return false; ClassNode iCommand = getClassNode(className); if (iCommand == null) return false; if ((iCommand.access & Opcodes.ACC_INTERFACE) == 0) return false; addMethodMapping("net/minecraft/command/CommandHandler registerCommand (Lnet/minecraft/command/ICommand;)Lnet/minecraft/command/ICommand;", commandHandler.name + " " + methods.get(0).name + " " + methods.get(0).desc); addClassMapping("net/minecraft/command/ICommand", iCommand.name); return true; } @Mapping(provides={ "net/minecraft/command/ICommandSender", "net/minecraft/command/CommandException" }, providesMethods={ "net/minecraft/command/ICommand getCommandName ()Ljava/lang/String;", "net/minecraft/command/ICommand getCommandUsage (Lnet/minecraft/command/ICommandSender;)Ljava/lang/String;", "net/minecraft/command/ICommand getCommandAliases ()Ljava/util/List;", "net/minecraft/command/ICommand processCommand (Lnet/minecraft/server/MinecraftServer;Lnet/minecraft/command/ICommandSender;[Ljava/lang/String;)V", "net/minecraft/command/ICommand canCommandSenderUseCommand (Lnet/minecraft/server/MinecraftServer;Lnet/minecraft/command/ICommandSender;)Z", "net/minecraft/command/ICommand addTabCompletionOptions (Lnet/minecraft/server/MinecraftServer;Lnet/minecraft/command/ICommandSender;[Ljava/lang/String;Lnet/minecraft/util/BlockPos;)Ljava/util/List;", "net/minecraft/command/ICommand isUsernameIndex ([Ljava/lang/String;I)Z" }, depends={ "net/minecraft/command/ICommand", "net/minecraft/util/BlockPos", "net/minecraft/server/MinecraftServer" }) public boolean processICommandClass() { ClassNode iCommand = getClassNodeFromMapping("net/minecraft/command/ICommand"); ClassNode blockPos = getClassNodeFromMapping("net/minecraft/util/BlockPos"); ClassNode server = getClassNodeFromMapping("net/minecraft/server/MinecraftServer"); if (iCommand == null || blockPos == null || server == null) return false; // String getCommandName(); List<MethodNode> methods = getMatchingMethods(iCommand, null, "()Ljava/lang/String;"); if (methods.size() != 1) return false; addMethodMapping("net/minecraft/command/ICommand getCommandName ()Ljava/lang/String;", iCommand.name + " " + methods.get(0).name + " " + methods.get(0).desc); // String getCommandUsage(ICommandSender sender); methods.clear(); String iCommandSender_name = null; for (MethodNode method : iCommand.methods) { if (!method.desc.endsWith(";)Ljava/lang/String;")) continue; Type t = Type.getMethodType(method.desc); Type[] args = t.getArgumentTypes(); if (args.length != 1) continue; if (args[0].getSort() != Type.OBJECT) continue; methods.add(method); iCommandSender_name = args[0].getClassName(); } if (methods.size() != 1 || iCommandSender_name == null) return false; ClassNode iCommandSender = getClassNode(iCommandSender_name); if (iCommandSender == null) return false; if ((iCommandSender.access & Opcodes.ACC_INTERFACE) == 0) return false; addClassMapping("net/minecraft/command/ICommandSender", iCommandSender_name); addMethodMapping("net/minecraft/command/ICommand getCommandUsage (Lnet/minecraft/command/ICommandSender;)Ljava/lang/String;", iCommand.name + " " + methods.get(0).name + " " + methods.get(0).desc); // List getCommandAliases(); methods = getMatchingMethods(iCommand, null, "()Ljava/util/List;"); if (methods.size() == 1) { addMethodMapping("net/minecraft/command/ICommand getCommandAliases ()Ljava/util/List;", iCommand.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // POST-15w35c, added MinecraftServer // void processCommand(MinecraftServer, ICommandSender sender, String[] args) throws CommandException; methods = getMatchingMethods(iCommand, null, "(L" + server.name + ";L" + iCommandSender.name + ";[Ljava/lang/String;)V"); if (methods.size() == 1) { addMethodMapping("net/minecraft/command/ICommand processCommand (Lnet/minecraft/server/MinecraftServer;Lnet/minecraft/command/ICommandSender;[Ljava/lang/String;)V", iCommand.name + " " + methods.get(0).name + " " + methods.get(0).desc); if (methods.get(0).exceptions.size() == 1) { addClassMapping("net/minecraft/command/CommandException", methods.get(0).exceptions.get(0)); } } // POST-15w35c, added MinecraftServer // boolean canCommandSenderUseCommand(MinecraftServer, ICommandSender sender); methods = getMatchingMethods(iCommand, null, "(L" + server.name + ";L" + iCommandSender.name + ";)Z"); if (methods.size() == 1) { addMethodMapping("net/minecraft/command/ICommand canCommandSenderUseCommand (Lnet/minecraft/server/MinecraftServer;Lnet/minecraft/command/ICommandSender;)Z", iCommand.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // POST-15w35c, added MinecraftServer // List addTabCompletionOptions(MinecraftServer, ICommandSender sender, String[] args, BlockPos pos); methods = getMatchingMethods(iCommand, null, "(L" + server.name + ";L" + iCommandSender.name + ";[Ljava/lang/String;L" + blockPos.name + ";)Ljava/util/List;"); if (methods.size() == 1) { addMethodMapping("net/minecraft/command/ICommand addTabCompletionOptions (Lnet/minecraft/server/MinecraftServer;Lnet/minecraft/command/ICommandSender;[Ljava/lang/String;Lnet/minecraft/util/BlockPos;)Ljava/util/List;", iCommand.name + " " + methods.get(0).name + " " + methods.get(0).desc); } //boolean isUsernameIndex(String[] args, int index); methods = getMatchingMethods(iCommand, null, "([Ljava/lang/String;I)Z"); if (methods.size() == 1) { addMethodMapping("net/minecraft/command/ICommand isUsernameIndex ([Ljava/lang/String;I)Z", iCommand.name + " " + methods.get(0).name + " " + methods.get(0).desc); } return true; } @Mapping(provides={ "net/minecraft/command/CommandResultStats", "net/minecraft/command/CommandResultStats$Type", }, providesMethods={ "net/minecraft/command/ICommandSender getCommandSenderName ()Ljava/lang/String;", "net/minecraft/command/ICommandSender getDisplayName ()Lnet/minecraft/util/IChatComponent;", "net/minecraft/command/ICommandSender addChatMessage (Lnet/minecraft/util/IChatComponent;)V", "net/minecraft/command/ICommandSender canCommandSenderUseCommand (ILjava/lang/String;)Z", "net/minecraft/command/ICommandSender getPosition ()Lnet/minecraft/util/BlockPos;", "net/minecraft/command/ICommandSender getPositionVector ()Lnet/minecraft/util/Vec3;", "net/minecraft/command/ICommandSender getEntityWorld ()Lnet/minecraft/world/World;", "net/minecraft/command/ICommandSender getCommandSenderEntity ()Lnet/minecraft/entity/Entity;", "net/minecraft/command/ICommandSender sendCommandFeedback ()Z", "net/minecraft/command/ICommandSender setCommandStat (Lnet/minecraft/command/CommandResultStats$Type;I)V" }, depends={ "net/minecraft/command/ICommandSender", "net/minecraft/util/IChatComponent", "net/minecraft/util/BlockPos", "net/minecraft/util/Vec3", "net/minecraft/world/World", "net/minecraft/entity/Entity" }) public boolean processICommandSenderClass() { ClassNode iCommandSender = getClassNodeFromMapping("net/minecraft/command/ICommandSender"); ClassNode iChatComponent = getClassNodeFromMapping("net/minecraft/util/IChatComponent"); ClassNode blockPos = getClassNodeFromMapping("net/minecraft/util/BlockPos"); ClassNode vec3 = getClassNodeFromMapping("net/minecraft/util/Vec3"); ClassNode world = getClassNodeFromMapping("net/minecraft/world/World"); ClassNode entity = getClassNodeFromMapping("net/minecraft/entity/Entity"); if (!MeddleUtil.notNull(iCommandSender, iChatComponent, blockPos, vec3, world, entity)) return false; // String getCommandSenderName(); List<MethodNode> methods = getMatchingMethods(iCommandSender, null, "()Ljava/lang/String;"); if (methods.size() == 1) { addMethodMapping("net/minecraft/command/ICommandSender getCommandSenderName ()Ljava/lang/String;", iCommandSender.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // IChatComponent getDisplayName(); methods = getMatchingMethods(iCommandSender, null, "()L" + iChatComponent.name + ";"); if (methods.size() == 1) { addMethodMapping("net/minecraft/command/ICommandSender getDisplayName ()Lnet/minecraft/util/IChatComponent;", iCommandSender.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // void addChatMessage(IChatComponent component); methods = getMatchingMethods(iCommandSender, null, "(L" + iChatComponent.name + ";)V"); if (methods.size() == 1) { addMethodMapping("net/minecraft/command/ICommandSender addChatMessage (Lnet/minecraft/util/IChatComponent;)V", iCommandSender.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // boolean canCommandSenderUseCommand(int permLevel, String commandName); methods = getMatchingMethods(iCommandSender, null, "(ILjava/lang/String;)Z"); if (methods.size() == 1) { addMethodMapping("net/minecraft/command/ICommandSender canCommandSenderUseCommand (ILjava/lang/String;)Z", iCommandSender.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // BlockPos getPosition(); methods = getMatchingMethods(iCommandSender, null, "()L" + blockPos.name + ";"); if (methods.size() == 1) { addMethodMapping("net/minecraft/command/ICommandSender getPosition ()Lnet/minecraft/util/BlockPos;", iCommandSender.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // Vec3 getPositionVector(); methods = getMatchingMethods(iCommandSender, null, "()L" + vec3.name + ";"); if (methods.size() == 1) { addMethodMapping("net/minecraft/command/ICommandSender getPositionVector ()Lnet/minecraft/util/Vec3;", iCommandSender.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // World getEntityWorld(); methods = getMatchingMethods(iCommandSender, null, "()L" + world.name + ";"); if (methods.size() == 1) { addMethodMapping("net/minecraft/command/ICommandSender getEntityWorld ()Lnet/minecraft/world/World;", iCommandSender.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // Entity getCommandSenderEntity(); methods = getMatchingMethods(iCommandSender, null, "()L" + entity.name + ";"); if (methods.size() == 1) { addMethodMapping("net/minecraft/command/ICommandSender getCommandSenderEntity ()Lnet/minecraft/entity/Entity;", iCommandSender.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // boolean sendCommandFeedback(); methods = getMatchingMethods(iCommandSender, null, "()Z"); if (methods.size() == 1) { addMethodMapping("net/minecraft/command/ICommandSender sendCommandFeedback ()Z", iCommandSender.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // void setCommandStat(CommandResultStats.Type type, int amount); String commandResultStatsType_name = null; methods.clear(); for (MethodNode method : iCommandSender.methods) { if (!method.desc.endsWith(";I)V")) continue; Type t = Type.getMethodType(method.desc); Type[] args = t.getArgumentTypes(); if (args.length != 2) continue; commandResultStatsType_name = args[0].getClassName(); methods.add(method); } if (methods.size() == 1) { if (commandResultStatsType_name.contains("$")) { String baseName = commandResultStatsType_name.substring(0, commandResultStatsType_name.indexOf('$')); addClassMapping("net/minecraft/command/CommandResultStats", baseName); } addClassMapping("net/minecraft/command/CommandResultStats$Type", commandResultStatsType_name); addMethodMapping("net/minecraft/command/ICommandSender setCommandStat (Lnet/minecraft/command/CommandResultStats$Type;I)V", iCommandSender.name + " " + methods.get(0).name + " " + methods.get(0).desc); } return true; } @Mapping(provides="net/minecraft/entity/player/EntityPlayerMP", depends="net/minecraft/server/MinecraftServer") public boolean getEntityPlayerMPClass() { ClassNode server = getClassNodeFromMapping("net/minecraft/server/MinecraftServer"); if (server == null) return false; List<MethodNode> methods = getMatchingMethods(server, null, "()V"); for (MethodNode method : methods) { for (AbstractInsnNode insn = method.instructions.getFirst(); insn != null; insn = insn.getNext()) { if (insn.getOpcode() != Opcodes.CHECKCAST) continue; TypeInsnNode tn = (TypeInsnNode)insn; if (searchConstantPoolForStrings(tn.desc, "en_US", "playerGameType", "Player being ticked")) { addClassMapping("net/minecraft/entity/player/EntityPlayerMP", tn.desc); return true; } } } return false; } @Mapping(provides={ "net/minecraft/network/play/server/S2DPacketOpenWindow", "net/minecraft/network/NetHandlerPlayServer", "net/minecraft/inventory/ICrafting" }, providesFields={ "net/minecraft/entity/player/EntityPlayer openContainer Lnet/minecraft/inventory/Container;", "net/minecraft/inventory/Container windowId I" }, providesMethods={ "net/minecraft/network/NetHandlerPlayServer sendPacket (Lnet/minecraft/network/Packet;)V", "net/minecraft/inventory/Container onCraftGuiOpened (Lnet/minecraft/inventory/ICrafting;)V" }, depends={ "net/minecraft/entity/player/EntityPlayerMP", "net/minecraft/entity/player/EntityPlayer", "net/minecraft/world/IInteractionObject", "net/minecraft/network/Packet", "net/minecraft/inventory/Container" }) public boolean processEntityPlayerMPClass() { ClassNode playerMP = getClassNodeFromMapping("net/minecraft/entity/player/EntityPlayerMP"); ClassNode player = getClassNodeFromMapping("net/minecraft/entity/player/EntityPlayer"); ClassNode iInteractionObject = getClassNodeFromMapping("net/minecraft/world/IInteractionObject"); ClassNode packet = getClassNodeFromMapping("net/minecraft/network/Packet"); ClassNode container = getClassNodeFromMapping("net/minecraft/inventory/Container"); if (!MeddleUtil.notNull(playerMP, player, iInteractionObject, packet, container)) return false; String iCrafting_name = null; if (playerMP.interfaces.size() == 1) { String className = playerMP.interfaces.get(0); ClassNode iCrafting = getClassNode(className); if (iCrafting != null) { boolean matched = true; for (MethodNode method : iCrafting.methods) { Type t = Type.getMethodType(method.desc); if (t.getReturnType().getSort() != Type.VOID) matched = false; if (t.getArgumentTypes().length < 1) matched = false; if (!t.getArgumentTypes()[0].getClassName().equals(container.name)) matched = false; } if (matched) { addClassMapping("net/minecraft/inventory/ICrafting", iCrafting); iCrafting_name = iCrafting.name; } } } List<MethodNode> methods = getMatchingMethods(playerMP, null, "(L" + iInteractionObject.name + ";)V"); if (methods.size() == 1) { for (AbstractInsnNode insn = methods.get(0).instructions.getFirst(); insn != null; insn = insn.getNext()) { if (insn.getOpcode() == Opcodes.NEW) { TypeInsnNode tn = (TypeInsnNode)insn; ClassNode cn = getClassNode(tn.desc); if (cn == null) continue; for (String iface : cn.interfaces) { if (iface.equals(packet.name)) addClassMapping("net/minecraft/network/play/server/S2DPacketOpenWindow", cn.name); } } // net/minecraft/network/NetHandlerPlayServer.sendPacket (Lnet/minecraft/network/Packet;)V if (insn.getOpcode() == Opcodes.INVOKEVIRTUAL) { MethodInsnNode mn = (MethodInsnNode)insn; if (mn.desc.equals("(L" + packet.name + ";)V")) { if (searchConstantPoolForStrings(mn.owner, "keepAlive", "Sending packet")) { addClassMapping("net/minecraft/network/NetHandlerPlayServer", mn.owner); addMethodMapping("net/minecraft/network/NetHandlerPlayServer sendPacket (Lnet/minecraft/network/Packet;)V", mn.owner + " " + mn.name + " " + mn.desc); } } // public void Container.onCraftGuiOpened(ICrafting listener) if (mn.owner.equals(container.name) && mn.desc.equals("(L" + iCrafting_name + ";)V")) { addMethodMapping("net/minecraft/inventory/Container onCraftGuiOpened (Lnet/minecraft/inventory/ICrafting;)V", container.name + " " + mn.name + " " + mn.desc); } } if (insn.getOpcode() == Opcodes.PUTFIELD) { FieldInsnNode fn = (FieldInsnNode)insn; if (fn.owner.equals(playerMP.name) && fn.desc.equals("L" + container.name + ";")) { addFieldMapping("net/minecraft/entity/player/EntityPlayer openContainer Lnet/minecraft/inventory/Container;", player.name + " " + fn.name + " " + fn.desc); } if (fn.owner.equals(container.name) && fn.desc.equals("I")) { addFieldMapping("net/minecraft/inventory/Container windowId I", container.name + " " + fn.name + " " + fn.desc); } } } } return true; } @Mapping(providesFields={ "net/minecraft/util/AxisAlignedBB minX D", "net/minecraft/util/AxisAlignedBB minY D", "net/minecraft/util/AxisAlignedBB minZ D", "net/minecraft/util/AxisAlignedBB maxX D", "net/minecraft/util/AxisAlignedBB maxY D", "net/minecraft/util/AxisAlignedBB maxZ D" }, providesMethods={ "net/minecraft/util/AxisAlignedBB offset (Lnet/minecraft/util/BlockPos;)Lnet/minecraft/util/AxisAlignedBB;" }, depends={ "net/minecraft/util/AxisAlignedBB", "net/minecraft/util/BlockPos" }) public boolean processAxisAlignedBBClass() { ClassNode aabb = getClassNodeFromMapping("net/minecraft/util/AxisAlignedBB"); ClassNode blockPos = getClassNodeFromMapping("net/minecraft/util/BlockPos"); if (!MeddleUtil.notNull(aabb, blockPos)) return false; MethodNode toString = DynamicMappings.getMethodNode(aabb, "- toString ()Ljava/lang/String;"); if (toString == null) return false; List<FieldInsnNode> fieldInsns = DynamicMappings.getAllInsnNodesOfType(toString.instructions.getFirst(), FieldInsnNode.class); if (fieldInsns.size() == 6) { String[] fieldNames = {"minX", "minY", "minZ", "maxX", "maxY", "maxZ"}; for (int n = 0; n < 6; n++) { FieldInsnNode fn = fieldInsns.get(n); if (fn.owner.equals(aabb.name)) { addFieldMapping("net/minecraft/util/AxisAlignedBB " + fieldNames[n] + " D", fn.owner + " " + fn.name + " " + fn.desc); } } } // public AxisAlignedBB offset(BlockPos param0) List<MethodNode> methods = getMatchingMethods(aabb, null, "(L" + blockPos.name + ";)L" + aabb.name + ";"); if (methods.size() == 1) { addMethodMapping("net/minecraft/util/AxisAlignedBB offset (Lnet/minecraft/util/BlockPos;)Lnet/minecraft/util/AxisAlignedBB;", aabb.name + " " + methods.get(0).name + " " + methods.get(0).desc); } return true; } @Mapping(providesMethods={ "net/minecraft/util/RegistryNamespaced getIDForObject (Ljava/lang/Object;)I", "net/minecraft/util/RegistryNamespaced getObjectById (I)Ljava/lang/Object;", "net/minecraft/util/RegistryNamespaced containsKey (Ljava/lang/Object;)Z", "net/minecraft/util/RegistryNamespaced register (ILjava/lang/Object;Ljava/lang/Object;)V", "net/minecraft/util/RegistryNamespaced getObject (Ljava/lang/Object;)Ljava/lang/Object;", "net/minecraft/util/RegistryNamespaced getNameForObject (Ljava/lang/Object;)Ljava/lang/Object;" }, depends={ "net/minecraft/util/RegistryNamespaced" }) public boolean processRegistryNamespacedClass() { ClassNode registry = getClassNodeFromMapping("net/minecraft/util/RegistryNamespaced"); if (!MeddleUtil.notNull(registry)) return false; // public int getIDForObject(Object p_148757_1_) List<MethodNode> methods = getMatchingMethods(registry, null, "(Ljava/lang/Object;)I"); if (methods.size() == 1) { addMethodMapping("net/minecraft/util/RegistryNamespaced getIDForObject (Ljava/lang/Object;)I", registry.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public Object getObjectById(int id) methods = getMatchingMethods(registry, null, "(I)Ljava/lang/Object;"); if (methods.size() == 1) { addMethodMapping("net/minecraft/util/RegistryNamespaced getObjectById (I)Ljava/lang/Object;", registry.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public boolean containsKey(Object p_148741_1_) methods = getMatchingMethods(registry, null, "(Ljava/lang/Object;)Z"); if (methods.size() == 1) { addMethodMapping("net/minecraft/util/RegistryNamespaced containsKey (Ljava/lang/Object;)Z", registry.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public void register(int id, Object p_177775_2_, Object p_177775_3_) methods = getMatchingMethods(registry, null, "(ILjava/lang/Object;Ljava/lang/Object;)V"); if (methods.size() == 1) { addMethodMapping("net/minecraft/util/RegistryNamespaced register (ILjava/lang/Object;Ljava/lang/Object;)V", registry.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public Object getObject(Object p_82594_1_) // public Object getNameForObject(Object p_177774_1_) methods = getMatchingMethods(registry, null, "(Ljava/lang/Object;)Ljava/lang/Object;"); if (methods.size() == 2) { MethodNode m1 = methods.get(0); MethodNode m2 = methods.get(1); if (matchOpcodeSequence(m1.instructions.getFirst(), Opcodes.ALOAD, Opcodes.ALOAD, Opcodes.INVOKESPECIAL, Opcodes.ARETURN) && matchOpcodeSequence(m2.instructions.getFirst(), Opcodes.ALOAD, Opcodes.GETFIELD, Opcodes.ALOAD, Opcodes.INVOKEINTERFACE, Opcodes.ARETURN)) { addMethodMapping("net/minecraft/util/RegistryNamespaced getObject (Ljava/lang/Object;)Ljava/lang/Object;", registry.name + " " + m1.name + " " + m1.desc); addMethodMapping("net/minecraft/util/RegistryNamespaced getNameForObject (Ljava/lang/Object;)Ljava/lang/Object;", registry.name + " " + m2.name + " " + m2.desc); } } return true; } @Mapping(providesFields={ "net/minecraft/util/MainOrOffHand MAIN_HAND Lnet/minecraft/util/MainOrOffHand;", "net/minecraft/util/MainOrOffHand OFF_HAND Lnet/minecraft/util/MainOrOffHand;" }, depends="net/minecraft/util/MainOrOffHand") public boolean processMainOrOffHand() { ClassNode mainOrOffHand = getClassNodeFromMapping("net/minecraft/util/MainOrOffHand"); if (mainOrOffHand == null) return false; List<FieldNode> fields = getMatchingFields(mainOrOffHand, null, "L" + mainOrOffHand.name + ";"); if (fields.size() == 2) { addFieldMapping("net/minecraft/util/MainOrOffHand MAIN_HAND Lnet/minecraft/util/MainOrOffHand;", mainOrOffHand.name + " " + fields.get(0).name + " " + fields.get(0).desc); addFieldMapping("net/minecraft/util/MainOrOffHand OFF_HAND Lnet/minecraft/util/MainOrOffHand;", mainOrOffHand.name + " " + fields.get(1).name + " " + fields.get(1).desc); } return true; } @Mapping(provides={ "net/minecraft/inventory/EnumEquipSlot" }, providesMethods={ "net/minecraft/entity/EntityLivingBase getHeldItem (Lnet/minecraft/util/MainOrOffHand;)Lnet/minecraft/item/ItemStack;", "net/minecraft/entity/EntityLivingBase getHeldMainHandItem ()Lnet/minecraft/item/ItemStack;", "net/minecraft/entity/EntityLivingBase getHeldOffHandItem ()Lnet/minecraft/item/ItemStack;", "net/minecraft/entity/EntityLivingBase setHeldItem (Lnet/minecraft/util/MainOrOffHand;Lnet/minecraft/item/ItemStack;)V", "net/minecraft/entity/Entity setPositionAndUpdate (DDD)V" }, depends={ "net/minecraft/entity/Entity", "net/minecraft/entity/EntityLivingBase", "net/minecraft/item/ItemStack", "net/minecraft/util/MainOrOffHand" }) public boolean processEntityLivingBase() { ClassNode entity = getClassNodeFromMapping("net/minecraft/entity/Entity"); ClassNode entityLivingBase = getClassNodeFromMapping("net/minecraft/entity/EntityLivingBase"); ClassNode itemStack = getClassNodeFromMapping("net/minecraft/item/ItemStack"); ClassNode mainOrOffHand = getClassNodeFromMapping("net/minecraft/util/MainOrOffHand"); if (!MeddleUtil.notNull(entity, entityLivingBase, itemStack, mainOrOffHand)) return false; String enumEquipSlot_name = null; //public ItemStack getHeldItem(MainOrOffHand param0) List<MethodNode> methods = getMatchingMethods(entityLivingBase, null, "(L" + mainOrOffHand.name + ";)L" + itemStack.name + ";"); if (methods.size() == 1) { addMethodMapping("net/minecraft/entity/EntityLivingBase getHeldItem (Lnet/minecraft/util/MainOrOffHand;)Lnet/minecraft/item/ItemStack;", entityLivingBase.name + " " + methods.get(0).name + " " + methods.get(0).desc); List<MethodInsnNode> nodes = getAllInsnNodesOfType(methods.get(0), MethodInsnNode.class); for (MethodInsnNode mn : nodes) { if (!mn.owner.equals(entityLivingBase.name)) continue; if (!mn.desc.startsWith("(L") || !mn.desc.endsWith(")L" + itemStack.name + ";")) continue; Type t = Type.getMethodType(mn.desc); Type[] args = t.getArgumentTypes(); if (args.length != 1) continue; String className = args[0].getClassName(); if (searchConstantPoolForStrings(className, "MAINHAND", "OFFHAND", "FEET", "LEGS")) { addClassMapping("net/minecraft/inventory/EnumEquipSlot", className); enumEquipSlot_name = className; break; } } } // ItemStack getHeldMainHandItem(), ItemStack getHeldOffHandItem() methods = getMatchingMethods(entityLivingBase, null, "()L" + itemStack.name + ";"); // Remove getItemInUse() in case we're on the client for (Iterator<MethodNode> it = methods.iterator(); it.hasNext(); ) { MethodNode method = it.next(); if (matchOpcodeSequence(method.instructions.getFirst(), Opcodes.ALOAD, Opcodes.GETFIELD, Opcodes.ARETURN)) it.remove(); } if (methods.size() == 2 && enumEquipSlot_name != null) { List<FieldInsnNode> nodes1 = getAllInsnNodesOfType(methods.get(0), FieldInsnNode.class); List<FieldInsnNode> nodes2 = getAllInsnNodesOfType(methods.get(1), FieldInsnNode.class); if (nodes1.size() == 1 && nodes2.size() == 1) { FieldInsnNode fn1 = nodes1.get(0); FieldInsnNode fn2 = nodes2.get(0); if (fn1.owner.equals(enumEquipSlot_name) && fn2.owner.equals(enumEquipSlot_name)) { MethodNode main = null; MethodNode off = null; if (fn1.name.equals("a") && fn2.name.equals("b")) { main = methods.get(0); off = methods.get(1); } else if (fn1.name.equals("b") && fn2.name.equals("a")) { main = methods.get(1); off = methods.get(0); } if (main != null && off != null) { addMethodMapping("net/minecraft/entity/EntityLivingBase getHeldMainHandItem ()Lnet/minecraft/item/ItemStack;", entityLivingBase.name + " " + main.name + " " + main.desc); addMethodMapping("net/minecraft/entity/EntityLivingBase getHeldOffHandItem ()Lnet/minecraft/item/ItemStack;", entityLivingBase.name + " " + off.name + " " + off.desc); } } } } // void setHeldItem(MainOrOffHand, ItemStack) methods = getMatchingMethods(entityLivingBase, null, "(L" + mainOrOffHand.name + ";L" + itemStack.name + ";)V"); if (methods.size() == 1) { addMethodMapping("net/minecraft/entity/EntityLivingBase setHeldItem (Lnet/minecraft/util/MainOrOffHand;Lnet/minecraft/item/ItemStack;)V", entityLivingBase.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public boolean EntityLivingBase.teleportTo(double param0, double param1, double param2) (Added in 15w49a) methods = getMatchingMethods(entityLivingBase, null, "(DDD)Z"); if (methods.size() == 1) { addMethodMapping("net/minecraft/entity/EntityLivingBase teleportTo (DDD)Z", entityLivingBase.name + " " + methods.get(0).name + " " + methods.get(0).desc); // public void Entity.setPositionAndUpdate(double, double, double) List<MethodInsnNode> mnodes = getAllInsnNodesOfType(methods.get(0), MethodInsnNode.class); List<String> mnames = new ArrayList<>(); for (Iterator<MethodInsnNode> it = mnodes.iterator(); it.hasNext();) { MethodInsnNode mn = it.next(); if (!mn.owner.equals(entityLivingBase.name) || !mn.desc.equals("(DDD)V")) { it.remove(); continue; } if (getMethodNode(entity, "--- " + mn.name + " (DDD)V") == null) { it.remove(); continue; } // Remove duplicate method invocations if (mnames.contains(mn.name)) { it.remove(); continue; } mnames.add(mn.name); } if (mnodes.size() == 1) { addMethodMapping("net/minecraft/entity/Entity setPositionAndUpdate (DDD)V", entity.name + " " + mnodes.get(0).name + " (DDD)V"); } } return true; } @Mapping(provides="net/minecraft/block/properties/PropertyInteger", providesFields={ "net/minecraft/block/BlockLiquid LEVEL Lnet/minecraft/block/properties/PropertyInteger;" }, providesMethods={ "net/minecraft/block/Block isPassable (Lnet/minecraft/world/IBlockAccess;Lnet/minecraft/util/BlockPos;)Z", "net/minecraft/block/Block tickRate (Lnet/minecraft/world/World;)I", "net/minecraft/block/properties/PropertyInteger create (Ljava/lang/String;II)Lnet/minecraft/block/properties/PropertyInteger;" }, depends={ "net/minecraft/block/Block", "net/minecraft/block/BlockLiquid", "net/minecraft/world/IBlockAccess", "net/minecraft/util/BlockPos", "net/minecraft/world/World" }) public boolean processBlockLiquidClass() { ClassNode block = getClassNodeFromMapping("net/minecraft/block/Block"); ClassNode blockLiquid = getClassNodeFromMapping("net/minecraft/block/BlockLiquid"); ClassNode iBlockAccess = getClassNodeFromMapping("net/minecraft/world/IBlockAccess"); ClassNode blockPos = getClassNodeFromMapping("net/minecraft/util/BlockPos"); ClassNode world = getClassNodeFromMapping("net/minecraft/world/World"); if (!MeddleUtil.notNull(block, blockLiquid, iBlockAccess, blockPos, world)) return false; MethodNode clinit = getMethodNode(blockLiquid, "--- <clinit> ()V"); if (clinit != null) { List<FieldInsnNode> fieldNodes = getAllInsnNodesOfType(clinit, FieldInsnNode.class); List<MethodInsnNode> methodNodes = getAllInsnNodesOfType(clinit, MethodInsnNode.class); String propertyInteger = null; if (fieldNodes.size() == 1 && fieldNodes.get(0).owner.equals(blockLiquid.name)) { String className = Type.getType(fieldNodes.get(0).desc).getClassName(); if (searchConstantPoolForStrings(className, "Min value of ", " must be 0 or greater")) { addClassMapping("net/minecraft/block/properties/PropertyInteger", className); propertyInteger = className; addFieldMapping("net/minecraft/block/BlockLiquid LEVEL Lnet/minecraft/block/properties/PropertyInteger;", blockLiquid.name + " " + fieldNodes.get(0).name + " " + fieldNodes.get(0).desc); } } if (methodNodes.size() == 1 && propertyInteger != null) { MethodInsnNode mn = methodNodes.get(0); if (mn.owner.equals(propertyInteger) && mn.desc.equals("(Ljava/lang/String;II)L" + propertyInteger + ";")) { addMethodMapping("net/minecraft/block/properties/PropertyInteger create (Ljava/lang/String;II)Lnet/minecraft/block/properties/PropertyInteger;", propertyInteger + " " + mn.name + " " + mn.desc); } } } // public boolean isPassable(IBlockAccess worldIn, BlockPos pos) List<MethodNode> methods = getMatchingMethods(blockLiquid, null, assembleDescriptor("(", iBlockAccess, blockPos, ")Z")); for (Iterator<MethodNode> it = methods.iterator(); it.hasNext();) { MethodNode method = it.next(); if (getMethodNode(block, "--- " + method.name + " " + method.desc) == null) it.remove(); } if (methods.size() == 1) { addMethodMapping("net/minecraft/block/Block isPassable (Lnet/minecraft/world/IBlockAccess;Lnet/minecraft/util/BlockPos;)Z", block.name + " " + methods.get(0).name + " " + methods.get(0).desc); // TODO - Get Material.lava } // public int tickRate(World worldIn) methods = getMatchingMethods(blockLiquid, null, assembleDescriptor("(", world, ")I")); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/Block tickRate (Lnet/minecraft/world/World;)I", block.name + " " + methods.get(0).name + " " + methods.get(0).desc); } return true; } @Mapping(providesFields={ "net/minecraft/block/Block AIR_ID Lnet/minecraft/util/ResourceLocation;", "net/minecraft/block/Block needsRandomTick Z", "net/minecraft/block/Block blockHardness F" }, providesMethods={ "net/minecraft/block/state/IBlockWrapper getMaterial ()Lnet/minecraft/block/material/Material;", "net/minecraft/block/material/Material isSolid ()Z", "net/minecraft/block/Block isFullBlock (Lnet/minecraft/block/state/IBlockState;)Z", "net/minecraft/block/Block getUseNeighborBrightness (Lnet/minecraft/block/state/IBlockState;)Z", "net/minecraft/block/Block onBlockEventReceived (Lnet/minecraft/block/state/IBlockState;Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;II)Z", "net/minecraft/block/Block getLightOpacity (Lnet/minecraft/block/state/IBlockState;)I", "net/minecraft/block/Block getLightValue (Lnet/minecraft/block/state/IBlockState;)I", "net/minecraft/block/Block getTickRandomly ()Z", "net/minecraft/block/Block getBlockHardness (Lnet/minecraft/block/state/IBlockState;Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;)F", "net/minecraft/block/Block setBlockUnbreakable ()Lnet/minecraft/block/Block;" }, dependsFields={ "net/minecraft/block/Block fullBlock Z", "net/minecraft/block/Block useNeighborBrightness Z", "net/minecraft/block/Block lightOpacity I", "net/minecraft/block/Block translucent Z", "net/minecraft/block/Block lightValue I" }, dependsMethods={ "net/minecraft/block/Block isBlockSolid (Lnet/minecraft/world/IBlockAccess;Lnet/minecraft/util/BlockPos;Lnet/minecraft/util/EnumFacing;)Z", "net/minecraft/block/Block setTickRandomly (Z)Lnet/minecraft/block/Block;", "net/minecraft/block/Block setHardness (F)Lnet/minecraft/block/Block;" }, depends={ "net/minecraft/block/Block", "net/minecraft/block/state/IBlockState", "net/minecraft/block/state/IBlockWrapper", "net/minecraft/block/material/Material", "net/minecraft/util/ResourceLocation", "net/minecraft/world/World", "net/minecraft/util/BlockPos", "net/minecraft/util/AxisAlignedBB" }) public boolean processBlockClass4() { ClassNode block = getClassNodeFromMapping("net/minecraft/block/Block"); ClassNode iBlockState = getClassNodeFromMapping("net/minecraft/block/state/IBlockState"); ClassNode iBlockWrapper = getClassNodeFromMapping("net/minecraft/block/state/IBlockWrapper"); ClassNode material = getClassNodeFromMapping("net/minecraft/block/material/Material"); ClassNode resourceLocation = getClassNodeFromMapping("net/minecraft/util/ResourceLocation"); ClassNode world = getClassNodeFromMapping("net/minecraft/world/World"); ClassNode blockPos = getClassNodeFromMapping("net/minecraft/util/BlockPos"); ClassNode aabb = getClassNodeFromMapping("net/minecraft/util/AxisAlignedBB"); if (!MeddleUtil.notNull(block, iBlockState, iBlockWrapper, material, resourceLocation, world, blockPos, aabb)) return false; // Get Block.AIR_ID field String air_id_name = null; int count = 0; for (FieldNode field : block.fields) { if (field.desc.equals("L" + resourceLocation.name + ";")) { air_id_name = field.name; count++; } } if (air_id_name != null && count == 1) { addFieldMapping("net/minecraft/block/Block AIR_ID Lnet/minecraft/util/ResourceLocation;", block.name + " " + air_id_name + " L" + resourceLocation.name + ";"); } MethodNode isBlockSolid = getMethodNodeFromMapping(block, "net/minecraft/block/Block isBlockSolid (Lnet/minecraft/world/IBlockAccess;Lnet/minecraft/util/BlockPos;Lnet/minecraft/util/EnumFacing;)Z"); if (isBlockSolid != null) { List<MethodInsnNode> nodes = getAllInsnNodesOfType(isBlockSolid, MethodInsnNode.class); List<MethodInsnNode> getMaterial = new ArrayList<>(); List<MethodInsnNode> isSolid = new ArrayList<>(); for (MethodInsnNode mn : nodes) { if (mn.owner.equals(iBlockState.name) && mn.desc.equals("()L" + material.name + ";")) getMaterial.add(mn); else if (mn.owner.equals(material.name) && mn.desc.equals("()Z")) isSolid.add(mn); } if (getMaterial.size() == 1) { addMethodMapping("net/minecraft/block/state/IBlockWrapper getMaterial ()Lnet/minecraft/block/material/Material;", iBlockWrapper.name + " " + getMaterial.get(0).name + " " + getMaterial.get(0).desc); } if (isSolid.size() == 1) { addMethodMapping("net/minecraft/block/material/Material isSolid ()Z", material.name + " " + isSolid.get(0).name + " " + isSolid.get(0).desc); } } FieldNode fullBlock = getFieldNodeFromMapping(block, "net/minecraft/block/Block fullBlock Z"); FieldNode useNeighborBrightness = getFieldNodeFromMapping(block, "net/minecraft/block/Block useNeighborBrightness Z"); List<MethodNode> methods = getMatchingMethods(block, null, "(L" + iBlockState.name + ";)Z"); if (fullBlock != null && useNeighborBrightness != null) { List<MethodNode> isFullBlock = new ArrayList<>(); List<MethodNode> getUseNeighborBrightness = new ArrayList<>(); for (MethodNode method : methods) { AbstractInsnNode[] nodes = getOpcodeSequenceArray(method.instructions.getFirst(), Opcodes.ALOAD, Opcodes.GETFIELD, Opcodes.IRETURN); if (nodes == null) continue; FieldInsnNode fn = (FieldInsnNode)nodes[1]; if (fn.name.equals(fullBlock.name)) isFullBlock.add(method); else if (fn.name.equals(useNeighborBrightness.name)) getUseNeighborBrightness.add(method); } if (isFullBlock.size() == 1) { addMethodMapping("net/minecraft/block/Block isFullBlock (Lnet/minecraft/block/state/IBlockState;)Z", block.name + " " + isFullBlock.get(0).name + " " + isFullBlock.get(0).desc); } if (getUseNeighborBrightness.size() == 1) { addMethodMapping("net/minecraft/block/Block getUseNeighborBrightness (Lnet/minecraft/block/state/IBlockState;)Z", block.name + " " + getUseNeighborBrightness.get(0).name + " " + getUseNeighborBrightness.get(0).desc); } } // public boolean onBlockEventReceived(IBlockState state, World worldIn, BlockPos pos, int eventID, int eventParam) methods = getMatchingMethods(block, null, assembleDescriptor("(", iBlockState, world, blockPos, "II)Z")); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/Block onBlockEventReceived (Lnet/minecraft/block/state/IBlockState;Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;II)Z", block.name + " " + methods.get(0).name + " " + methods.get(0).desc); } FieldNode lightOpacity_field = getFieldNodeFromMapping(block, "net/minecraft/block/Block lightOpacity I"); FieldNode lightValue_field = getFieldNodeFromMapping(block, "net/minecraft/block/Block lightValue I"); // public int getLightOpacity(IBlockState state) if (lightOpacity_field != null) { methods = getMatchingMethods(block, null, assembleDescriptor("(", iBlockState, ")I")); methods = filterMethodsUsingField(methods, block.name, lightOpacity_field.name, lightOpacity_field.desc); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/Block getLightOpacity (Lnet/minecraft/block/state/IBlockState;)I", block.name + " " + methods.get(0).name + " " + methods.get(0).desc); } } // public int getLightValue(IBlockState state) if (lightValue_field != null) { methods = getMatchingMethods(block, null, assembleDescriptor("(", iBlockState, ")I")); methods = filterMethodsUsingField(methods, block.name, lightValue_field.name, lightValue_field.desc); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/Block getLightValue (Lnet/minecraft/block/state/IBlockState;)I", block.name + " " + methods.get(0).name + " " + methods.get(0).desc); } } // boolean needsRandomTick String needsRandomTick_name = null; MethodNode setTickRandomly = getMethodNodeFromMapping(block, "net/minecraft/block/Block setTickRandomly (Z)Lnet/minecraft/block/Block;"); if (setTickRandomly != null) { List<FieldInsnNode> fnList = getAllInsnNodesOfType(setTickRandomly, FieldInsnNode.class); if (fnList.size() == 1) { FieldInsnNode fn = fnList.get(0); if (fn.desc.equals("Z") && fn.owner.equals(block.name)) { addFieldMapping("net/minecraft/block/Block needsRandomTick Z", block.name + " " + fn.name + " Z"); needsRandomTick_name = fn.name; } } } // public boolean getTickRandomly() if (needsRandomTick_name != null) { methods = getMatchingMethods(block, null, "()Z"); methods = filterMethodsUsingField(methods, block.name, needsRandomTick_name, "Z"); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/Block getTickRandomly ()Z", block.name + " " + methods.get(0).name + " " + methods.get(0).desc); } } // public float getBlockHardness(IBlockState param0, World param1, BlockPos param2) // float blockHardness methods = getMatchingMethods(block, null, assembleDescriptor("(", iBlockState, world, blockPos, ")F")); if (methods.size() == 1) { MethodNode method = methods.get(0); AbstractInsnNode[] nodes = getOpcodeSequenceArray(method.instructions.getFirst(), Opcodes.ALOAD, Opcodes.GETFIELD, Opcodes.FRETURN); if (nodes != null) { FieldInsnNode fn = (FieldInsnNode)nodes[1]; if (fn.owner.equals(block.name)) { addMethodMapping("net/minecraft/block/Block getBlockHardness (Lnet/minecraft/block/state/IBlockState;Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;)F", block.name + " " + method.name + " " + method.desc); addFieldMapping("net/minecraft/block/Block blockHardness F", block.name + " " + fn.name + " F"); } } } // protected Block setBlockUnbreakable() MethodNode setHardness = getMethodNodeFromMapping(block, "net/minecraft/block/Block setHardness (F)Lnet/minecraft/block/Block;"); if (setHardness != null) { methods = getMatchingMethods(block, null, "()L" + block.name + ";"); methods = filterMethodsUsingMethod(methods, block.name, setHardness.name, setHardness.desc); if (methods.size() == 1) { List<Float> floats = getFloatsFromMethod(methods.get(0)); if (floats.size() == 1 && floats.get(0) == -1.0F) { addMethodMapping("net/minecraft/block/Block setBlockUnbreakable ()Lnet/minecraft/block/Block;", block.name + " " + methods.get(0).name + " " + methods.get(0).desc); } } } return true; } @Mapping(provides={ "net/minecraft/stats/StatBase" }, depends={ "net/minecraft/stats/StatList" }) public boolean processStatListClass() { ClassNode statList = getClassNodeFromMapping("net/minecraft/stats/StatList"); if (!MeddleUtil.notNull(statList)) return false; String statBase = null; for (FieldNode field : statList.fields) { // We just want arrays if (!field.desc.startsWith("[")) continue; // And only arrays of objects Type t = Type.getType(field.desc).getElementType(); if (t.getSort() != Type.OBJECT) continue; String className = t.getClassName(); if (searchConstantPoolForStrings(className, "Duplicate stat id: \"", "Stat{id=")) { addClassMapping("net/minecraft/stats/StatBase", className); statBase = className; break; } } return true; } @Mapping(providesMethods={ "net/minecraft/block/Block getItem (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;Lnet/minecraft/block/state/IBlockState;)Lnet/minecraft/item/ItemStack;" }, depends={ "net/minecraft/block/Block", "net/minecraft/block/BlockReed", "net/minecraft/world/World", "net/minecraft/util/BlockPos", "net/minecraft/block/state/IBlockState", "net/minecraft/item/ItemStack" }) public boolean processBlockFarmlandClass() { ClassNode block = getClassNodeFromMapping("net/minecraft/block/Block"); ClassNode reed = getClassNodeFromMapping("net/minecraft/block/BlockReed"); ClassNode world = getClassNodeFromMapping("net/minecraft/world/World"); ClassNode blockPos = getClassNodeFromMapping("net/minecraft/util/BlockPos"); ClassNode iBlockState = getClassNodeFromMapping("net/minecraft/block/state/IBlockState"); ClassNode itemStack = getClassNodeFromMapping("net/minecraft/item/ItemStack"); if (!MeddleUtil.notNull(block, reed, world, blockPos, iBlockState, itemStack)) return false; // public ItemStack getItem(World param0, BlockPos param1, IBlockState param2) List<MethodNode> methods = getMatchingMethods(reed, null, assembleDescriptor("(", world, blockPos, iBlockState, ")", itemStack)); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/Block getItem (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;Lnet/minecraft/block/state/IBlockState;)Lnet/minecraft/item/ItemStack;", block.name + " " + methods.get(0).name + " " + methods.get(0).desc); } return true; } @Mapping(provides={ "net/minecraft/block/BlockBush" }, providesMethods={ "net/minecraft/block/BlockBush canPlaceBlockOn (Lnet/minecraft/block/state/IBlockState;)Z", "net/minecraft/block/BlockBush canBlockStay (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;Lnet/minecraft/block/state/IBlockState;)Z" }, depends={ "net/minecraft/block/Block", "net/minecraft/block/BlockLilyPad", "net/minecraft/block/BlockMushroom", "net/minecraft/block/BlockTallGrass", "net/minecraft/world/World", "net/minecraft/util/BlockPos", "net/minecraft/block/state/IBlockState", "net/minecraft/item/ItemStack" }) public boolean processBlockLilypadClass() { ClassNode block = getClassNodeFromMapping("net/minecraft/block/Block"); ClassNode lilypad = getClassNodeFromMapping("net/minecraft/block/BlockLilyPad"); ClassNode mushroom = getClassNodeFromMapping("net/minecraft/block/BlockMushroom"); ClassNode tallGrass = getClassNodeFromMapping("net/minecraft/block/BlockTallGrass"); ClassNode world = getClassNodeFromMapping("net/minecraft/world/World"); ClassNode blockPos = getClassNodeFromMapping("net/minecraft/util/BlockPos"); ClassNode iBlockState = getClassNodeFromMapping("net/minecraft/block/state/IBlockState"); ClassNode itemStack = getClassNodeFromMapping("net/minecraft/item/ItemStack"); if (!MeddleUtil.notNull(block, lilypad, world, blockPos, iBlockState, itemStack)) return false; ClassNode blockBush = getClassNode(lilypad.superName); if (blockBush != null) { Set<String> children = DynamicMappings.classesExtendFrom.get(blockBush.name); if (children.contains(tallGrass.name) && children.contains(mushroom.name)) { addClassMapping("net/minecraft/block/BlockBush", blockBush.name); } else return false; } // protected boolean canPlaceBlockOn(IBlockState param0) List<MethodNode> methods = getMatchingMethods(lilypad, null, "(L" + iBlockState.name + ";)Z"); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/BlockBush canPlaceBlockOn (Lnet/minecraft/block/state/IBlockState;)Z", blockBush.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // public boolean canBlockStay(World param0, BlockPos param1, IBlockState param2) { methods = getMatchingMethods(lilypad, null, assembleDescriptor("(", world, blockPos, iBlockState, ")Z")); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/BlockBush canBlockStay (Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;Lnet/minecraft/block/state/IBlockState;)Z", blockBush.name + " " + methods.get(0).name + " " + methods.get(0).desc); } return true; } @Mapping(provides="net/minecraft/util/MovingObjectPosition$MovingObjectType", providesFields={ "net/minecraft/util/MovingObjectPosition blockPos Lnet/minecraft/util/BlockPos;", "net/minecraft/util/MovingObjectPosition sideHit Lnet/minecraft/util/EnumFacing;", "net/minecraft/util/MovingObjectPosition hitVec Lnet/minecraft/util/Vec3;", "net/minecraft/util/MovingObjectPosition entityHit Lnet/minecraft/entity/Entity;", "net/minecraft/util/MovingObjectPosition typeOfHit Lnet/minecraft/util/MovingObjectPosition$MovingObjectType;", "net/minecraft/util/MovingObjectPosition$MovingObjectType MISS Lnet/minecraft/util/MovingObjectPosition$MovingObjectType;", "net/minecraft/util/MovingObjectPosition$MovingObjectType BLOCK Lnet/minecraft/util/MovingObjectPosition$MovingObjectType;", "net/minecraft/util/MovingObjectPosition$MovingObjectType ENTITY Lnet/minecraft/util/MovingObjectPosition$MovingObjectType;" }, providesMethods={ "net/minecraft/util/MovingObjectPosition getBlockPos ()Lnet/minecraft/util/BlockPos;" }, depends={ "net/minecraft/util/MovingObjectPosition", "net/minecraft/entity/Entity", "net/minecraft/util/BlockPos", "net/minecraft/util/EnumFacing", "net/minecraft/util/Vec3" }) public boolean processMovingObjectPositionClass() { ClassNode mop = getClassNodeFromMapping("net/minecraft/util/MovingObjectPosition"); ClassNode entity = getClassNodeFromMapping("net/minecraft/entity/Entity"); ClassNode blockPos = getClassNodeFromMapping("net/minecraft/util/BlockPos"); ClassNode enumFacing = getClassNodeFromMapping("net/minecraft/util/EnumFacing"); ClassNode vec3 = getClassNodeFromMapping("net/minecraft/util/Vec3"); if (!MeddleUtil.notNull(mop, entity, blockPos, enumFacing, vec3)) return false; List<FieldNode> fields = getMatchingFields(mop, null, "L" + blockPos.name + ";"); if (fields.size() == 1) { addFieldMapping("net/minecraft/util/MovingObjectPosition blockPos Lnet/minecraft/util/BlockPos;", mop.name + " " + fields.get(0).name + " " + fields.get(0).desc); } fields = getMatchingFields(mop, null, "L" + enumFacing.name + ";"); if (fields.size() == 1) { addFieldMapping("net/minecraft/util/MovingObjectPosition sideHit Lnet/minecraft/util/EnumFacing;", mop.name + " " + fields.get(0).name + " " + fields.get(0).desc); } fields = getMatchingFields(mop, null, "L" + vec3.name + ";"); if (fields.size() == 1) { addFieldMapping("net/minecraft/util/MovingObjectPosition hitVec Lnet/minecraft/util/Vec3;", mop.name + " " + fields.get(0).name + " " + fields.get(0).desc); } fields = getMatchingFields(mop, null, "L" + entity.name + ";"); if (fields.size() == 1) { addFieldMapping("net/minecraft/util/MovingObjectPosition entityHit Lnet/minecraft/entity/Entity;", mop.name + " " + fields.get(0).name + " " + fields.get(0).desc); } fields = getMatchingFields(mop, null, null); for (Iterator<FieldNode> it = fields.iterator(); it.hasNext();) { FieldNode fn = it.next(); Type t = Type.getType(fn.desc); if (t.getSort() != Type.OBJECT) { it.remove(); continue; } String className = t.getClassName(); if (className.equals(entity.name) || className.equals(vec3.name) || className.equals(enumFacing.name) || className.equals(blockPos.name)) it.remove(); } if (fields.size() == 1) { String className = Type.getType(fields.get(0).desc).getClassName(); if (searchConstantPoolForStrings(className, "MISS", "BLOCK", "ENTITY")) { addClassMapping("net/minecraft/util/MovingObjectPosition$MovingObjectType", className); addFieldMapping("net/minecraft/util/MovingObjectPosition typeOfHit Lnet/minecraft/util/MovingObjectPosition$MovingObjectType;", mop.name + " " + fields.get(0).name + " " + fields.get(0).desc); // Map $MovingObjectType's fields while we're at it ClassNode mot = getClassNode(className); if (mot != null) { Map<String, FieldInsnNode> enumFields = extractEnumFieldsWithNames(mot); for (String key : enumFields.keySet()) { if (key.equals("MISS") || key.equals("BLOCK") || key.equals("ENTITY")) addFieldMapping("net/minecraft/util/MovingObjectPosition$MovingObjectType " + key + " Lnet/minecraft/util/MovingObjectPosition$MovingObjectType;", mot.name + " " + enumFields.get(key).name + " L" + mot.name + ";"); } } } } // public BlockPos getBlockPos() List<MethodNode> methods = getMatchingMethods(mop, null, "()L" + blockPos.name + ";"); if (methods.size() == 1) { addMethodMapping("net/minecraft/util/MovingObjectPosition getBlockPos ()Lnet/minecraft/util/BlockPos;", mop.name + " " + methods.get(0).name + " " + methods.get(0).desc); } // TODO - Get Entity.xPos, yPos, zPos from constructor return true; } @Mapping(providesMethods={ "net/minecraft/block/Block hasComparatorInputOverride (Lnet/minecraft/block/state/IBlockState;)Z" }, depends={ "net/minecraft/block/Block", "net/minecraft/block/BlockCommandBlock", "net/minecraft/block/state/IBlockState" }) public boolean processBlockCommandBlockClass() { ClassNode block = getClassNodeFromMapping("net/minecraft/block/Block"); ClassNode commandBlock = getClassNodeFromMapping("net/minecraft/block/BlockCommandBlock"); ClassNode iBlockState = getClassNodeFromMapping("net/minecraft/block/state/IBlockState"); if (!MeddleUtil.notNull(block, commandBlock, iBlockState)) return false; List<MethodNode> methods = getMatchingMethods(commandBlock, null, "(L" + iBlockState.name + ";)Z"); if (methods.size() == 1) { addMethodMapping("net/minecraft/block/Block hasComparatorInputOverride (Lnet/minecraft/block/state/IBlockState;)Z", block.name + " " + methods.get(0).name + " " + methods.get(0).desc); } return true; } @Mapping(provides="net/minecraft/block/BlockBasePressurePlate", depends={ "net/minecraft/block/Block", "net/minecraft/block/BlockPressurePlate" }) public boolean getBlockPressurePlateClass() { ClassNode block = getClassNodeFromMapping("net/minecraft/block/Block"); ClassNode pressurePlate = getClassNodeFromMapping("net/minecraft/block/BlockPressurePlate"); if (!MeddleUtil.notNull(block, pressurePlate)) return false; ClassNode pressurePlateBase = getClassNode(pressurePlate.superName); if (!block.name.equals(pressurePlateBase.superName)) return false; addClassMapping("net/minecraft/block/BlockBasePressurePlate", pressurePlateBase); return true; } @Mapping(provides="net/minecraft/block/BlockRailBase", depends={ "net/minecraft/block/Block", "net/minecraft/block/BlockRail", "net/minecraft/block/BlockRailPowered" }) public boolean getBlockRailClass() { ClassNode block = getClassNodeFromMapping("net/minecraft/block/Block"); ClassNode rail = getClassNodeFromMapping("net/minecraft/block/BlockRail"); ClassNode railPowered = getClassNodeFromMapping("net/minecraft/block/BlockRailPowered"); if (!MeddleUtil.notNull(block, rail, railPowered)) return false; if (!rail.superName.equals(railPowered.superName)) return false; ClassNode railBase = getClassNode(rail.superName); if (!block.name.equals(railBase.superName)) return false; addClassMapping("net/minecraft/block/BlockRailBase", railBase); return true; } @Mapping(provides="net/minecraft/block/BlockButton", depends={ "net/minecraft/block/BlockButtonStone", "net/minecraft/block/BlockButtonWood" }) public boolean getBlockButtonClass() { ClassNode buttonStone = getClassNodeFromMapping("net/minecraft/block/BlockButtonStone"); ClassNode buttonWood = getClassNodeFromMapping("net/minecraft/block/BlockButtonWood"); if (!MeddleUtil.notNull(buttonStone, buttonWood)) return false; if (!buttonStone.superName.equals(buttonWood.superName)) return false; if (!searchConstantPoolForStrings(buttonStone.superName, "powered")) return false; addClassMapping("net/minecraft/block/BlockButton", buttonStone.superName); return true; } @Mapping(provides="net/minecraft/block/BlockRedstoneDiode", depends={ "net/minecraft/block/BlockDirectional", "net/minecraft/block/BlockRedstoneRepeater", "net/minecraft/block/BlockRedstoneComparator" }) public boolean getBlockRedstoneDiodeClass() { ClassNode directional = getClassNodeFromMapping("net/minecraft/block/BlockDirectional"); ClassNode repeater = getClassNodeFromMapping("net/minecraft/block/BlockRedstoneRepeater"); ClassNode comparator = getClassNodeFromMapping("net/minecraft/block/BlockRedstoneComparator"); if (!MeddleUtil.notNull(directional, repeater, comparator)) return false; if (!repeater.superName.equals(comparator.superName)) return false; ClassNode diode = getClassNode(repeater.superName); if (!directional.name.equals(diode.superName)) return false; addClassMapping("net/minecraft/block/BlockRedstoneDiode", diode); return true; } @Mapping(provides="net/minecraft/block/BlockFalling", depends={ "net/minecraft/block/Block", "net/minecraft/block/BlockSand", "net/minecraft/block/BlockGravel" }) public boolean getBlockFallingClass() { ClassNode block = getClassNodeFromMapping("net/minecraft/block/Block"); ClassNode sand = getClassNodeFromMapping("net/minecraft/block/BlockSand"); ClassNode gravel = getClassNodeFromMapping("net/minecraft/block/BlockGravel"); if (!MeddleUtil.notNull(block, sand, gravel)) return false; if (!sand.superName.equals(gravel.superName)) return false; ClassNode falling = getClassNode(sand.superName); if (!block.name.equals(falling.superName)) return false; addClassMapping("net/minecraft/block/BlockFalling", falling); return true; } @Mapping(provides="net/minecraft/block/BlockFlower", depends={ "net/minecraft/block/BlockBush", "net/minecraft/block/BlockYellowFlower", "net/minecraft/block/BlockRedFlower" }) public boolean getBlockFlowerClass() { ClassNode bush = getClassNodeFromMapping("net/minecraft/block/BlockBush"); ClassNode yellowFlower = getClassNodeFromMapping("net/minecraft/block/BlockYellowFlower"); ClassNode redFlower = getClassNodeFromMapping("net/minecraft/block/BlockRedFlower"); if (!MeddleUtil.notNull(bush, yellowFlower, redFlower)) return false; if (!yellowFlower.superName.equals(redFlower.superName)) return false; ClassNode flower = getClassNode(yellowFlower.superName); if (!bush.name.equals(flower.superName)) return false; addClassMapping("net/minecraft/block/BlockFlower", flower); return true; } @Mapping(provides="net/minecraft/block/BlockBreakable", depends={ "net/minecraft/block/Block", "net/minecraft/block/BlockGlass", "net/minecraft/block/BlockIce" }) public boolean getBlockBreakableClass() { ClassNode block = getClassNodeFromMapping("net/minecraft/block/Block"); ClassNode glass = getClassNodeFromMapping("net/minecraft/block/BlockGlass"); ClassNode ice = getClassNodeFromMapping("net/minecraft/block/BlockIce"); if (!MeddleUtil.notNull(block, glass, ice)) return false; if (!glass.superName.equals(ice.superName)) return false; ClassNode flower = getClassNode(glass.superName); if (!block.name.equals(flower.superName)) return false; addClassMapping("net/minecraft/block/BlockBreakable", flower); return true; } @Mapping(provides="net/minecraft/block/BlockSign", depends={ "net/minecraft/block/BlockContainer", "net/minecraft/block/BlockStandingSign", "net/minecraft/block/BlockWallSign" }) public boolean getBlockSignClass() { ClassNode container = getClassNodeFromMapping("net/minecraft/block/BlockContainer"); ClassNode standingSign = getClassNodeFromMapping("net/minecraft/block/BlockStandingSign"); ClassNode wallSign = getClassNodeFromMapping("net/minecraft/block/BlockWallSign"); if (!MeddleUtil.notNull(container, standingSign, wallSign)) return false; if (!standingSign.superName.equals(wallSign.superName)) return false; ClassNode sign = getClassNode(standingSign.superName); if (!container.name.equals(sign.superName)) return false; addClassMapping("net/minecraft/block/BlockSign", sign); return true; } @Mapping(providesFields={ "net/minecraft/util/SoundCategory MASTER Lnet/minecraft/util/SoundCategory;", "net/minecraft/util/SoundCategory MUSIC Lnet/minecraft/util/SoundCategory;", "net/minecraft/util/SoundCategory RECORDS Lnet/minecraft/util/SoundCategory;", "net/minecraft/util/SoundCategory WEATHER Lnet/minecraft/util/SoundCategory;", "net/minecraft/util/SoundCategory BLOCKS Lnet/minecraft/util/SoundCategory;", "net/minecraft/util/SoundCategory HOSTILE Lnet/minecraft/util/SoundCategory;", "net/minecraft/util/SoundCategory NEUTRAL Lnet/minecraft/util/SoundCategory;", "net/minecraft/util/SoundCategory PLAYERS Lnet/minecraft/util/SoundCategory;", "net/minecraft/util/SoundCategory AMBIENT Lnet/minecraft/util/SoundCategory;", "net/minecraft/util/SoundCategory VOICE Lnet/minecraft/util/SoundCategory;" }, depends={ "net/minecraft/util/SoundCategory" }) public boolean processSoundCategoryClass() { ClassNode soundCategory = getClassNodeFromMapping("net/minecraft/util/SoundCategory"); if (!MeddleUtil.notNull(soundCategory)) return false; String[] enumNames = new String[] { "MASTER", "MUSIC", "RECORDS", "WEATHER", "BLOCKS", "HOSTILE", "NEUTRAL", "PLAYERS", "AMBIENT", "VOICE" }; MethodNode clinit = getMethodNode(soundCategory, "--- <clinit> ()V"); if (clinit == null) return false; String lastString = null; Map<String, String> fields = new HashMap<>(); for (AbstractInsnNode insn = clinit.instructions.getFirst(); insn != null; insn = insn.getNext()) { String s = getLdcString(insn); if (s != null && lastString == null) { lastString = s; continue; } if (insn.getOpcode() == Opcodes.PUTSTATIC && lastString != null) { FieldInsnNode fn = (FieldInsnNode)insn; if (fn.owner.equals(soundCategory.name) && fn.desc.equals("L" + soundCategory.name + ";")) fields.put(lastString, fn.name); lastString = null; } } if (enumNames.length == fields.size()) { for (String enumName : enumNames) { String fieldName = fields.get(enumName); if (fieldName == null) continue; addFieldMapping("net/minecraft/util/SoundCategory " + enumName + " Lnet/minecraft/util/SoundCategory;", soundCategory.name + " " + fieldName + " L" + soundCategory.name + ";"); } } return true; } @Mapping(provides = { "net/minecraft/item/Item$ToolMaterial" }, providesFields = { "net/minecraft/item/Item$ToolMaterial WOOD Lnet/minecraft/item/Item$ToolMaterial", "net/minecraft/item/Item$ToolMaterial STONE Lnet/minecraft/item/Item$ToolMaterial", "net/minecraft/item/Item$ToolMaterial IRON Lnet/minecraft/item/Item$ToolMaterial", "net/minecraft/item/Item$ToolMaterial DIAMOND Lnet/minecraft/item/Item$ToolMaterial", "net/minecraft/item/Item$ToolMaterial GOLD Lnet/minecraft/item/Item$ToolMaterial" }, depends = { "net/minecraft/item/ItemTool" }) public boolean processToolMaterial(){ ClassNode item = getClassNodeFromMapping("net/minecraft/item/ItemTool"); List<FieldNode> fields = new ArrayList<>(); for(FieldNode field : item.fields){ if(!Objects.equals(field.desc, "F") && !Objects.equals(field.desc, "Ljava/util/Set;")){ fields.add(field); } } if(fields.size() == 1){ addClassMapping("net/minecraft/item/Item$ToolMaterial", Type.getType(fields.get(0).desc).getClassName()); } ClassNode toolmaterial = getClassNodeFromMapping("net/minecraft/item/Item$ToolMaterial"); String[] names = {"WOOD", "STONE", "IRON", "DIAMOND", "GOLD"}; List<FieldNode> matchingFields = getMatchingFields(toolmaterial, null, assembleDescriptor(toolmaterial)); for(int i = 0; i < matchingFields.size(); i++){ FieldNode field = matchingFields.get(i); addFieldMapping("net/minecraft/item/Item$ToolMaterial " + names[i] +" Lnet/minecraft/item/Item$ToolMaterial", toolmaterial.name + " " + field.name + " " + field.desc); } return true; } @Mapping(providesMethods={ "net/minecraft/world/World notifyNeighborsOfStateChange (Lnet/minecraft/util/BlockPos;Lnet/minecraft/block/Block;)V" }, depends={ "net/minecraft/block/BlockBasePressurePlate", "net/minecraft/world/World", "net/minecraft/util/BlockPos", "net/minecraft/block/Block" }) public boolean processBlockBasePressurePlate() { ClassNode basePressurePlate = getClassNodeFromMapping("net/minecraft/block/BlockBasePressurePlate"); ClassNode world = getClassNodeFromMapping("net/minecraft/world/World"); ClassNode blockPos = getClassNodeFromMapping("net/minecraft/util/BlockPos"); ClassNode block = getClassNodeFromMapping("net/minecraft/block/Block"); if (!MeddleUtil.notNull(basePressurePlate, world, blockPos, block)) return false; // public void World.notifyNeighborsOfStateChange(BlockPos pos, Block blockType) // Find in updateNeighbors(World, BlockPos) List<MethodNode> methods = getMatchingMethods(basePressurePlate, null, assembleDescriptor("(", world, blockPos, ")V")); methods = removeMethodsWithFlags(methods, Opcodes.ACC_ABSTRACT); if (methods.size() == 1) { List<MethodInsnNode> mnodes = getAllInsnNodesOfType(methods.get(0), MethodInsnNode.class); mnodes = filterMethodInsnNodes(mnodes, world.name, assembleDescriptor("(", blockPos, block, ")V")); if (mnodes.size() == 2 && mnodes.get(0).name.equals(mnodes.get(1).name)) { addMethodMapping("net/minecraft/world/World notifyNeighborsOfStateChange (Lnet/minecraft/util/BlockPos;Lnet/minecraft/block/Block;)V", world.name + " " + mnodes.get(0).name + " " + mnodes.get(0).desc); } } // TODO - get getWeakPower and getStrongPower return true; } }