package immibis.bon.cui; import immibis.bon.ClassCollection; import immibis.bon.ReferenceDataCollection; import immibis.bon.Remapper; import immibis.bon.io.ClassCollectionFactory; import immibis.bon.io.JarWriter; import immibis.bon.mcp.MappingFactory; import immibis.bon.mcp.MappingLoader_MCP; import immibis.bon.mcp.MinecraftNameSet; import java.io.File; import java.util.ArrayList; import java.util.Collections; import java.util.List; public class MCPRemap extends CUIBase { private static class Timer { private long start; public Timer() {start = System.currentTimeMillis();} public int flip() { int rv = (int)(System.currentTimeMillis() - start); start = System.currentTimeMillis(); return rv; } } @Override protected void run() throws Exception { Timer timer = new Timer(); int readTime = 0, remapTime = 0, writeTime = 0; System.out.println("Loading MCP configuration"); String mcVer = MappingLoader_MCP.getMCVer(mcpDir); MappingFactory.registerMCPInstance(mcVer, side, mcpDir, null); readTime += timer.flip(); MinecraftNameSet inputNS = new MinecraftNameSet(fromType, side, mcVer); MinecraftNameSet outputNS = new MinecraftNameSet(toType, side, mcVer); List<ReferenceDataCollection> refs = new ArrayList<>(); for(RefOption ro : refOptsParsed) { MinecraftNameSet refNS = new MinecraftNameSet(ro.type, side, mcVer); System.out.println("Loading "+ro.file); ClassCollection refCC = ClassCollectionFactory.loadClassCollection(refNS, ro.file, null); readTime += timer.flip(); if(!refNS.equals(inputNS)) { System.out.println("Remapping "+ro.file+" ("+refNS+" -> "+inputNS+")"); refCC = Remapper.remap(refCC, MappingFactory.getMapping((MinecraftNameSet)refCC.getNameSet(), inputNS, null), Collections.<ReferenceDataCollection>emptyList(), null); remapTime += timer.flip(); } refs.add(ReferenceDataCollection.fromClassCollection(refCC)); } System.out.println("Loading "+inFile); ClassCollection inputCC = ClassCollectionFactory.loadClassCollection(inputNS, inFile, null); readTime += timer.flip(); System.out.println("Remapping "+inFile+" ("+inputNS+" -> "+outputNS+")"); ClassCollection outputCC = Remapper.remap(inputCC, MappingFactory.getMapping((MinecraftNameSet)inputCC.getNameSet(), outputNS, null), refs, null); remapTime += timer.flip(); System.out.println("Writing "+outFile); JarWriter.write(outFile, outputCC, null); writeTime += timer.flip(); //System.out.printf("Completed in %dms (%dms read, %dms remap, %dms write)\n", readTime+remapTime+writeTime, readTime, remapTime, writeTime); System.out.printf("Completed in %d ms\n", readTime + remapTime + writeTime); } @Required @Option("-mcp") public File mcpDir; @Required @Option("-from") public MinecraftNameSet.Type fromType; @Required @Option("-to") public MinecraftNameSet.Type toType; @Required @Option("-side") public MinecraftNameSet.Side side; @Required @Option("-in") public File inFile; @Required @Option("-out") public File outFile; @Option("-ref") public List<String> refOpts = new ArrayList<>(); @Option("-refn") public List<String> refnOpts = new ArrayList<>(); private static class RefOption { public MinecraftNameSet.Type type; public File file; public RefOption(MinecraftNameSet.Type t, File f) { type = t; file = f; } } private List<RefOption> refOptsParsed = new ArrayList<>(); @Override protected boolean checkOptions() throws Exception { if(!super.checkOptions()) return false; boolean ok = true; if(!inFile.exists()) { System.err.println("Input file doesn't exist: " + inFile.getAbsolutePath()); ok = false; } if(outFile.isDirectory()) { System.err.println("Output file already exists and is a directory: " + outFile.getAbsolutePath()); ok = false; } if(!mcpDir.exists()) { System.err.println("MCP directory doesn't exist: " + mcpDir.getAbsolutePath()); ok = false; } for(String s : refOpts) { refOptsParsed.add(new RefOption(fromType, new File(s))); } for(String s : refnOpts) { String[] p = s.split(":", 2); if(p.length != 2) { System.err.println("Missing : in -refn option: " + s); ok = false; } else { try { refOptsParsed.add(new RefOption(MinecraftNameSet.Type.valueOf(p[0]), new File(p[1]))); } catch(EnumConstantNotPresentException e) { System.err.println("Invalid name type: " + p[0]); ok = false; } } } for(RefOption ro : refOptsParsed) { if(!ro.file.exists()) { System.err.println("Reference file doesn't exist: " + ro.file.getAbsolutePath()); ok = false; } } return ok; } @Override protected void showUsage() { System.out.println("Usage:"); System.out.println(" java -cp BON.jar immibis.bon.cui.MCPRemap <option>..."); System.out.println(""); System.out.println("Required options:"); System.out.println(" -mcp <mcp dir>"); System.out.println(" Specifies the path to the MCP directory."); System.out.println(" -from <source names>"); System.out.println(" Specifies the type of names the input file will uses."); System.out.println(" Can be OBF or SRG or MCP."); System.out.println(" -to <target names>"); System.out.println(" Specifies the type of names the output file will use."); System.out.println(" Can be OBF or SRG or MCP."); System.out.println(" -side <side>"); System.out.println(" Can be UNIVERSAL, CLIENT or SERVER."); System.out.println(" -in <input file>"); System.out.println(" Specifies the path to the input file"); System.out.println(" -out <output file>"); System.out.println(" Specifies the path to the output file"); System.out.println(""); System.out.println("Optional options:"); System.out.println(" -ref <reference file>"); System.out.println(" Specifies the path to a jar file or directory which the input code depends on."); System.out.println(" This is hard to describe exactly, but you will want to specify MCP/bin/minecraft"); System.out.println(" as well as any mods your mod depends on (e.g. RedPowerCore when processing"); System.out.println(" RedPowerDigital). You can use this option several times with different files."); System.out.println(" The file must be using the same names specified in <source names>. See -refn."); System.out.println(""); System.out.println(" -refn <names>:<reference file>"); System.out.println(" Same as -ref, but the reference file can be using obfuscated, SRG or MCP names."); System.out.println(" If <names> is different from <source names>, the file will be remapped automatically,"); System.out.println(" which will take slightly longer than if the file was already remapped."); System.out.println(""); System.out.println("Example command line:"); System.out.println(" -mcp . -from OBF -to MCP -side UNIVERSAL -in RedPowerDigital.zip -out RedPowerDigital-deobf.zip -ref RedPowerCore.zip -refn MCP:bin/minecraft"); System.out.println(" Deobfuscates RedPowerDigital.zip, saving the result in RedPowerDigital-deobf.zip."); System.out.println(" The current directory contains an MCP installation. RedPowerCore.zip (which is obfuscated)"); System.out.println(" and bin/minecraft (which is not) will also be loaded."); System.out.println(""); System.out.println(" -mcp . -from MCP -to OBF -side UNIVERSAL -in AwesomeMod.jar -out AwesomeMod-obf.jar -ref bin/minecraft"); System.out.println(" Obfuscates AwesomeMod.jar, saving the result in AwesomeMod-obf.jar."); System.out.println(" The current directory contains an MCP installation."); System.out.println(""); System.out.println("Note: If deobfuscating, you need to know if the input file is using SRG or OBF names."); System.out.println("The GUI gets around this by remapping twice, once with '-from OBF -to SRG', and then with '-from SRG -to MCP',"); System.out.println("which is slower."); System.out.println(""); System.out.println("Note: Automatic remapping of reference files may not work correctly if the reference file itself needs"); System.out.println("reference files to remap correctly. (E.g. if RPDigital.zip requires RPCore.zip which requires bin/minecraft)"); System.out.println("In this case you will need to ensure the reference files do not need remapping."); System.out.println("A reference file could be the output of a previous command."); System.out.println(""); } public static void main(String[] args) throws Exception { new MCPRemap().run(args); } }