diff --git a/build.gradle b/build.gradle index cc2809c69..750f24fdd 100644 --- a/build.gradle +++ b/build.gradle @@ -74,9 +74,9 @@ dependencies { compile 'com.nothome:javaxdelta:2.0.1' // GDIFF implementation for BinPatches compile 'com.google.code.gson:gson:2.2.4' // Used instead of Argo for buuilding changelog. compile 'com.github.tony19:named-regexp:0.2.3' // 1.7 Named regexp features - compile 'net.minecraftforge:forgeflower:1.0.342-SNAPSHOT' // Fernflower Forge edition + compile 'net.minecraftforge:forgeflower:1.5.380.22' // Fernflower Forge edition - shade 'net.md-5:SpecialSource:1.8.2' // deobf and reobf + shade 'net.md-5:SpecialSource:1.8.3' // deobf and reobf // because curse compile 'org.apache.httpcomponents:httpclient:4.3.3' @@ -84,7 +84,7 @@ dependencies { // mcp stuff shade 'de.oceanlabs.mcp:RetroGuard:3.6.6' - shade('de.oceanlabs.mcp:mcinjector:3.4-SNAPSHOT'){ + shade('de.oceanlabs.mcp:mcinjector:3.7.3'){ exclude group: 'org.ow2.asm', module: 'asm-debug-all' } shade('net.minecraftforge.srg2source:Srg2Source:4.0-SNAPSHOT'){ @@ -94,7 +94,7 @@ dependencies { //Stuff used in the GradleStart classes compileOnly 'com.mojang:authlib:1.5.16' - compileOnly('net.minecraft:launchwrapper:1.11'){ + compileOnly('net.minecraft:launchwrapper:1.12'){ exclude group: 'org.ow2.asm', module: 'asm-debug-all' } @@ -214,7 +214,7 @@ pluginBundle { uploadArchives { repositories.mavenDeployer { - dependsOn 'build' + dependsOn 'jar' if (project.hasProperty('forgeMavenPass')) { diff --git a/src/main/java/net/minecraftforge/gradle/common/BasePlugin.java b/src/main/java/net/minecraftforge/gradle/common/BasePlugin.java index 461ef6994..785e9ca3a 100644 --- a/src/main/java/net/minecraftforge/gradle/common/BasePlugin.java +++ b/src/main/java/net/minecraftforge/gradle/common/BasePlugin.java @@ -223,7 +223,7 @@ protected void afterEvaluate() // ApplyFernFlowerTask ffTask = ((ApplyFernFlowerTask) project.getTasks().getByName("decompileJar")); // ffTask.setClasspath(javaConv.getSourceSets().getByName("main").getCompileClasspath()); - // http://files.minecraftforge.net/maven/de/oceanlabs/mcp/mcp/1.7.10/mcp-1.7.10-srg.zip + // http://files.minecraftforge.net/maven/de/oceanlabs/mcp/mcp_config/1.13.1/mcp_config-1.13.1.zip project.getDependencies().add(CONFIG_MAPPINGS, ImmutableMap.of( "group", "de.oceanlabs.mcp", "name", delayedString("mcp_" + REPLACE_MCP_CHANNEL).call(), @@ -233,9 +233,8 @@ protected void afterEvaluate() project.getDependencies().add(CONFIG_MCP_DATA, ImmutableMap.of( "group", "de.oceanlabs.mcp", - "name", "mcp", + "name", "mcp_config", "version", delayedString(REPLACE_MC_VERSION).call(), - "classifier", "srg", "ext", "zip" )); @@ -523,7 +522,7 @@ public String call() merge.setDescription(null); } - ExtractConfigTask extractMcpData = makeTask(TASK_EXTRACT_MCP, ExtractConfigTask.class); + ExtractConfigTask extractMcpData = makeTask(TASK_EXTRACT_MCP, ExtractMcpConfigTask.class); { extractMcpData.setDestinationDir(delayedFile(DIR_MCP_DATA)); extractMcpData.setConfig(CONFIG_MCP_DATA); @@ -540,7 +539,7 @@ public String call() GenSrgs genSrgs = makeTask(TASK_GENERATE_SRGS, GenSrgs.class); { genSrgs.setInSrg(delayedFile(MCP_DATA_SRG)); - genSrgs.setInExc(delayedFile(MCP_DATA_EXC)); + genSrgs.setInConstructors(delayedFile(MCP_DATA_CONSTRUCTORS)); genSrgs.setInStatics(delayedFile(MCP_DATA_STATICS)); genSrgs.setMethodsCsv(delayedFile(CSV_METHOD)); genSrgs.setFieldsCsv(delayedFile(CSV_FIELD)); diff --git a/src/main/java/net/minecraftforge/gradle/common/Constants.java b/src/main/java/net/minecraftforge/gradle/common/Constants.java index 18047ddae..2d989792c 100644 --- a/src/main/java/net/minecraftforge/gradle/common/Constants.java +++ b/src/main/java/net/minecraftforge/gradle/common/Constants.java @@ -169,15 +169,16 @@ public Boolean call(Object o) }; // mcp data constants - public static final String MCP_DATA_SRG = DIR_MCP_DATA + "/joined.srg"; - public static final String MCP_DATA_EXC = DIR_MCP_DATA + "/joined.exc"; - public static final String MCP_DATA_EXC_JSON = DIR_MCP_DATA + "/exceptor.json"; - public static final String MCP_DATA_STYLE = DIR_MCP_DATA + "/astyle.cfg"; - public static final String MCP_DATA_STATICS = DIR_MCP_DATA + "/static_methods.txt"; - public static final String MCP_PATCHES_CLIENT = DIR_MCP_DATA + "/patches/minecraft_ff"; - public static final String MCP_PATCHES_SERVER = DIR_MCP_DATA + "/patches/minecraft_server_ff"; - public static final String MCP_PATCHES_MERGED = DIR_MCP_DATA + "/patches/minecraft_merged_ff"; - public static final String MCP_INJECT = DIR_MCP_DATA + "/patches/inject"; + public static final String MCP_DATA_SRG = DIR_MCP_DATA + "/config/joined.srg"; + public static final String MCP_DATA_STYLE = DIR_MCP_DATA + "/astyle.cfg"; + public static final String MCP_DATA_ACCESS = DIR_MCP_DATA + "/config/access.txt"; + public static final String MCP_DATA_EXCEPTIONS = DIR_MCP_DATA + "/config/exceptions.txt"; + public static final String MCP_DATA_CONSTRUCTORS = DIR_MCP_DATA + "/config/constructors.txt"; + public static final String MCP_DATA_STATICS = DIR_MCP_DATA + "/config/static_methods.txt"; + public static final String MCP_PATCHES_CLIENT = DIR_MCP_DATA + "/patches/client"; + public static final String MCP_PATCHES_SERVER = DIR_MCP_DATA + "/patches/server"; + public static final String MCP_PATCHES_MERGED = DIR_MCP_DATA + "/patches/joined"; + public static final String MCP_INJECT = DIR_MCP_DATA + "/config/inject"; // generated off of MCP data constants public static final String CSV_METHOD = DIR_MCP_MAPPINGS + "/methods.csv"; diff --git a/src/main/java/net/minecraftforge/gradle/patcher/PatcherPlugin.java b/src/main/java/net/minecraftforge/gradle/patcher/PatcherPlugin.java index 00bd512dc..a87107d75 100644 --- a/src/main/java/net/minecraftforge/gradle/patcher/PatcherPlugin.java +++ b/src/main/java/net/minecraftforge/gradle/patcher/PatcherPlugin.java @@ -112,8 +112,9 @@ protected void makeGeneralSetupTasks() deobfJar.setOutJar(delayedFile(JAR_DEOBF)); deobfJar.setSrg(delayedFile(SRG_NOTCH_TO_SRG)); deobfJar.setExceptorCfg(delayedFile(EXC_SRG)); - deobfJar.setExceptorJson(delayedFile(MCP_DATA_EXC_JSON)); - deobfJar.setApplyMarkers(true); + deobfJar.setAccessCfg(delayedFile(MCP_DATA_ACCESS)); + deobfJar.setConstructorCfg(delayedFile(MCP_DATA_CONSTRUCTORS)); + deobfJar.setExceptionsCfg(delayedFile(MCP_DATA_EXCEPTIONS)); deobfJar.setDoesCache(false); // access transformers are added afterEvaluate deobfJar.dependsOn(TASK_MERGE_JARS, TASK_GENERATE_SRGS); diff --git a/src/main/java/net/minecraftforge/gradle/tasks/DeobfuscateJar.java b/src/main/java/net/minecraftforge/gradle/tasks/DeobfuscateJar.java index 4971da3bb..2f6bdde1c 100644 --- a/src/main/java/net/minecraftforge/gradle/tasks/DeobfuscateJar.java +++ b/src/main/java/net/minecraftforge/gradle/tasks/DeobfuscateJar.java @@ -25,30 +25,32 @@ import com.google.common.collect.Maps; import com.google.common.io.Files; import com.google.common.io.LineProcessor; -import de.oceanlabs.mcp.mcinjector.LVTNaming; -import de.oceanlabs.mcp.mcinjector.MCInjectorImpl; + +import de.oceanlabs.mcp.mcinjector.lvt.LVTNaming; +import de.oceanlabs.mcp.mcinjector.MCInjector; + import groovy.lang.Closure; + import net.md_5.specialsource.*; import net.md_5.specialsource.provider.JarProvider; import net.md_5.specialsource.provider.JointProvider; + import net.minecraftforge.gradle.common.Constants; import net.minecraftforge.gradle.util.caching.Cached; import net.minecraftforge.gradle.util.caching.CachedTask; -import net.minecraftforge.gradle.util.json.JsonFactory; -import net.minecraftforge.gradle.util.json.MCInjectorStruct; -import net.minecraftforge.gradle.util.json.MCInjectorStruct.InnerClass; + import org.gradle.api.file.FileCollection; import org.gradle.api.tasks.*; -import org.gradle.api.tasks.Optional; import java.io.BufferedReader; import java.io.File; import java.io.IOException; -import java.nio.charset.Charset; -import java.util.*; -import java.util.zip.ZipFile; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; -import static org.objectweb.asm.Opcodes.*; public class DeobfuscateJar extends CachedTask { @@ -69,10 +71,13 @@ public class DeobfuscateJar extends CachedTask private Object exceptorCfg; @InputFile - private Object exceptorJson; - - @Input - private boolean applyMarkers = false; + private Object access; + + @InputFile + private Object constructors; + + @InputFile + private Object exceptions; @Input private boolean failOnAtError = true; @@ -163,158 +168,22 @@ private void deobfJar(File inJar, File outJar, File srg, Collection ats) t } } - private int fixAccess(int access, String target) - { - int ret = access & ~7; - int t = 0; - - if (target.startsWith("public")) - t = ACC_PUBLIC; - else if (target.startsWith("private")) - t = ACC_PRIVATE; - else if (target.startsWith("protected")) - t = ACC_PROTECTED; - - switch (access & 7) - { - case ACC_PRIVATE: - ret |= t; - break; - case 0: - ret |= (t != ACC_PRIVATE ? t : 0); - break; - case ACC_PROTECTED: - ret |= (t != ACC_PRIVATE && t != 0 ? t : ACC_PROTECTED); - break; - case ACC_PUBLIC: - ret |= ACC_PUBLIC; - break; - } - - if (target.endsWith("-f")) - ret &= ~ACC_FINAL; - else if (target.endsWith("+f")) - ret |= ACC_FINAL; - return ret; - } - public void applyExceptor(File inJar, File outJar, File config, File log, Set ats) throws IOException { - String json = null; - File getJson = getExceptorJson(); - if (getJson != null) - { - final Map struct = JsonFactory.loadMCIJson(getJson); - for (File at : ats) - { - getLogger().info("loading AT: " + at.getCanonicalPath()); - - Files.readLines(at, Charset.defaultCharset(), new LineProcessor() - { - @Override - public boolean processLine(String line) throws IOException - { - if (line.indexOf('#') != -1) - line = line.substring(0, line.indexOf('#')); - line = line.trim().replace('.', '/'); - if (line.isEmpty()) - return true; - - String[] s = line.split(" "); - if (s.length == 2 && s[1].indexOf('$') > 0) - { - String parent = s[1].substring(0, s[1].indexOf('$')); - for (MCInjectorStruct cls : new MCInjectorStruct[] { struct.get(parent), struct.get(s[1]) }) - { - if (cls != null && cls.innerClasses != null) - { - for (InnerClass inner : cls.innerClasses) - { - if (inner.inner_class.equals(s[1])) - { - int access = fixAccess(inner.getAccess(), s[0]); - inner.access = (access == 0 ? null : Integer.toHexString(access)); - } - } - } - } - } - - return true; - } - - @Override - public Object getResult() - { - return null; - } - }); - } - - // Remove unknown classes from configuration - removeUnknownClasses(inJar, struct); - - File jsonTmp = new File(this.getTemporaryDir(), "transformed.json"); - json = jsonTmp.getCanonicalPath(); - Files.write(JsonFactory.GSON.toJson(struct).getBytes(), jsonTmp); - } - getLogger().debug("INPUT: " + inJar); getLogger().debug("OUTPUT: " + outJar); getLogger().debug("CONFIG: " + config); - getLogger().debug("JSON: " + json); + getLogger().debug("ACCESS: " + getAccessCfg()); + getLogger().debug("CONSTRUCTOR: " + getConstructorCfg()); + getLogger().debug("EXCEPTION: " + getExceptionsCfg()); getLogger().debug("LOG: " + log); getLogger().debug("PARAMS: true"); - MCInjectorImpl.process(inJar.getCanonicalPath(), - outJar.getCanonicalPath(), - config.getCanonicalPath(), - log.getCanonicalPath(), - null, - 0, - json, - isApplyMarkers(), - true, - LVTNaming.LVT - ); - } - - private void removeUnknownClasses(File inJar, Map config) throws IOException - { - try (ZipFile zip = new ZipFile(inJar)) - { - Iterator> entries = config.entrySet().iterator(); - while (entries.hasNext()) - { - Map.Entry entry = entries.next(); - String className = entry.getKey(); - - // Verify the configuration contains only classes we actually have - if (zip.getEntry(className + ".class") == null) - { - getLogger().info("Removing unknown class {}", className); - entries.remove(); - continue; - } - - MCInjectorStruct struct = entry.getValue(); - - // Verify the inner classes in the configuration actually exist in our deobfuscated JAR file - if (struct.innerClasses != null) - { - Iterator innerClasses = struct.innerClasses.iterator(); - while (innerClasses.hasNext()) - { - InnerClass innerClass = innerClasses.next(); - if (zip.getEntry(innerClass.inner_class + ".class") == null) - { - getLogger().info("Removing unknown inner class {} from {}", innerClass.inner_class, className); - innerClasses.remove(); - } - } - } - } - } + new MCInjector(inJar.toPath(), outJar.toPath()).log(log.toPath()) + .access(getAccessCfg().toPath()) + .constructors(getConstructorCfg().toPath()) + .exceptions(getExceptionsCfg().toPath()) + .lvt(LVTNaming.LVT).process(); } public File getExceptorCfg() @@ -327,27 +196,28 @@ public void setExceptorCfg(Object exceptorCfg) this.exceptorCfg = exceptorCfg; } - public File getExceptorJson() - { - if (exceptorJson == null) - return null; - else - return getProject().file(exceptorJson); + public File getAccessCfg() { + return getProject().file(access); } - public void setExceptorJson(Object exceptorJson) - { - this.exceptorJson = exceptorJson; + public void setAccessCfg(Object accessCfg) { + access = accessCfg; } - public boolean isApplyMarkers() - { - return applyMarkers; + public File getConstructorCfg() { + return getProject().file(constructors); } - public void setApplyMarkers(boolean applyMarkers) - { - this.applyMarkers = applyMarkers; + public void setConstructorCfg(Object constructorCfg) { + constructors = constructorCfg; + } + + public File getExceptionsCfg() { + return getProject().file(exceptions); + } + + public void setExceptionsCfg(Object exceptionCfg) { + exceptions = exceptionCfg; } public boolean isFailOnAtError() diff --git a/src/main/java/net/minecraftforge/gradle/tasks/ExtractConfigTask.java b/src/main/java/net/minecraftforge/gradle/tasks/ExtractConfigTask.java index abfbec5bf..71badd526 100644 --- a/src/main/java/net/minecraftforge/gradle/tasks/ExtractConfigTask.java +++ b/src/main/java/net/minecraftforge/gradle/tasks/ExtractConfigTask.java @@ -31,6 +31,7 @@ import org.gradle.api.file.FileCollection; import org.gradle.api.file.FileTreeElement; +import org.gradle.api.file.FileVisitor; import org.gradle.api.specs.Spec; import org.gradle.api.tasks.Input; import org.gradle.api.tasks.InputFiles; @@ -72,7 +73,7 @@ public void doTask() throws IOException dest.mkdirs(); - ExtractionVisitor visitor = new ExtractionVisitor(dest, isIncludeEmptyDirs(), patternSet.getAsSpec()); + FileVisitor visitor = makeExtractor(dest, isIncludeEmptyDirs(), patternSet.getAsSpec()); for (File source : getConfigFiles()) { @@ -81,6 +82,10 @@ public void doTask() throws IOException } } + protected FileVisitor makeExtractor(File outDir, boolean emptyDirs, Spec spec) { + return new ExtractionVisitor(outDir, emptyDirs, spec); + } + private void delete(File f) throws IOException { if (f.isDirectory()) diff --git a/src/main/java/net/minecraftforge/gradle/tasks/ExtractMcpConfigTask.java b/src/main/java/net/minecraftforge/gradle/tasks/ExtractMcpConfigTask.java new file mode 100644 index 000000000..e6e6327bb --- /dev/null +++ b/src/main/java/net/minecraftforge/gradle/tasks/ExtractMcpConfigTask.java @@ -0,0 +1,171 @@ +/* + * A Gradle plugin for the creation of Minecraft mods and MinecraftForge plugins. + * Copyright (C) 2013-2018 Minecraft Forge + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ +package net.minecraftforge.gradle.tasks; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.UncheckedIOException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.gradle.api.file.FileTreeElement; +import org.gradle.api.file.FileVisitDetails; +import org.gradle.api.file.FileVisitor; +import org.gradle.api.specs.Spec; + +import net.minecraftforge.gradle.util.ExtractionVisitor; + +public class ExtractMcpConfigTask extends ExtractConfigTask { + public static class Extractor extends ExtractionVisitor { + public Extractor(File outDir, boolean emptyDirs, Spec spec) { + super(outDir, emptyDirs, spec); + } + + @Override + public void visitFile(FileVisitDetails details) { + if (!spec.isSatisfiedBy(details)) return; + + File destination = new File(outputDir, details.getPath()); + destination.getParentFile().mkdirs(); + + switch (details.getRelativePath().toString()) { + case "config.json": + //We don't need the config.json, but at some point we will need an astyle.cfg (which doesn't come in the zip) + //So let's take the opportunity to create one now to save any trouble later + try (BufferedWriter out = new BufferedWriter(new FileWriter(new File(outputDir, "astyle.cfg")))) { + //https://github.com/MinecraftForge/MCPConfig/blob/master/config/astyle.cfg + out.write("style=allman"); + out.newLine(); + out.newLine(); + out.write("add-brackets"); + out.newLine(); + out.write("break-closing-brackets"); + out.newLine(); + out.newLine(); + out.write("indent-switches"); + out.newLine(); + out.newLine(); + out.write("max-instatement-indent=40"); + out.newLine(); + out.newLine(); + out.write("pad-oper"); + out.newLine(); + out.write("pad-header"); + out.newLine(); + out.write("unpad-paren"); + out.newLine(); + out.newLine(); + out.write("break-blocks"); + out.newLine(); + out.newLine(); + out.write("delete-empty-lines"); + out.newLine(); + } catch (IOException e) { + throw new UncheckedIOException("Error writing astyle.cfg" + details.getName(), e); + } + break; + + case "config/joined.tsrg": + //To save anything getting confused with tiny srg, let's convert the mappings into normal srg + try (BufferedReader in = new BufferedReader(new InputStreamReader(details.open())); + BufferedWriter out = new BufferedWriter(new FileWriter(new File(destination.getParentFile(), "joined.srg")))) { + Map classes = new HashMap<>(); + Map methods = new HashMap<>(); + Map fields = new HashMap<>(); + + String currentObf = null; + String currentDeobf = null; + for (String line = in.readLine(); line != null; line = in.readLine()) { + if (line.charAt(0) != '\t') { + String[] parts = line.split(" "); + if (parts.length != 2) + throw new IllegalStateException("Unexpected line split: " + Arrays.toString(parts) + " in " + details.getName()); + + currentObf = parts[0]; + currentDeobf = parts[1]; + classes.put(currentObf, currentDeobf); + } else { + String[] parts = line.substring(1).split(" "); + switch (parts.length) { + case 2: //Field + fields.put(currentObf + '/' + parts[0], currentDeobf + '/' + parts[1]); + break; + + case 3: //Method + methods.put(currentObf + '/' + parts[0] + ' ' + parts[1], currentDeobf + '/' + parts[2]); + break; + + default: + throw new IllegalStateException("Unexpected line split: " + Arrays.toString(parts) + " in " + details.getName()); + } + } + } + + Pattern classFinder = Pattern.compile("L([^;]+);"); + for (Entry entry : methods.entrySet()) { + String obf = entry.getKey(); + String desc = obf.substring(obf.lastIndexOf(' ') + 1); + + StringBuffer buf = new StringBuffer(); + Matcher matcher = classFinder.matcher(desc); + while (matcher.find()) { + matcher.appendReplacement(buf, Matcher.quoteReplacement('L' + classes.getOrDefault(matcher.group(1), matcher.group(1)) + ';')); + } + matcher.appendTail(buf); + + entry.setValue(entry.getValue() + ' ' + buf.toString()); + } + + for (Entry entry : classes.entrySet()) { + out.write("CL: " + entry.getKey() + ' ' + entry.getValue()); + out.newLine(); + } + for (Entry entry : fields.entrySet()) { + out.write("FD: " + entry.getKey() + ' ' + entry.getValue()); + out.newLine(); + } + for (Entry entry : methods.entrySet()) { + out.write("MD: " + entry.getKey() + ' ' + entry.getValue()); + out.newLine(); + } + } catch (IOException e) { + throw new UncheckedIOException("Error converting " + details.getName(), e); + } + break; + + default: + details.copyTo(destination); + } + } + } + + @Override + protected FileVisitor makeExtractor(File outDir, boolean emptyDirs, Spec spec) { + return new Extractor(outDir, emptyDirs, spec); + } +} \ No newline at end of file diff --git a/src/main/java/net/minecraftforge/gradle/tasks/GenSrgs.java b/src/main/java/net/minecraftforge/gradle/tasks/GenSrgs.java index f85df3434..8fac112de 100644 --- a/src/main/java/net/minecraftforge/gradle/tasks/GenSrgs.java +++ b/src/main/java/net/minecraftforge/gradle/tasks/GenSrgs.java @@ -22,6 +22,7 @@ import java.io.BufferedWriter; import java.io.File; import java.io.IOException; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.LinkedList; @@ -57,7 +58,7 @@ public class GenSrgs extends CachedTask { //@formatter:off @InputFile private DelayedFile inSrg; - @InputFile private DelayedFile inExc; + @InputFile private DelayedFile inConstructors; @InputFile private DelayedFile inStatics; @InputFile private DelayedFile methodsCsv; @InputFile private DelayedFile fieldsCsv; @@ -288,7 +289,7 @@ private void writeOutExcs(SrgContainer inSrg, Map excRemap, Map< BufferedWriter mcpOut = Files.newWriter(getMcpExc(), Charsets.UTF_8); // read and write existing lines - List excLines = Files.readLines(getInExc(), Charsets.UTF_8); + List excLines = Files.readLines(getInConstructors(), Charsets.UTF_8); Map tmp = Maps.newHashMap(); for (String line : excLines) { @@ -296,8 +297,21 @@ private void writeOutExcs(SrgContainer inSrg, Map excRemap, Map< tmp.put(line, null); else { - String[] pts = line.split("="); - tmp.put(pts[0], pts[1]); + String[] pts = line.split(" "); + + if (pts.length != 3) + throw new IllegalStateException("Unexpected line length: " + Arrays.toString(pts) + " from " + line); + + String prefix = "p_i" + pts[0] + '_'; + List ret = Lists.newArrayList(); + + int idx = 1; + for (Type arg : Type.getArgumentTypes(pts[2])) { + ret.add(prefix + idx + '_'); + idx += arg.getSize(); + } + + tmp.put(pts[1] + "." + pts[2], '|' + String.join(",", ret)); } } @@ -433,14 +447,14 @@ public void setInSrg(DelayedFile inSrg) this.inSrg = inSrg; } - public File getInExc() + public File getInConstructors() { - return inExc.call(); + return inConstructors.call(); } - public void setInExc(DelayedFile inSrg) + public void setInConstructors(DelayedFile inConstructors) { - this.inExc = inSrg; + this.inConstructors = inConstructors; } public File getInStatics() diff --git a/src/main/java/net/minecraftforge/gradle/tasks/PostDecompileTask.java b/src/main/java/net/minecraftforge/gradle/tasks/PostDecompileTask.java index ffbd94df2..876773f79 100644 --- a/src/main/java/net/minecraftforge/gradle/tasks/PostDecompileTask.java +++ b/src/main/java/net/minecraftforge/gradle/tasks/PostDecompileTask.java @@ -90,9 +90,10 @@ public class PostDecompileTask extends AbstractEditJarTask @Override public void doStuffBefore() throws Exception { + String patchRoot = getProject().file(patchDir).getAbsolutePath(); for (File f : getPatches()) { - String name = f.getName(); + String name = f.getAbsolutePath().substring(patchRoot.length() + 1).replace('\\', '/'); int patchIndex = name.indexOf(".patch"); @@ -126,15 +127,18 @@ public String asRead(String name, String file) throws Exception file = FFPatcher.processFile(file); // patch the file - Collection patchFiles = patchesMap.get(name.replace('/', '.')); + Collection patchFiles = patchesMap.get(name); if (!patchFiles.isEmpty()) { - getLogger().debug("applying MCP patches"); + getLogger().debug("applying " + patchFiles.size() + " MCP patch(es)"); ContextProvider provider = new ContextProvider(file); ContextualPatch patch = findPatch(patchFiles, provider,getLogger()); if (patch != null) { patchErrors.add(new PatchAttempt(patch.patch(false),file)); file = provider.getAsString(); + } else { + //This shouldn't ever happen + throw new IllegalStateException("Cannot find patches " + patchFiles + " for " + name); } } @@ -178,28 +182,23 @@ protected void postWriteEntry(JarOutputStream jarOut, String entryName) throws I protected void postWrite(JarOutputStream jarOut) throws IOException { File file = ((DelayedFile)this.injectDir).call(); - File info = new File(file, "package-info-template.java"); - if (info.exists()) - { - String template = Resources.toString(info.toURI().toURL(), Charsets.UTF_8); - getLogger().debug("Adding package-infos"); - for (String pkg : this.seenPackages) - { - jarOut.putNextEntry(new ZipEntry(pkg + "/package-info.java")); - jarOut.write(template.replaceAll("\\{PACKAGE\\}", pkg.replace('/', '.')).getBytes()); - jarOut.closeEntry(); - } - } - File common = new File(file, "common/"); - if (common.isDirectory()) - { - for (File f : this.getProject().fileTree(common)) - { - String name = f.getAbsolutePath().substring(common.getAbsolutePath().length() + 1).replace('\\', '/'); - jarOut.putNextEntry(new ZipEntry(name)); - jarOut.write(Resources.toByteArray(f.toURI().toURL())); - jarOut.closeEntry(); - } + + for (File f : getProject().fileTree(file)) { + if ("package-info-template.java".equals(f.getName())) { + String template = Files.toString(f, Charsets.UTF_8); + getLogger().debug("Adding package-infos"); + + for (String pkg : seenPackages) { + jarOut.putNextEntry(new ZipEntry(pkg + "/package-info.java")); + jarOut.write(template.replaceAll("\\{PACKAGE\\}", pkg.replace('/', '.')).getBytes()); + jarOut.closeEntry(); + } + } else { + String name = f.getAbsolutePath().substring(file.getAbsolutePath().length() + 1).replace('\\', '/'); + jarOut.putNextEntry(new ZipEntry(name)); + jarOut.write(Files.asByteSource(f).read()); + jarOut.closeEntry(); + } } } @@ -259,7 +258,7 @@ private static ContextualPatch findPatch(Collection files, ContextProvider { ContextualPatch patch = null; File lastFile = null; - boolean success = true; + boolean success = false; for (File f : files) { logger.debug("trying MCP patch " + f.getName()); diff --git a/src/main/java/net/minecraftforge/gradle/user/UserBasePlugin.java b/src/main/java/net/minecraftforge/gradle/user/UserBasePlugin.java index 7a11a9d1f..0820fad9b 100644 --- a/src/main/java/net/minecraftforge/gradle/user/UserBasePlugin.java +++ b/src/main/java/net/minecraftforge/gradle/user/UserBasePlugin.java @@ -113,10 +113,10 @@ public final void applyPlugin() task.setGroup("ForgeGradle"); task.dependsOn(TASK_DD_PROVIDED, TASK_DD_COMPILE); -// task = makeTask(TASK_SETUP_DECOMP, DefaultTask.class); -// task.setDescription("DevWorkspace + the deobfuscated Minecraft source linked as a source jar."); -// task.setGroup("ForgeGradle"); -// task.dependsOn(TASK_DD_PROVIDED, TASK_DD_COMPILE); + task = makeTask(TASK_SETUP_DECOMP, DefaultTask.class); + task.setDescription("DevWorkspace + the deobfuscated Minecraft source linked as a source jar."); + task.setGroup("ForgeGradle"); + task.dependsOn(TASK_DD_PROVIDED, TASK_DD_COMPILE); // create configs project.getConfigurations().maybeCreate(CONFIG_MC); @@ -288,11 +288,12 @@ protected void makeDecompTasks(final String globalPattern, final String localPat final DeobfuscateJar deobfBin = makeTask(TASK_DEOBF_BIN, DeobfuscateJar.class); { deobfBin.setSrg(delayedFile(SRG_NOTCH_TO_MCP)); - deobfBin.setExceptorJson(delayedFile(MCP_DATA_EXC_JSON)); deobfBin.setExceptorCfg(delayedFile(EXC_MCP)); + deobfBin.setAccessCfg(delayedFile(MCP_DATA_ACCESS)); + deobfBin.setConstructorCfg(delayedFile(MCP_DATA_CONSTRUCTORS)); + deobfBin.setExceptionsCfg(delayedFile(MCP_DATA_EXCEPTIONS)); deobfBin.setFieldCsv(delayedFile(CSV_FIELD)); deobfBin.setMethodCsv(delayedFile(CSV_METHOD)); - deobfBin.setApplyMarkers(false); deobfBin.setInJar(transformedJar); deobfBin.setOutJar(chooseDeobfOutput(globalPattern, localPattern, "Bin", "")); deobfBin.dependsOn(transformAccess); @@ -307,12 +308,13 @@ protected void makeDecompTasks(final String globalPattern, final String localPat final DeobfuscateJar deobfDecomp = makeTask(TASK_DEOBF, DeobfuscateJar.class); { deobfDecomp.setSrg(delayedFile(SRG_NOTCH_TO_SRG)); - deobfDecomp.setExceptorJson(delayedFile(MCP_DATA_EXC_JSON)); deobfDecomp.setExceptorCfg(delayedFile(EXC_SRG)); - deobfDecomp.setApplyMarkers(true); + deobfDecomp.setAccessCfg(delayedFile(MCP_DATA_ACCESS)); + deobfDecomp.setConstructorCfg(delayedFile(MCP_DATA_CONSTRUCTORS)); + deobfDecomp.setExceptionsCfg(delayedFile(MCP_DATA_EXCEPTIONS)); deobfDecomp.setInJar(transformedJar); deobfDecomp.setOutJar(deobfDecompJar); - deobfDecomp.dependsOn(inputTask, TASK_GENERATE_SRGS, TASK_EXTRACT_DEP_ATS, TASK_DD_COMPILE, TASK_DD_PROVIDED); // todo grab correct task to depend on + deobfDecomp.dependsOn(transformAccess); } final ApplyFernFlowerTask decompile = makeTask(TASK_DECOMPILE, ApplyFernFlowerTask.class); @@ -398,7 +400,7 @@ protected void makeDecompTasks(final String globalPattern, final String localPat // add setup dependencies project.getTasks().getByName(TASK_SETUP_CI).dependsOn(deobfBin); project.getTasks().getByName(TASK_SETUP_DEV).dependsOn(deobfBin, makeStart); -// project.getTasks().getByName(TASK_SETUP_DECOMP).dependsOn(recompile, makeStart); + project.getTasks().getByName(TASK_SETUP_DECOMP).dependsOn(recompile, makeStart); // configure MC compiling. This AfterEvaluate section should happen after the one made in // also configure the dummy task dependencies diff --git a/src/main/java/net/minecraftforge/gradle/util/ExtractionVisitor.java b/src/main/java/net/minecraftforge/gradle/util/ExtractionVisitor.java index b3ba0776d..a2a8b26f9 100644 --- a/src/main/java/net/minecraftforge/gradle/util/ExtractionVisitor.java +++ b/src/main/java/net/minecraftforge/gradle/util/ExtractionVisitor.java @@ -28,9 +28,9 @@ public class ExtractionVisitor implements FileVisitor { - private final File outputDir; - private final boolean emptyDirs; - private final Spec spec; + protected final File outputDir; + private final boolean emptyDirs; + protected final Spec spec; public ExtractionVisitor(File outDir, boolean emptyDirs, Spec spec) { diff --git a/src/main/java/net/minecraftforge/gradle/util/mcp/ReobfExceptor.java b/src/main/java/net/minecraftforge/gradle/util/mcp/ReobfExceptor.java index 5be2d51ef..de57b2165 100644 --- a/src/main/java/net/minecraftforge/gradle/util/mcp/ReobfExceptor.java +++ b/src/main/java/net/minecraftforge/gradle/util/mcp/ReobfExceptor.java @@ -36,7 +36,6 @@ import java.io.IOException; import java.nio.charset.Charset; import java.util.ArrayList; -import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -59,8 +58,6 @@ import com.google.common.io.Files; import com.google.common.io.LineProcessor; -import de.oceanlabs.mcp.mcinjector.StringUtil; - public class ReobfExceptor { // info supplied. @@ -321,7 +318,7 @@ else if (split[0].equals("MD:")) m.appendTail(b); split[4] = b.toString(); } - out.append(StringUtil.joinString(Arrays.asList(split), " ")).append('\n'); + out.append(String.join(" ", split)).append('\n'); return true; } diff --git a/src/main/java/net/minecraftforge/gradle/util/patching/ContextualPatch.java b/src/main/java/net/minecraftforge/gradle/util/patching/ContextualPatch.java index 6afe117b4..a3c28786c 100644 --- a/src/main/java/net/minecraftforge/gradle/util/patching/ContextualPatch.java +++ b/src/main/java/net/minecraftforge/gradle/util/patching/ContextualPatch.java @@ -185,6 +185,7 @@ public List patch(boolean dryRun) throws PatchException, IOExceptio private void init() throws IOException { + unreadPatchLine(); if (patchString != null) { //Just read the string as is, without trying to read the magic/encoding as the string shuldn't need encoding! diff --git a/src/test/java/net/minecraftforge/gradle/tasks/TestExtractMcpConfig.java b/src/test/java/net/minecraftforge/gradle/tasks/TestExtractMcpConfig.java new file mode 100644 index 000000000..9a92bb5f7 --- /dev/null +++ b/src/test/java/net/minecraftforge/gradle/tasks/TestExtractMcpConfig.java @@ -0,0 +1,58 @@ +package net.minecraftforge.gradle.tasks; + +import static net.minecraftforge.gradle.common.Constants.CONFIG_MCP_DATA; +import static net.minecraftforge.gradle.common.Constants.URL_FORGE_MAVEN; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; + +import org.gradle.api.Project; +import org.junit.Assert; +import org.junit.Test; + +import com.google.common.collect.ImmutableMap; + +import net.minecraftforge.gradle.testsupport.TaskTest; + +public class TestExtractMcpConfig extends TaskTest { + private static final String CONFIG_VERSION = "1.13.1-20180919.183102"; + + private static void attachDownload(Project project) { + project.getConfigurations().maybeCreate(CONFIG_MCP_DATA); + project.getRepositories().maven(repo -> { + repo.setName("forge"); + repo.setUrl(URL_FORGE_MAVEN); + }); + project.getDependencies().add(CONFIG_MCP_DATA, ImmutableMap.of( + "group", "de.oceanlabs.mcp", + "name", "mcp_config", + "version", CONFIG_VERSION, + //"classifier", "srg", + "ext", "zip" + )); + } + + @Test + public void runTask() throws IOException { + File outDir = temporaryFolder.newFolder("extract"); + + ExtractConfigTask extractMcpData = getTask(ExtractMcpConfigTask.class); + attachDownload(extractMcpData.getProject()); + + extractMcpData.setDestinationDir(outDir); + extractMcpData.setConfig(CONFIG_MCP_DATA); + extractMcpData.setDoesCache(true); + + extractMcpData.doTask(); + + Assert.assertTrue(new File(outDir, "config/joined.srg").exists()); + try (BufferedReader in = new BufferedReader(new FileReader(new File(outDir, "config/joined.srg")))) { + //Take a quick look at the first 10 lines to double check it's not all rubbish + for (int read = 0; read < 10; read++) { + System.out.println(in.readLine()); + } + } + } +} \ No newline at end of file