diff --git a/src/main/java/net/fabricmc/loom/AbstractPlugin.java b/src/main/java/net/fabricmc/loom/AbstractPlugin.java index 365f266..5b815a7 100644 --- a/src/main/java/net/fabricmc/loom/AbstractPlugin.java +++ b/src/main/java/net/fabricmc/loom/AbstractPlugin.java @@ -28,7 +28,7 @@ import com.google.common.collect.ImmutableMap; import net.fabricmc.loom.providers.MinecraftProvider; import net.fabricmc.loom.providers.ModRemapperProvider; import net.fabricmc.loom.providers.PomfProvider; -import net.fabricmc.loom.task.RemapModsTask; +import net.fabricmc.loom.task.RemapJar; import net.fabricmc.loom.util.Constants; import net.fabricmc.loom.util.LoomDependencyManager; import net.fabricmc.loom.util.SetupIntelijRunConfigs; @@ -40,8 +40,10 @@ import org.gradle.api.artifacts.repositories.MavenArtifactRepository; import org.gradle.api.plugins.JavaPlugin; import org.gradle.api.plugins.JavaPluginConvention; import org.gradle.api.tasks.SourceSet; +import org.gradle.api.tasks.bundling.AbstractArchiveTask; import org.gradle.api.tasks.compile.JavaCompile; import org.gradle.api.tasks.javadoc.Javadoc; +import org.gradle.jvm.tasks.Jar; import org.gradle.plugins.ide.eclipse.model.EclipseModel; import org.gradle.plugins.ide.idea.model.IdeaModel; @@ -221,17 +223,15 @@ public class AbstractPlugin implements Plugin { SetupIntelijRunConfigs.setup(project1); //Enables the default mod remapper - if(extension.remapMod){ - RemapModsTask remapModsTask = (RemapModsTask) project1.getTasks().findByName("remapMod"); - remapModsTask.from(main.getOutput()); - remapModsTask.doLast(task -> project1.getArtifacts().add("archives", remapModsTask)); - project1.getTasks().getByName("build").finalizedBy(remapModsTask); + if (extension.remapMod) { + AbstractArchiveTask jarTask = (AbstractArchiveTask) project1.getTasks().getByName("jar"); + + RemapJar remapJarTask = (RemapJar) project1.getTasks().findByName("remapJar"); + remapJarTask.jar = jarTask.getArchivePath(); + remapJarTask.doLast(task -> project1.getArtifacts().add("archives", remapJarTask.jar)); + remapJarTask.dependsOn(project1.getTasks().getByName("jar")); + project1.getTasks().getByName("build").dependsOn(remapJarTask); } - }); - - //Disables the creation of a standard jar - project.getTasks().getByName("jar").onlyIf(element -> false); - } } diff --git a/src/main/java/net/fabricmc/loom/LoomGradlePlugin.java b/src/main/java/net/fabricmc/loom/LoomGradlePlugin.java index 34851b9..e2a8a35 100644 --- a/src/main/java/net/fabricmc/loom/LoomGradlePlugin.java +++ b/src/main/java/net/fabricmc/loom/LoomGradlePlugin.java @@ -25,7 +25,7 @@ package net.fabricmc.loom; import net.fabricmc.loom.task.GenIdeaProjectTask; -import net.fabricmc.loom.task.RemapModsTask; +import net.fabricmc.loom.task.RemapJar; import net.fabricmc.loom.task.RunClientTask; import net.fabricmc.loom.task.RunServerTask; import org.gradle.api.Project; @@ -35,7 +35,7 @@ public class LoomGradlePlugin extends AbstractPlugin { public void apply(Project target) { super.apply(target); - makeTask("remapMod", RemapModsTask.class); + makeTask("remapJar", RemapJar.class); makeTask("genIdeaWorkspace", GenIdeaProjectTask.class).dependsOn("idea").setGroup("ide"); diff --git a/src/main/java/net/fabricmc/loom/providers/PomfProvider.java b/src/main/java/net/fabricmc/loom/providers/PomfProvider.java index 91715a7..1cf305b 100644 --- a/src/main/java/net/fabricmc/loom/providers/PomfProvider.java +++ b/src/main/java/net/fabricmc/loom/providers/PomfProvider.java @@ -56,8 +56,8 @@ public class PomfProvider extends DependencyProvider { File mappingsJar = dependency.resolveFile(); - this.pomfVersion = split[0]; - this.minecraftVersion = split[1]; + this.minecraftVersion = split[0]; + this.pomfVersion = split[1]; initFiles(project); diff --git a/src/main/java/net/fabricmc/loom/task/RemapModsTask.java b/src/main/java/net/fabricmc/loom/task/RemapJar.java similarity index 85% rename from src/main/java/net/fabricmc/loom/task/RemapModsTask.java rename to src/main/java/net/fabricmc/loom/task/RemapJar.java index 9636de4..c837dfc 100644 --- a/src/main/java/net/fabricmc/loom/task/RemapModsTask.java +++ b/src/main/java/net/fabricmc/loom/task/RemapJar.java @@ -25,14 +25,24 @@ package net.fabricmc.loom.task; import net.fabricmc.loom.util.ModRemapper; +import org.gradle.api.DefaultTask; +import org.gradle.api.tasks.Input; +import org.gradle.api.tasks.OutputFile; import org.gradle.api.tasks.TaskAction; import org.gradle.jvm.tasks.Jar; -public class RemapModsTask extends Jar { +import java.io.File; + +public class RemapJar extends DefaultTask { + public File jar; + + @Input + public File getJar() { + return jar; + } @TaskAction public void remap() { ModRemapper.remap(this); } - } diff --git a/src/main/java/net/fabricmc/loom/util/MixinRefmapHelper.java b/src/main/java/net/fabricmc/loom/util/MixinRefmapHelper.java new file mode 100644 index 0000000..70de12d --- /dev/null +++ b/src/main/java/net/fabricmc/loom/util/MixinRefmapHelper.java @@ -0,0 +1,204 @@ +/* + * This file is part of fabric-loom, licensed under the MIT License (MIT). + * + * Copyright (c) 2016, 2017, 2018 FabricMC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.fabricmc.loom.util; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import net.fabricmc.tinyremapper.TinyRemapper; +import org.objectweb.asm.commons.Remapper; +import org.spongepowered.asm.mixin.injection.struct.MemberInfo; +import org.zeroturnaround.zip.ZipUtil; +import org.zeroturnaround.zip.transform.StringZipEntryTransformer; +import org.zeroturnaround.zip.transform.ZipEntryTransformerEntry; + +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.lang.reflect.Field; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.zip.ZipEntry; + +public final class MixinRefmapHelper { + private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create(); + + private MixinRefmapHelper() { + + } + public static boolean addRefmapName(String filename, File output) { + Set mixinFilenames = findMixins(output, true); + + if (mixinFilenames.size() > 0) { + ZipUtil.transformEntries( + output, + mixinFilenames.stream() + .map((f) -> new ZipEntryTransformerEntry(f, new StringZipEntryTransformer("UTF-8") { + @Override + protected String transform(ZipEntry zipEntry, String input) throws IOException { + JsonObject json = GSON.fromJson(input, JsonObject.class); + json.addProperty("refmap", filename); + return GSON.toJson(json); + } + })).toArray(ZipEntryTransformerEntry[]::new) + ); + + return true; + } else { + return false; + } + } + + private static Set findMixins(File output, boolean onlyWithoutRefmap) { + // first, identify all of the mixin files + Set mixinFilename = new HashSet<>(); + // TODO: this is a lovely hack + ZipUtil.iterate(output, (stream, entry) -> { + if (!entry.isDirectory() && entry.getName().endsWith(".json") && !entry.getName().contains("/") && !entry.getName().contains("\\")) { + // JSON file in root directory + try { + InputStreamReader inputStreamReader = new InputStreamReader(stream); + JsonObject json = GSON.fromJson(inputStreamReader, JsonObject.class); + inputStreamReader.close(); + stream.close(); + if (json != null && json.has("mixins") && json.get("mixins").isJsonArray()) { + if (!onlyWithoutRefmap || !json.has("refmap")) { + mixinFilename.add(entry.getName()); + } + } + } catch (Exception e) { + // ... + } + } + }); + return mixinFilename; + } + + private static Set findRefmaps(File output) { + // first, identify all of the mixin refmaps + Set mixinRefmapFilenames = new HashSet<>(); + // TODO: this is also a lovely hack + ZipUtil.iterate(output, (stream, entry) -> { + if (!entry.isDirectory() && entry.getName().endsWith(".json") && !entry.getName().contains("/") && !entry.getName().contains("\\")) { + // JSON file in root directory + try { + InputStreamReader inputStreamReader = new InputStreamReader(stream); + JsonObject json = GSON.fromJson(inputStreamReader, JsonObject.class); + inputStreamReader.close(); + stream.close(); + if (json != null && json.has("refmap")) { + mixinRefmapFilenames.add(json.get("refmap").getAsString()); + } + } catch (Exception e) { + // ... + } + } + }); + return mixinRefmapFilenames; + } + + public static boolean transformRefmaps(TinyRemapper remapper, File output) { + Set mixinRefmapFilenames = findRefmaps(output); + + if (mixinRefmapFilenames.size() > 0) { + Remapper asmRemapper; + // TODO: Expose in tiny-remapper + try { + Field f = TinyRemapper.class.getDeclaredField("remapper");; + f.setAccessible(true); + asmRemapper = (Remapper) f.get(remapper); + } catch (Exception e) { + throw new RuntimeException(e); + } + + ZipUtil.transformEntries( + output, + mixinRefmapFilenames.stream() + .map((f) -> new ZipEntryTransformerEntry(f, new StringZipEntryTransformer("UTF-8") { + @Override + protected String transform(ZipEntry zipEntry, String input) throws IOException { + return transformRefmap(asmRemapper, GSON, input); + } + })).toArray(ZipEntryTransformerEntry[]::new) + ); + + return true; + } else { + return false; + } + } + + public static String transformRefmap(Remapper remapper, Gson gson, String input) throws IOException { + try { + JsonObject refMap = gson.fromJson(input, JsonObject.class); + JsonObject mappings = refMap.getAsJsonObject("mappings"); + + for (Map.Entry elementEntry : mappings.entrySet()) { + JsonObject value = elementEntry.getValue().getAsJsonObject(); + for (String k : new HashSet<>(value.keySet())) { + try { + String v = value.get(k).getAsString(); + String v2; + + if (v.charAt(0) == 'L') { + // field or member + MemberInfo info = MemberInfo.parse(v); + String owner = remapper.map(info.owner); + if (info.isField()) { + v2 = new MemberInfo( + remapper.mapFieldName(info.owner, info.name, info.desc), + owner, + remapper.mapDesc(info.desc) + ).toString(); + } else { + v2 = new MemberInfo( + remapper.mapMethodName(info.owner, info.name, info.desc), + owner, + remapper.mapMethodDesc(info.desc) + ).toString(); + } + } else { + // class + v2 = remapper.map(v); + } + + if (v2 != null) { + value.addProperty(k, v2); + } + } catch (Exception ee) { + ee.printStackTrace(); + } + } + } + + return gson.toJson(refMap); + } catch (Exception e) { + e.printStackTrace(); + return input; + } + } +} diff --git a/src/main/java/net/fabricmc/loom/util/ModProcessor.java b/src/main/java/net/fabricmc/loom/util/ModProcessor.java index ec57f5f..1b62c5b 100644 --- a/src/main/java/net/fabricmc/loom/util/ModProcessor.java +++ b/src/main/java/net/fabricmc/loom/util/ModProcessor.java @@ -119,105 +119,12 @@ public class ModProcessor { throw new RuntimeException("Failed to remap JAR to " + toM + " file not found: " + output.getAbsolutePath()); } - Gson gson = new GsonBuilder().setPrettyPrinting().create(); - // first, identify all of the mixin refmaps - Set mixinRefmapFilenames = new HashSet<>(); - // TODO: this is a lovely hack - ZipUtil.iterate(output, (stream, entry) -> { - if (!entry.isDirectory() && entry.getName().endsWith(".json") && !entry.getName().contains("/") && !entry.getName().contains("\\")) { - // JSON file in root directory - try { - InputStreamReader inputStreamReader = new InputStreamReader(stream); - JsonObject json = gson.fromJson(inputStreamReader, JsonObject.class); - inputStreamReader.close(); - stream.close(); - if (json != null && json.has("refmap")) { - mixinRefmapFilenames.add(json.get("refmap").getAsString()); - } - } catch (Exception e) { - // ... - } - } - }); - - if (mixinRefmapFilenames.size() > 0) { - Remapper asmRemapper; - // TODO: Expose in tiny-remapper - try { - Field f = TinyRemapper.class.getDeclaredField("remapper");; - f.setAccessible(true); - asmRemapper = (Remapper) f.get(remapper); - } catch (Exception e) { - throw new RuntimeException(e); - } - + if (MixinRefmapHelper.transformRefmaps(remapper, output)) { project.getLogger().lifecycle(":remapping " + input.getName() + " (Mixin reference maps)"); - - ZipUtil.transformEntries( - output, - mixinRefmapFilenames.stream() - .map((f) -> new ZipEntryTransformerEntry(f, new StringZipEntryTransformer("UTF-8") { - @Override - protected String transform(ZipEntry zipEntry, String input) throws IOException { - return transformRefmap(asmRemapper, gson, input); - } - })).toArray(ZipEntryTransformerEntry[]::new) - ); - remapper.finish(); } } - public static String transformRefmap(Remapper remapper, Gson gson, String input) throws IOException { - try { - JsonObject refMap = gson.fromJson(input, JsonObject.class); - JsonObject mappings = refMap.getAsJsonObject("mappings"); - - for (Map.Entry elementEntry : mappings.entrySet()) { - JsonObject value = elementEntry.getValue().getAsJsonObject(); - for (String k : new HashSet<>(value.keySet())) { - try { - String v = value.get(k).getAsString(); - String v2; - - if (v.charAt(0) == 'L') { - // field or member - MemberInfo info = MemberInfo.parse(v); - String owner = remapper.map(info.owner); - if (info.isField()) { - v2 = new MemberInfo( - remapper.mapFieldName(info.owner, info.name, info.desc), - owner, - remapper.mapDesc(info.desc) - ).toString(); - } else { - v2 = new MemberInfo( - remapper.mapMethodName(info.owner, info.name, info.desc), - owner, - remapper.mapMethodDesc(info.desc) - ).toString(); - } - } else { - // class - v2 = remapper.map(v); - } - - if (v2 != null) { - value.addProperty(k, v2); - } - } catch (Exception ee) { - ee.printStackTrace(); - } - } - } - - return gson.toJson(refMap); - } catch (Exception e) { - e.printStackTrace(); - return input; - } - } - private static void handleInstallerJson(JsonObject jsonObject, Project project){ JsonObject libraries = jsonObject.get("libraries").getAsJsonObject(); libraries.get("common").getAsJsonArray().forEach(jsonElement -> { diff --git a/src/main/java/net/fabricmc/loom/util/ModRemapper.java b/src/main/java/net/fabricmc/loom/util/ModRemapper.java index ef537f1..328c409 100644 --- a/src/main/java/net/fabricmc/loom/util/ModRemapper.java +++ b/src/main/java/net/fabricmc/loom/util/ModRemapper.java @@ -26,7 +26,7 @@ package net.fabricmc.loom.util; import net.fabricmc.loom.LoomGradleExtension; import net.fabricmc.loom.providers.PomfProvider; -import net.fabricmc.loom.task.RemapModsTask; +import net.fabricmc.loom.task.RemapJar; import net.fabricmc.tinyremapper.OutputConsumerPath; import net.fabricmc.tinyremapper.TinyRemapper; import net.fabricmc.tinyremapper.TinyUtils; @@ -39,14 +39,14 @@ import java.util.List; public class ModRemapper { - public static void remap(RemapModsTask task) { + public static void remap(RemapJar task) { Project project = task.getProject(); LoomGradleExtension extension = project.getExtensions().getByType(LoomGradleExtension.class); - File modJar = task.getArchivePath(); + File modJar = task.jar; if (!modJar.exists()) { - project.getLogger().error("This is can be fixed by adding a 'settings.gradle' file specifying 'rootProject.name'"); + project.getLogger().error("Source .JAR not found!"); return; } @@ -59,8 +59,12 @@ public class ModRemapper { List classpathFiles = new ArrayList<>(); classpathFiles.addAll(project.getConfigurations().getByName("compile").getFiles()); - Path[] classpath = classpathFiles.stream().map(File::toPath).toArray(Path[]::new); + Path modJarPath = modJar.toPath(); + + String s =modJar.getAbsolutePath(); + File modJarOutput = new File(s.substring(0, s.length() - 4) + ".remapped.jar"); + Path modJarOutputPath = modJarOutput.toPath(); File mixinMapFile = pomfProvider.MAPPINGS_MIXIN_EXPORT; Path mixinMapPath = mixinMapFile.toPath(); @@ -71,17 +75,16 @@ public class ModRemapper { remapperBuilder = remapperBuilder.withMappings(TinyUtils.createTinyMappingProvider(mixinMapPath, fromM, toM)); } - project.getLogger().lifecycle("Remapping " + modJar.getName()); TinyRemapper remapper = remapperBuilder.build(); try { - OutputConsumerPath outputConsumer = new OutputConsumerPath(modJar.toPath()); - outputConsumer.addNonClassFiles(modJar.toPath()); - remapper.read(modJar.toPath()); + OutputConsumerPath outputConsumer = new OutputConsumerPath(modJarOutputPath); + outputConsumer.addNonClassFiles(modJarPath); remapper.read(classpath); - remapper.apply(modJar.toPath(), outputConsumer); + remapper.read(modJarPath); + remapper.apply(modJarPath, outputConsumer); outputConsumer.finish(); remapper.finish(); } catch (Exception e){ @@ -89,9 +92,19 @@ public class ModRemapper { throw new RuntimeException("Failed to remap JAR", e); } - if(!modJar.exists()){ + if (!modJarOutput.exists()){ throw new RuntimeException("Failed to reobfuscate JAR"); } + + if (extension.refmapName != null && extension.refmapName.length() > 0) { + MixinRefmapHelper.addRefmapName(extension.refmapName, modJarOutput); + } + + if (modJar.exists()) { + modJar.delete(); + } + + modJarOutput.renameTo(modJar); } }