diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 00000000..f1f17c27 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,29 @@ +name: Publish +on: + push: + branches: + - 'dev/**' + +jobs: + build: + runs-on: ubuntu-20.04 + container: + image: openjdk:8-jdk + options: --user root + steps: + - uses: actions/checkout@v1 + - uses: gradle/wrapper-validation-action@v1 + + # Generate the build number based on tags to allow per branch build numbers, not something github provides by default. + - name: Generate build number + id: buildnumber + uses: einaregilsson/build-number@v3 + with: + token: ${{ secrets.github_token }} + prefix: ${{ github.ref }} + + - run: ./gradlew build publish -x test --stacktrace + env: + MAVEN_URL: ${{ secrets.MAVEN_URL }} + MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }} + MAVEN_PASSWORD: ${{ secrets.MAVEN_PASSWORD }} \ No newline at end of file diff --git a/.github/workflows/test-push.yml b/.github/workflows/test-push.yml index a33c5956..9bde1bfc 100644 --- a/.github/workflows/test-push.yml +++ b/.github/workflows/test-push.yml @@ -4,15 +4,13 @@ jobs: gradle: strategy: matrix: - gradle: [4.9, 4.10.2, 6.5.1] - java: [jdk8, jdk11, jdk14] + gradle: [4.9, 4.10.2, 6.7] + java: [jdk8, jdk11, jdk15] exclude: # Dont run older gradle versions on newer java - - java: jdk14 + - java: jdk15 gradle: 4.9 - - java: jdk14 + - java: jdk15 gradle: 4.10.2 - - java: jdk14 - gradle: 5.6.4 - java: jdk11 gradle: 4.9 - java: jdk11 diff --git a/Jenkinsfile b/Jenkinsfile deleted file mode 100644 index 094a0a73..00000000 --- a/Jenkinsfile +++ /dev/null @@ -1,15 +0,0 @@ -node { - stage 'Checkout' - - checkout scm - - stage 'Build' - - sh "rm -rf build/libs/" - sh "chmod +x gradlew" - sh "./gradlew build -x test --refresh-dependencies" - - stage "Archive artifacts" - - sh "./gradlew publish" -} \ No newline at end of file diff --git a/build.gradle b/build.gradle index 23a98b65..18e33cab 100644 --- a/build.gradle +++ b/build.gradle @@ -18,7 +18,7 @@ def baseVersion = '0.5' def build = 'local' def ENV = System.getenv() if (ENV.BUILD_NUMBER) { - build = 'jenkins #${ENV.BUILD_NUMBER}' + build = "release #${ENV.BUILD_NUMBER}" version = baseVersion + '.' + ENV.BUILD_NUMBER } else { version = baseVersion + '-forge.28' @@ -54,9 +54,12 @@ dependencies { implementation ('net.fabricmc:tiny-remapper:0.3.0.70') implementation ('net.fabricmc:tiny-mappings-parser:0.2.2.14') + implementation 'net.fabricmc:access-widener:1.0.0' + implementation ('net.fabricmc:lorenz-tiny:2.0.0+build.2') { transitive = false } + implementation ('org.cadixdev:lorenz-io-proguard:0.5.5') // decompilers implementation ('net.fabricmc:procyon-fabric-compilertools:0.5.35.13') @@ -64,7 +67,7 @@ dependencies { implementation ('org.benf:cfr:0.150') // source code remapping - implementation ('org.cadixdev:mercury:0.1.0.fabric-SNAPSHOT') + implementation ('org.cadixdev:mercury:0.1.0-rc1') // Kapt integration compileOnly('org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.72') @@ -175,11 +178,11 @@ publishing { } repositories { maven { - url 'http://mavenupload.modmuss50.me/' - if (project.hasProperty('mavenPass')) { + if (ENV.MAVEN_URL) { + url ENV.MAVEN_URL credentials { - username 'buildslave' - password project.getProperty('mavenPass') + username ENV.MAVEN_USERNAME + password ENV.MAVEN_PASSWORD } } } diff --git a/src/main/java/net/fabricmc/loom/AbstractPlugin.java b/src/main/java/net/fabricmc/loom/AbstractPlugin.java index fe40152d..78a26ab6 100644 --- a/src/main/java/net/fabricmc/loom/AbstractPlugin.java +++ b/src/main/java/net/fabricmc/loom/AbstractPlugin.java @@ -38,6 +38,8 @@ import org.gradle.api.Task; import org.gradle.api.UnknownTaskException; import org.gradle.api.artifacts.Configuration; import org.gradle.api.artifacts.Dependency; +import org.gradle.api.artifacts.ExcludeRule; +import org.gradle.api.artifacts.ModuleDependency; import org.gradle.api.artifacts.repositories.MavenArtifactRepository; import org.gradle.api.plugins.JavaPlugin; import org.gradle.api.plugins.JavaPluginConvention; @@ -114,40 +116,40 @@ public class AbstractPlugin implements Plugin { addMavenRepo(target, "Mojang", "https://libraries.minecraft.net/"); addMavenRepo(target, "Forge", "https://files.minecraftforge.net/maven/"); - Configuration modCompileClasspathConfig = project.getConfigurations().maybeCreate(Constants.MOD_COMPILE_CLASSPATH); + Configuration modCompileClasspathConfig = project.getConfigurations().maybeCreate(Constants.Configurations.MOD_COMPILE_CLASSPATH); modCompileClasspathConfig.setTransitive(true); - Configuration modCompileClasspathMappedConfig = project.getConfigurations().maybeCreate(Constants.MOD_COMPILE_CLASSPATH_MAPPED); + Configuration modCompileClasspathMappedConfig = project.getConfigurations().maybeCreate(Constants.Configurations.MOD_COMPILE_CLASSPATH_MAPPED); modCompileClasspathMappedConfig.setTransitive(false); - Configuration minecraftNamedConfig = project.getConfigurations().maybeCreate(Constants.MINECRAFT_NAMED); + Configuration minecraftNamedConfig = project.getConfigurations().maybeCreate(Constants.Configurations.MINECRAFT_NAMED); minecraftNamedConfig.setTransitive(false); // The launchers do not recurse dependencies - Configuration minecraftDependenciesConfig = project.getConfigurations().maybeCreate(Constants.MINECRAFT_DEPENDENCIES); + Configuration minecraftDependenciesConfig = project.getConfigurations().maybeCreate(Constants.Configurations.MINECRAFT_DEPENDENCIES); minecraftDependenciesConfig.setTransitive(false); - Configuration minecraftConfig = project.getConfigurations().maybeCreate(Constants.MINECRAFT); + Configuration minecraftConfig = project.getConfigurations().maybeCreate(Constants.Configurations.MINECRAFT); minecraftConfig.setTransitive(false); if (project.getExtensions().getByType(LoomGradleExtension.class).isForge()) { - Configuration forgeConfig = project.getConfigurations().maybeCreate(Constants.FORGE); + Configuration forgeConfig = project.getConfigurations().maybeCreate(Constants.Configurations.FORGE); forgeConfig.setTransitive(false); - Configuration forgeUserdevConfig = project.getConfigurations().maybeCreate(Constants.FORGE_USERDEV); + Configuration forgeUserdevConfig = project.getConfigurations().maybeCreate(Constants.Configurations.FORGE_USERDEV); forgeUserdevConfig.setTransitive(false); - Configuration forgeInstallerConfig = project.getConfigurations().maybeCreate(Constants.FORGE_INSTALLER); + Configuration forgeInstallerConfig = project.getConfigurations().maybeCreate(Constants.Configurations.FORGE_INSTALLER); forgeInstallerConfig.setTransitive(false); - Configuration forgeUniversalConfig = project.getConfigurations().maybeCreate(Constants.FORGE_UNIVERSAL); + Configuration forgeUniversalConfig = project.getConfigurations().maybeCreate(Constants.Configurations.FORGE_UNIVERSAL); forgeUniversalConfig.setTransitive(false); - Configuration forgeDependencies = project.getConfigurations().maybeCreate(Constants.FORGE_DEPENDENCIES); + Configuration forgeDependencies = project.getConfigurations().maybeCreate(Constants.Configurations.FORGE_DEPENDENCIES); forgeDependencies.setTransitive(false); - Configuration mcpConfig = project.getConfigurations().maybeCreate(Constants.MCP_CONFIG); + Configuration mcpConfig = project.getConfigurations().maybeCreate(Constants.Configurations.MCP_CONFIG); mcpConfig.setTransitive(false); - extendsFrom(Constants.MINECRAFT_DEPENDENCIES, Constants.FORGE_DEPENDENCIES); + extendsFrom(Constants.Configurations.MINECRAFT_DEPENDENCIES, Constants.Configurations.FORGE_DEPENDENCIES); } - Configuration includeConfig = project.getConfigurations().maybeCreate(Constants.INCLUDE); + Configuration includeConfig = project.getConfigurations().maybeCreate(Constants.Configurations.INCLUDE); includeConfig.setTransitive(false); // Dont get transitive deps - project.getConfigurations().maybeCreate(Constants.MAPPINGS); - project.getConfigurations().maybeCreate(Constants.MAPPINGS_FINAL); + project.getConfigurations().maybeCreate(Constants.Configurations.MAPPINGS); + project.getConfigurations().maybeCreate(Constants.Configurations.MAPPINGS_FINAL); for (RemappedConfigurationEntry entry : Constants.MOD_COMPILE_ENTRIES) { Configuration compileModsConfig = project.getConfigurations().maybeCreate(entry.getSourceConfiguration()); @@ -158,19 +160,19 @@ public class AbstractPlugin implements Plugin { extendsFrom(entry.getTargetConfiguration(project.getConfigurations()), entry.getRemappedConfiguration()); if (entry.isOnModCompileClasspath()) { - extendsFrom(Constants.MOD_COMPILE_CLASSPATH, entry.getSourceConfiguration()); - extendsFrom(Constants.MOD_COMPILE_CLASSPATH_MAPPED, entry.getRemappedConfiguration()); + extendsFrom(Constants.Configurations.MOD_COMPILE_CLASSPATH, entry.getSourceConfiguration()); + extendsFrom(Constants.Configurations.MOD_COMPILE_CLASSPATH_MAPPED, entry.getRemappedConfiguration()); } } - extendsFrom("compileClasspath", Constants.MINECRAFT_NAMED); - extendsFrom("runtimeClasspath", Constants.MINECRAFT_NAMED); - extendsFrom("testCompileClasspath", Constants.MINECRAFT_NAMED); - extendsFrom("testRuntimeClasspath", Constants.MINECRAFT_NAMED); + extendsFrom("compileClasspath", Constants.Configurations.MINECRAFT_NAMED); + extendsFrom("runtimeClasspath", Constants.Configurations.MINECRAFT_NAMED); + extendsFrom("testCompileClasspath", Constants.Configurations.MINECRAFT_NAMED); + extendsFrom("testRuntimeClasspath", Constants.Configurations.MINECRAFT_NAMED); - extendsFrom(Constants.MINECRAFT_NAMED, Constants.MINECRAFT_DEPENDENCIES); + extendsFrom(Constants.Configurations.MINECRAFT_NAMED, Constants.Configurations.MINECRAFT_DEPENDENCIES); - extendsFrom("compile", Constants.MAPPINGS_FINAL); + extendsFrom("compile", Constants.Configurations.MAPPINGS_FINAL); configureIDEs(); configureCompile(); @@ -342,17 +344,15 @@ public class AbstractPlugin implements Plugin { } }); }); - - for (Project subProject : rootProject.getAllprojects()) { - subProject.getTasks().getByName("build").dependsOn(parentTask); - subProject.getTasks().getByName("build").dependsOn(rootProject.getTasks().getByName("remapAllJars")); - rootProject.getTasks().getByName("remapAllJars").dependsOn(subProject.getTasks().getByName("remapJar")); - } } else { parentTask = rootProject.getTasks().getByName("remapAllSources"); remapper = ((RemapAllSourcesTask) parentTask).sourceRemapper; remapJarTask.jarRemapper = ((RemapJarTask) rootProject.getTasks().getByName("remapJar")).jarRemapper; + + project1.getTasks().getByName("build").dependsOn(parentTask); + project1.getTasks().getByName("build").dependsOn(rootProject.getTasks().getByName("remapAllJars")); + rootProject.getTasks().getByName("remapAllJars").dependsOn(project1.getTasks().getByName("remapJar")); } } @@ -378,16 +378,20 @@ public class AbstractPlugin implements Plugin { extension.getUnmappedModCollection().from(jarTask); } - project.getLogger().lifecycle("Configuring compiler arguments for Java"); + // Disable some things used by log4j via the mixin AP that prevent it from being garbage collected + System.setProperty("log4j2.disable.jmx", "true"); + System.setProperty("log4j.shutdownHookEnabled", "false"); + + project.getLogger().info("Configuring compiler arguments for Java"); new JavaApInvoker(project).configureMixin(); if (project.getPluginManager().hasPlugin("scala")) { - project.getLogger().lifecycle("Configuring compiler arguments for Scala"); + project.getLogger().info("Configuring compiler arguments for Scala"); new ScalaApInvoker(project).configureMixin(); } if (project.getPluginManager().hasPlugin("org.jetbrains.kotlin.kapt")) { - project.getLogger().lifecycle("Configuring compiler arguments for Kapt plugin"); + project.getLogger().info("Configuring compiler arguments for Kapt plugin"); new KaptApInvoker(project).configureMixin(); } }); @@ -437,6 +441,20 @@ public class AbstractPlugin implements Plugin { depNode.appendNode("artifactId", dependency.getName()); depNode.appendNode("version", dependency.getVersion()); depNode.appendNode("scope", entry.getMavenScope()); + + if (dependency instanceof ModuleDependency) { + final Set exclusions = ((ModuleDependency) dependency).getExcludeRules(); + + if (!exclusions.isEmpty()) { + Node exclusionsNode = depNode.appendNode("exclusions"); + + for (ExcludeRule rule : exclusions) { + Node exclusionNode = exclusionsNode.appendNode("exclusion"); + exclusionNode.appendNode("groupId", rule.getGroup() == null ? "*" : rule.getGroup()); + exclusionNode.appendNode("artifactId", rule.getModule() == null ? "*" : rule.getModule()); + } + } + } } })); } diff --git a/src/main/java/net/fabricmc/loom/LoomGradleExtension.java b/src/main/java/net/fabricmc/loom/LoomGradleExtension.java index cc2f369c..b20fd12a 100644 --- a/src/main/java/net/fabricmc/loom/LoomGradleExtension.java +++ b/src/main/java/net/fabricmc/loom/LoomGradleExtension.java @@ -28,8 +28,11 @@ import java.io.File; import java.nio.file.Path; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; import java.util.List; import java.util.Objects; +import java.util.Set; import java.util.function.BiPredicate; import java.util.function.Function; import java.util.function.Supplier; @@ -47,6 +50,7 @@ import org.gradle.api.file.ConfigurableFileCollection; import org.gradle.api.plugins.BasePluginConvention; import net.fabricmc.loom.api.decompilers.LoomDecompiler; +import net.fabricmc.loom.processors.JarProcessor; import net.fabricmc.loom.processors.JarProcessorManager; import net.fabricmc.loom.providers.ForgeUniversalProvider; import net.fabricmc.loom.providers.ForgeUserdevProvider; @@ -57,6 +61,7 @@ import net.fabricmc.loom.providers.PatchProvider; import net.fabricmc.loom.providers.McpConfigProvider; import net.fabricmc.loom.util.function.LazyBool; import net.fabricmc.loom.util.LoomDependencyManager; +import net.fabricmc.loom.util.mappings.MojangMappingsDependency; public class LoomGradleExtension { private static final String FORGE_PROPERTY = "loom.forge"; @@ -74,6 +79,7 @@ public class LoomGradleExtension { private final ConfigurableFileCollection unmappedMods; final List decompilers = new ArrayList<>(); + private final List jarProcessors = new ArrayList<>(); // Not to be set in the build.gradle private final Project project; @@ -83,6 +89,7 @@ public class LoomGradleExtension { private MappingSet[] srcMappingCache = new MappingSet[2]; private Mercury[] srcMercuryCache = new Mercury[2]; private final LazyBool forge; + private Set mixinMappings = Collections.synchronizedSet(new HashSet<>()); /** * Loom will generate a new genSources task (with a new name, based off of {@link LoomDecompiler#name()}) @@ -92,6 +99,17 @@ public class LoomGradleExtension { decompilers.add(decompiler); } + /** + * Add a transformation over the mapped mc jar. + * Adding any jar processor will cause mapped mc jars to be stored per-project so that + * different transformation can be applied in different projects. + * This means remapping will need to be done individually per-project, which is slower when developing + * more than one project using the same minecraft version. + */ + public void addJarProcessor(JarProcessor processor) { + jarProcessors.add(processor); + } + public MappingSet getOrCreateSrcMappingCache(int id, Supplier factory) { return srcMappingCache[id] != null ? srcMappingCache[id] : (srcMappingCache[id] = factory.get()); } @@ -100,6 +118,10 @@ public class LoomGradleExtension { return srcMercuryCache[id] != null ? srcMercuryCache[id] : (srcMercuryCache[id] = factory.get()); } + public Dependency officialMojangMappings() { + return new MojangMappingsDependency(project, this); + } + public LoomGradleExtension(Project project) { this.project = project; this.autoGenIDERuns = AbstractPlugin.isRootProject(project); @@ -363,6 +385,10 @@ public class LoomGradleExtension { this.jarProcessorManager = jarProcessorManager; } + public List getJarProcessors() { + return jarProcessors; + } + public String getRefmapName() { if (refmapName == null || refmapName.isEmpty()) { String defaultRefmapName = project.getConvention().getPlugin(BasePluginConvention.class).getArchivesBaseName() + "-refmap.json"; @@ -406,4 +432,16 @@ public class LoomGradleExtension { public boolean isForge() { return forge.getAsBoolean(); } + + // Creates a new file each time its called, this is then held onto later when remapping the output jar + // Required as now when using parallel builds the old single file could be written by another sourceset compile task + public synchronized File getNextMixinMappings() { + File mixinMapping = new File(getProjectBuildCache(), "mixin-map-" + getMinecraftProvider().getMinecraftVersion() + "-" + getMappingsProvider().mappingsVersion + "." + mixinMappings.size() + ".tiny"); + mixinMappings.add(mixinMapping); + return mixinMapping; + } + + public Set getAllMixinMappings() { + return Collections.unmodifiableSet(mixinMappings); + } } diff --git a/src/main/java/net/fabricmc/loom/processors/JarProcessor.java b/src/main/java/net/fabricmc/loom/processors/JarProcessor.java index 59bd5485..0a028942 100644 --- a/src/main/java/net/fabricmc/loom/processors/JarProcessor.java +++ b/src/main/java/net/fabricmc/loom/processors/JarProcessor.java @@ -26,12 +26,16 @@ package net.fabricmc.loom.processors; import java.io.File; -import org.gradle.api.Project; - public interface JarProcessor { - void setup(Project project); + void setup(); + /** + * Currently this is a destructive process that replaces the existing jar. + */ void process(File file); + /** + * Return true to make all jar processors run again, return false to use the existing results of jar processing. + */ boolean isInvalid(File file); } diff --git a/src/main/java/net/fabricmc/loom/processors/JarProcessorManager.java b/src/main/java/net/fabricmc/loom/processors/JarProcessorManager.java index 579296cb..ab0d86d3 100644 --- a/src/main/java/net/fabricmc/loom/processors/JarProcessorManager.java +++ b/src/main/java/net/fabricmc/loom/processors/JarProcessorManager.java @@ -25,37 +25,17 @@ package net.fabricmc.loom.processors; import java.io.File; -import java.util.ArrayList; -import java.util.Collections; import java.util.List; -import org.gradle.api.Project; - -import net.fabricmc.loom.util.accesswidener.AccessWidenerJarProcessor; -import net.fabricmc.loom.LoomGradleExtension; - public class JarProcessorManager { - private final Project project; - private final LoomGradleExtension extension; - private final List jarProcessors; - public JarProcessorManager(Project project) { - this.project = project; - this.extension = project.getExtensions().getByType(LoomGradleExtension.class); - jarProcessors = setupProcessors(); + public JarProcessorManager(List jarProcessors) { + this.jarProcessors = jarProcessors; } - //TODO possibly expand via an API? - private List setupProcessors() { - List jarProcessors = new ArrayList<>(); - - if (extension.accessWidener != null) { - jarProcessors.add(new AccessWidenerJarProcessor()); - } - - jarProcessors.forEach(jarProcessor -> jarProcessor.setup(project)); - return Collections.unmodifiableList(jarProcessors); + public void setupProcessors() { + jarProcessors.forEach(JarProcessor::setup); } public boolean active() { diff --git a/src/main/java/net/fabricmc/loom/processors/MinecraftProcessedProvider.java b/src/main/java/net/fabricmc/loom/processors/MinecraftProcessedProvider.java index af9eba24..6e4a4bb2 100644 --- a/src/main/java/net/fabricmc/loom/processors/MinecraftProcessedProvider.java +++ b/src/main/java/net/fabricmc/loom/processors/MinecraftProcessedProvider.java @@ -65,7 +65,7 @@ public class MinecraftProcessedProvider extends MinecraftMappedProvider { getProject().getRepositories().flatDir(repository -> repository.dir(getJarDirectory(getExtension().getProjectPersistentCache(), PROJECT_MAPPED_CLASSIFIER))); - getProject().getDependencies().add(Constants.MINECRAFT_NAMED, + getProject().getDependencies().add(Constants.Configurations.MINECRAFT_NAMED, getProject().getDependencies().module("net.minecraft:minecraft:" + getJarVersionString(PROJECT_MAPPED_CLASSIFIER))); } diff --git a/src/main/java/net/fabricmc/loom/providers/LaunchProvider.java b/src/main/java/net/fabricmc/loom/providers/LaunchProvider.java index 252847dc..3697874c 100644 --- a/src/main/java/net/fabricmc/loom/providers/LaunchProvider.java +++ b/src/main/java/net/fabricmc/loom/providers/LaunchProvider.java @@ -36,14 +36,19 @@ import java.util.List; import java.util.Map; import java.util.StringJoiner; import java.util.function.Consumer; +import java.util.stream.Collectors; import org.apache.commons.io.FileUtils; import org.gradle.api.Project; +import org.gradle.api.artifacts.Dependency; import net.fabricmc.loom.util.Constants; import net.fabricmc.loom.util.DependencyProvider; +import net.fabricmc.loom.util.RemappedConfigurationEntry; public class LaunchProvider extends DependencyProvider { + public Dependency annotationDependency; + public LaunchProvider(Project project) { super(project); } @@ -52,6 +57,7 @@ public class LaunchProvider extends DependencyProvider { public void provide(DependencyInfo dependency, Consumer postPopulationScheduler) throws IOException { final LaunchConfig launchConfig = new LaunchConfig() .property("fabric.development", "true") + .property("fabric.remapClasspathFile", getRemapClasspathFile().getAbsolutePath()) .property("log4j.configurationFile", getLog4jConfigFile().getAbsolutePath()) .property("client", "java.library.path", getExtension().getNativesDirectory().getAbsolutePath()) @@ -72,15 +78,21 @@ public class LaunchProvider extends DependencyProvider { writeLog4jConfig(); FileUtils.writeStringToFile(getExtension().getDevLauncherConfig(), launchConfig.asString(), StandardCharsets.UTF_8); - addDependency("net.fabricmc:dev-launch-injector:" + Constants.DEV_LAUNCH_INJECTOR_VERSION, "runtimeOnly"); - addDependency("net.minecrell:terminalconsoleappender:" + Constants.TERMINAL_CONSOLE_APPENDER_VERSION, "runtimeOnly"); - addDependency("org.jetbrains:annotations:" + Constants.JETBRAINS_ANNOTATIONS_VERSION, "compileOnly"); + addDependency(Constants.Dependencies.DEV_LAUNCH_INJECTOR + Constants.Dependencies.Versions.DEV_LAUNCH_INJECTOR, "runtimeOnly"); + addDependency(Constants.Dependencies.TERMINAL_CONSOLE_APPENDER + Constants.Dependencies.Versions.TERMINAL_CONSOLE_APPENDER, "runtimeOnly"); + annotationDependency = addDependency(Constants.Dependencies.JETBRAINS_ANNOTATIONS + Constants.Dependencies.Versions.JETBRAINS_ANNOTATIONS, "compileOnly"); + + postPopulationScheduler.accept(this::writeRemapClassPath); } private File getLog4jConfigFile() { return new File(getExtension().getDevLauncherConfig().getParentFile(), "log4j.xml"); } + private File getRemapClasspathFile() { + return new File(getExtension().getDevLauncherConfig().getParentFile(), "remapClasspath.txt"); + } + private void writeLog4jConfig() { try (InputStream is = LaunchProvider.class.getClassLoader().getResourceAsStream("log4j2.fabric.xml")) { Files.deleteIfExists(getLog4jConfigFile().toPath()); @@ -90,9 +102,33 @@ public class LaunchProvider extends DependencyProvider { } } + private void writeRemapClassPath() { + List inputConfigurations = new ArrayList<>(); + inputConfigurations.add(Constants.Configurations.MINECRAFT_DEPENDENCIES); + inputConfigurations.addAll(Constants.MOD_COMPILE_ENTRIES.stream().map(RemappedConfigurationEntry::getSourceConfiguration).collect(Collectors.toList())); + + List remapClasspath = new ArrayList<>(); + + for (String inputConfiguration : inputConfigurations) { + remapClasspath.addAll(getProject().getConfigurations().getByName(inputConfiguration).getFiles()); + } + + remapClasspath.add(getExtension().getMinecraftMappedProvider().getIntermediaryJar()); + + String str = remapClasspath.stream() + .map(File::getAbsolutePath) + .collect(Collectors.joining(File.pathSeparator)); + + try { + Files.write(getRemapClasspathFile().toPath(), str.getBytes(StandardCharsets.UTF_8)); + } catch (IOException e) { + throw new RuntimeException("Failed to generate remap classpath", e); + } + } + @Override public String getTargetConfig() { - return Constants.MINECRAFT_NAMED; + return Constants.Configurations.MINECRAFT_NAMED; } public static class LaunchConfig { diff --git a/src/main/java/net/fabricmc/loom/providers/MappingsProvider.java b/src/main/java/net/fabricmc/loom/providers/MappingsProvider.java index cbea98f6..21c4dff3 100644 --- a/src/main/java/net/fabricmc/loom/providers/MappingsProvider.java +++ b/src/main/java/net/fabricmc/loom/providers/MappingsProvider.java @@ -36,6 +36,7 @@ import java.nio.file.Paths; import java.nio.file.StandardCopyOption; import java.util.function.Consumer; +import com.google.common.base.Preconditions; import com.google.common.net.UrlEscapers; import org.apache.commons.io.FileUtils; import org.apache.tools.ant.util.StringUtils; @@ -44,19 +45,21 @@ import org.zeroturnaround.zip.FileSource; import org.zeroturnaround.zip.ZipEntrySource; import org.zeroturnaround.zip.ZipUtil; +import net.fabricmc.loom.LoomGradleExtension; +import net.fabricmc.loom.processors.JarProcessorManager; +import net.fabricmc.loom.processors.MinecraftProcessedProvider; import net.fabricmc.loom.util.Constants; +import net.fabricmc.loom.util.DeletingFileVisitor; import net.fabricmc.loom.util.DependencyProvider; import net.fabricmc.loom.util.DownloadUtil; import net.fabricmc.loom.util.srg.SrgMerger; +import net.fabricmc.loom.util.accesswidener.AccessWidenerJarProcessor; import net.fabricmc.mapping.reader.v2.TinyV2Factory; import net.fabricmc.mapping.tree.TinyTree; import net.fabricmc.stitch.Command; import net.fabricmc.stitch.commands.CommandProposeFieldNames; import net.fabricmc.stitch.commands.tinyv2.CommandMergeTinyV2; import net.fabricmc.stitch.commands.tinyv2.CommandReorderTinyV2; -import net.fabricmc.loom.processors.JarProcessorManager; -import net.fabricmc.loom.processors.MinecraftProcessedProvider; -import net.fabricmc.loom.util.DeletingFileVisitor; public class MappingsProvider extends DependencyProvider { public MinecraftMappedProvider mappedProvider; @@ -65,8 +68,10 @@ public class MappingsProvider extends DependencyProvider { public String minecraftVersion; public String mappingsVersion; - private Path mappingsDir; - private Path mappingsStepsDir; + private final Path mappingsDir; + private final Path mappingsStepsDir; + private Path intermediaryTiny; + private boolean hasRefreshed = false; // The mappings that gradle gives us private Path baseTinyMappings; // The mappings we use in practice @@ -77,6 +82,8 @@ public class MappingsProvider extends DependencyProvider { public MappingsProvider(Project project) { super(project); + mappingsDir = getExtension().getUserCache().toPath().resolve("mappings"); + mappingsStepsDir = mappingsDir.resolve("steps"); } public void clean() throws IOException { @@ -153,10 +160,17 @@ public class MappingsProvider extends DependencyProvider { SrgMerger.mergeSrg(getExtension().getMcpConfigProvider().getSrg().toPath(), tinyMappings.toPath(), tinyMappingsWithSrg); } - addDependency(tinyMappingsJar, Constants.MAPPINGS_FINAL); + addDependency(tinyMappingsJar, Constants.Configurations.MAPPINGS_FINAL); - JarProcessorManager processorManager = new JarProcessorManager(getProject()); - getExtension().setJarProcessorManager(processorManager); + LoomGradleExtension extension = getExtension(); + + if (extension.accessWidener != null) { + extension.addJarProcessor(new AccessWidenerJarProcessor(getProject())); + } + + JarProcessorManager processorManager = new JarProcessorManager(extension.getJarProcessors()); + extension.setJarProcessorManager(processorManager); + processorManager.setupProcessors(); if (processorManager.active()) { mappedProvider = new MinecraftProcessedProvider(getProject(), processorManager); @@ -178,14 +192,7 @@ public class MappingsProvider extends DependencyProvider { if (baseMappingsAreV2()) { // These are unmerged v2 mappings - - // Download and extract intermediary - String encodedMinecraftVersion = UrlEscapers.urlFragmentEscaper().escape(minecraftVersion); - String intermediaryArtifactUrl = getExtension().getIntermediaryUrl().apply(encodedMinecraftVersion); - Path intermediaryJar = mappingsStepsDir.resolve("v2-intermediary-" + minecraftVersion + ".jar"); - DownloadUtil.downloadIfChanged(new URL(intermediaryArtifactUrl), intermediaryJar.toFile(), project.getLogger()); - - mergeAndSaveMappings(project, intermediaryJar, yarnJar); + mergeAndSaveMappings(project, yarnJar); } else { // These are merged v1 mappings if (tinyMappings.exists()) { @@ -222,14 +229,15 @@ public class MappingsProvider extends DependencyProvider { Files.copy(jar.getPath("mappings/mappings.tiny"), extractTo, StandardCopyOption.REPLACE_EXISTING); } - private void mergeAndSaveMappings(Project project, Path unmergedIntermediaryJar, Path unmergedYarnJar) throws IOException { - Path unmergedIntermediary = Paths.get(mappingsStepsDir.toString(), "unmerged-intermediary.tiny"); - project.getLogger().info(":extracting " + unmergedIntermediaryJar.getFileName()); + private void extractIntermediary(Path intermediaryJar, Path intermediaryTiny) throws IOException { + getProject().getLogger().info(":extracting " + intermediaryJar.getFileName()); - try (FileSystem unmergedIntermediaryFs = FileSystems.newFileSystem(unmergedIntermediaryJar, (ClassLoader) null)) { - extractMappings(unmergedIntermediaryFs, unmergedIntermediary); + try (FileSystem unmergedIntermediaryFs = FileSystems.newFileSystem(intermediaryJar, (ClassLoader) null)) { + extractMappings(unmergedIntermediaryFs, intermediaryTiny); } + } + private void mergeAndSaveMappings(Project project, Path unmergedYarnJar) throws IOException { Path unmergedYarn = Paths.get(mappingsStepsDir.toString(), "unmerged-yarn.tiny"); project.getLogger().info(":extracting " + unmergedYarnJar.getFileName()); @@ -238,7 +246,7 @@ public class MappingsProvider extends DependencyProvider { } Path invertedIntermediary = Paths.get(mappingsStepsDir.toString(), "inverted-intermediary.tiny"); - reorderMappings(unmergedIntermediary, invertedIntermediary, "intermediary", "official"); + reorderMappings(getIntermediaryTiny(), invertedIntermediary, "intermediary", "official"); Path unorderedMergedMappings = Paths.get(mappingsStepsDir.toString(), "unordered-merged.tiny"); project.getLogger().info(":merging"); mergeMappings(invertedIntermediary, unmergedYarn, unorderedMergedMappings); @@ -283,11 +291,7 @@ public class MappingsProvider extends DependencyProvider { } private void initFiles() { - mappingsDir = getExtension().getUserCache().toPath().resolve("mappings"); - mappingsStepsDir = mappingsDir.resolve("steps"); - baseTinyMappings = mappingsDir.resolve(mappingsName + "-tiny-" + minecraftVersion + "-" + mappingsVersion + "-base"); - mappingsMixinExport = new File(getExtension().getProjectBuildCache(), "mixin-map-" + minecraftVersion + "-" + mappingsVersion + ".tiny"); } public void cleanFiles() { @@ -300,8 +304,6 @@ public class MappingsProvider extends DependencyProvider { Files.deleteIfExists(baseTinyMappings); } - mappingsMixinExport.delete(); - if (tinyMappings != null) { tinyMappings.delete(); } @@ -316,6 +318,33 @@ public class MappingsProvider extends DependencyProvider { @Override public String getTargetConfig() { - return Constants.MAPPINGS; + return Constants.Configurations.MAPPINGS; + } + + public Path getMappingsDir() { + return mappingsDir; + } + + public Path getIntermediaryTiny() throws IOException { + if (intermediaryTiny == null) { + minecraftVersion = getExtension().getMinecraftProvider().getMinecraftVersion(); + Preconditions.checkNotNull(minecraftVersion, "Minecraft version cannot be null"); + + intermediaryTiny = mappingsDir.resolve(String.format("intermediary-%s-v2.tiny", minecraftVersion)); + + if (!Files.exists(intermediaryTiny) || (isRefreshDeps() && !hasRefreshed)) { + hasRefreshed = true; + + // Download and extract intermediary + String encodedMinecraftVersion = UrlEscapers.urlFragmentEscaper().escape(minecraftVersion); + String intermediaryArtifactUrl = getExtension().getIntermediaryUrl().apply(encodedMinecraftVersion); + Path intermediaryJar = mappingsDir.resolve("v2-intermediary-" + minecraftVersion + ".jar"); + DownloadUtil.downloadIfChanged(new URL(intermediaryArtifactUrl), intermediaryJar.toFile(), getProject().getLogger()); + + extractIntermediary(intermediaryJar, intermediaryTiny); + } + } + + return intermediaryTiny; } } diff --git a/src/main/java/net/fabricmc/loom/providers/MinecraftLibraryProvider.java b/src/main/java/net/fabricmc/loom/providers/MinecraftLibraryProvider.java index 922eed6d..ed74ef29 100644 --- a/src/main/java/net/fabricmc/loom/providers/MinecraftLibraryProvider.java +++ b/src/main/java/net/fabricmc/loom/providers/MinecraftLibraryProvider.java @@ -55,7 +55,7 @@ public class MinecraftLibraryProvider { isClientOnly = true; } */ - project.getDependencies().add(Constants.MINECRAFT_DEPENDENCIES, project.getDependencies().module(library.getArtifactName())); + project.getDependencies().add(Constants.Configurations.MINECRAFT_DEPENDENCIES, project.getDependencies().module(library.getArtifactName())); } } } diff --git a/src/main/java/net/fabricmc/loom/providers/MinecraftMappedProvider.java b/src/main/java/net/fabricmc/loom/providers/MinecraftMappedProvider.java index 140859e2..545fde9a 100644 --- a/src/main/java/net/fabricmc/loom/providers/MinecraftMappedProvider.java +++ b/src/main/java/net/fabricmc/loom/providers/MinecraftMappedProvider.java @@ -141,7 +141,7 @@ public class MinecraftMappedProvider extends DependencyProvider { protected void addDependencies(DependencyInfo dependency, Consumer postPopulationScheduler) { getProject().getRepositories().flatDir(repository -> repository.dir(getJarDirectory(getExtension().getUserCache(), "mapped"))); - getProject().getDependencies().add(Constants.MINECRAFT_NAMED, + getProject().getDependencies().add(Constants.Configurations.MINECRAFT_NAMED, getProject().getDependencies().module("net.minecraft:minecraft:" + getJarVersionString("mapped"))); } @@ -173,6 +173,6 @@ public class MinecraftMappedProvider extends DependencyProvider { @Override public String getTargetConfig() { - return Constants.MINECRAFT_NAMED; + return Constants.Configurations.MINECRAFT_NAMED; } } diff --git a/src/main/java/net/fabricmc/loom/providers/MinecraftProvider.java b/src/main/java/net/fabricmc/loom/providers/MinecraftProvider.java index 2632081e..9cdd34f0 100644 --- a/src/main/java/net/fabricmc/loom/providers/MinecraftProvider.java +++ b/src/main/java/net/fabricmc/loom/providers/MinecraftProvider.java @@ -201,7 +201,7 @@ public class MinecraftProvider extends DependencyProvider { } } else { getProject().getLogger().debug("Downloading version manifests"); - DownloadUtil.downloadIfChanged(new URL("https://launchermeta.mojang.com/mc/game/version_manifest.json"), manifests, getProject().getLogger()); + DownloadUtil.downloadIfChanged(new URL(Constants.VERSION_MANIFESTS), manifests, getProject().getLogger()); } String versionManifest = Files.asCharSource(manifests, StandardCharsets.UTF_8).read(); @@ -444,6 +444,6 @@ public class MinecraftProvider extends DependencyProvider { @Override public String getTargetConfig() { - return Constants.MINECRAFT; + return Constants.Configurations.MINECRAFT; } } diff --git a/src/main/java/net/fabricmc/loom/task/MigrateMappingsTask.java b/src/main/java/net/fabricmc/loom/task/MigrateMappingsTask.java index a048d5a1..c3b1d264 100644 --- a/src/main/java/net/fabricmc/loom/task/MigrateMappingsTask.java +++ b/src/main/java/net/fabricmc/loom/task/MigrateMappingsTask.java @@ -43,6 +43,7 @@ import org.gradle.api.GradleException; import org.gradle.api.IllegalDependencyNotation; import org.gradle.api.JavaVersion; import org.gradle.api.Project; +import org.gradle.api.artifacts.Dependency; import org.gradle.api.plugins.JavaPluginConvention; import org.gradle.api.tasks.TaskAction; import org.gradle.api.tasks.options.Option; @@ -51,6 +52,7 @@ import net.fabricmc.loom.LoomGradleExtension; import net.fabricmc.loom.providers.MappingsProvider; import net.fabricmc.loom.providers.MinecraftMappedProvider; import net.fabricmc.loom.util.SourceRemapper; +import net.fabricmc.loom.util.mappings.MojangMappingsDependency; import net.fabricmc.lorenztiny.TinyMappingsJoiner; import net.fabricmc.mapping.tree.TinyMappingFactory; import net.fabricmc.mapping.tree.TinyTree; @@ -116,7 +118,16 @@ public class MigrateMappingsTask extends AbstractLoomTask { Set files; try { - files = project.getConfigurations().detachedConfiguration(project.getDependencies().create(mappings)).resolve(); + if (mappings.startsWith(MojangMappingsDependency.GROUP + ':' + MojangMappingsDependency.MODULE + ':') || mappings.startsWith("net.mojang.minecraft:mappings:")) { + if (!mappings.endsWith(":" + project.getExtensions().getByType(LoomGradleExtension.class).getMinecraftProvider().getMinecraftVersion())) { + throw new UnsupportedOperationException("Migrating Mojang mappings is currently only supported for the specified minecraft version"); + } + + files = new MojangMappingsDependency(project, getExtension()).resolve(); + } else { + Dependency dependency = project.getDependencies().create(mappings); + files = project.getConfigurations().detachedConfiguration(dependency).resolve(); + } } catch (IllegalDependencyNotation ignored) { project.getLogger().info("Could not locate mappings, presuming V2 Yarn"); diff --git a/src/main/java/net/fabricmc/loom/task/RemapJarTask.java b/src/main/java/net/fabricmc/loom/task/RemapJarTask.java index 6f157ff5..6c2a988c 100644 --- a/src/main/java/net/fabricmc/loom/task/RemapJarTask.java +++ b/src/main/java/net/fabricmc/loom/task/RemapJarTask.java @@ -32,6 +32,7 @@ import java.nio.file.Path; import java.util.LinkedHashSet; import java.util.Set; +import com.google.common.base.Preconditions; import org.gradle.api.Project; import org.gradle.api.file.RegularFileProperty; import org.gradle.api.provider.Property; @@ -104,17 +105,16 @@ public class RemapJarTask extends Jar { ); Path[] classpath = classpathFiles.stream().map(File::toPath).filter((p) -> !input.equals(p) && Files.exists(p)).toArray(Path[]::new); - File mixinMapFile = mappingsProvider.mappingsMixinExport; - Path mixinMapPath = mixinMapFile.toPath(); - TinyRemapper.Builder remapperBuilder = TinyRemapper.newRemapper(); remapperBuilder = remapperBuilder.withMappings(TinyRemapperMappingsHelper.create(extension.isForge() ? mappingsProvider.getMappingsWithSrg() : mappingsProvider.getMappings(), fromM, toM, false)); // FIXME: The mixin map is named->intermediary, but I think we need named->srg? - if (mixinMapFile.exists()) { + for (File mixinMapFile : extension.getAllMixinMappings()) { if ("intermediary".equals(toM)) { - remapperBuilder = remapperBuilder.withMappings(TinyUtils.createTinyMappingProvider(mixinMapPath, fromM, toM)); + if (mixinMapFile.exists()) { + remapperBuilder = remapperBuilder.withMappings(TinyUtils.createTinyMappingProvider(mixinMapFile.toPath(), fromM, toM)); + } } else { project.getLogger().error("Mixins in Forge projects are currently not supported."); } @@ -204,14 +204,13 @@ public class RemapJarTask extends Jar { jarRemapper.addMappings(TinyRemapperMappingsHelper.create(extension.isForge() ? mappingsProvider.getMappingsWithSrg() : mappingsProvider.getMappings(), fromM, toM, false)); } - File mixinMapFile = mappingsProvider.mappingsMixinExport; - Path mixinMapPath = mixinMapFile.toPath(); - - if (mixinMapFile.exists()) { + for (File mixinMapFile : extension.getAllMixinMappings()) { if ("intermediary".equals(toM)) { - jarRemapper.addMappings(TinyUtils.createTinyMappingProvider(mixinMapPath, fromM, toM)); - } else { - project.getLogger().error("Mixins in Forge projects are currently not supported."); + if (mixinMapFile.exists()) { + jarRemapper.addMappings(TinyUtils.createTinyMappingProvider(mixinMapFile.toPath(), fromM, toM)); + } else { + project.getLogger().error("Mixins in Forge projects are currently not supported."); + } } } @@ -227,7 +226,10 @@ public class RemapJarTask extends Jar { throw new RuntimeException("Failed to remap access widener"); } - return Pair.of(accessWidenerJarProcessor.getAccessWidenerPath(remapData.output), data); + String awPath = accessWidenerJarProcessor.getAccessWidenerPath(remapData.input); + Preconditions.checkNotNull(awPath, "Failed to find accessWidener in fabric.mod.json: " + remapData.input); + + return Pair.of(awPath, data); } return null; @@ -248,7 +250,8 @@ public class RemapJarTask extends Jar { } if (accessWidener != null) { - ZipUtil.replaceEntry(data.output.toFile(), accessWidener.getLeft(), accessWidener.getRight()); + boolean replaced = ZipUtil.replaceEntry(data.output.toFile(), accessWidener.getLeft(), accessWidener.getRight()); + Preconditions.checkArgument(replaced, "Failed to remap access widener"); } }); } diff --git a/src/main/java/net/fabricmc/loom/util/Constants.java b/src/main/java/net/fabricmc/loom/util/Constants.java index c12eb48c..c0906c02 100644 --- a/src/main/java/net/fabricmc/loom/util/Constants.java +++ b/src/main/java/net/fabricmc/loom/util/Constants.java @@ -27,18 +27,17 @@ package net.fabricmc.loom.util; import java.util.List; import com.google.common.collect.ImmutableList; +import org.objectweb.asm.Opcodes; public class Constants { - public static final String DEFAULT_FABRIC_CLIENT_TWEAKER = "net.fabricmc.loader.launch.FabricClientTweaker"; - public static final String DEFAULT_FABRIC_SERVER_TWEAKER = "net.fabricmc.loader.launch.FabricServerTweaker"; - public static final String LIBRARIES_BASE = "https://libraries.minecraft.net/"; public static final String RESOURCES_BASE = "http://resources.download.minecraft.net/"; + public static final String VERSION_MANIFESTS = "https://launchermeta.mojang.com/mc/game/version_manifest.json"; public static final String SYSTEM_ARCH = System.getProperty("os.arch").equals("64") ? "64" : "32"; - public static final String MOD_COMPILE_CLASSPATH = "modCompileClasspath"; - public static final String MOD_COMPILE_CLASSPATH_MAPPED = "modCompileClasspathMapped"; + public static final int ASM_VERSION = Opcodes.ASM9; + public static final List MOD_COMPILE_ENTRIES = ImmutableList.of( new RemappedConfigurationEntry("modCompile", "compile", true, "compile"), new RemappedConfigurationEntry("modApi", "api", true, "compile"), @@ -47,21 +46,73 @@ public class Constants { new RemappedConfigurationEntry("modCompileOnly", "compileOnly", true, "") ); - public static final String INCLUDE = "include"; - public static final String MINECRAFT = "minecraft"; - public static final String MINECRAFT_DEPENDENCIES = "minecraftLibraries"; - public static final String MINECRAFT_NAMED = "minecraftNamed"; - public static final String MAPPINGS = "mappings"; - public static final String MAPPINGS_FINAL = "mappingsFinal"; - public static final String MCP_CONFIG = "mcp"; - public static final String FORGE = "forge"; - public static final String FORGE_USERDEV = "forgeUserdev"; - public static final String FORGE_INSTALLER = "forgeInstaller"; - public static final String FORGE_UNIVERSAL = "forgeUniversal"; - public static final String FORGE_DEPENDENCIES = "forgeDependencies"; + private Constants() { + } - public static final String MIXIN_COMPILE_EXTENSIONS_VERSION = "0.3.1.5"; - public static final String DEV_LAUNCH_INJECTOR_VERSION = "0.2.1+build.8"; - public static final String TERMINAL_CONSOLE_APPENDER_VERSION = "1.2.0"; - public static final String JETBRAINS_ANNOTATIONS_VERSION = "19.0.0"; + /** + * Constants related to configurations. + */ + public static final class Configurations { + public static final String MOD_COMPILE_CLASSPATH = "modCompileClasspath"; + public static final String MOD_COMPILE_CLASSPATH_MAPPED = "modCompileClasspathMapped"; + public static final String INCLUDE = "include"; + public static final String MINECRAFT = "minecraft"; + public static final String MINECRAFT_DEPENDENCIES = "minecraftLibraries"; + public static final String MINECRAFT_NAMED = "minecraftNamed"; + public static final String MAPPINGS = "mappings"; + public static final String MAPPINGS_FINAL = "mappingsFinal"; + public static final String MCP_CONFIG = "mcp"; + public static final String FORGE = "forge"; + public static final String FORGE_USERDEV = "forgeUserdev"; + public static final String FORGE_INSTALLER = "forgeInstaller"; + public static final String FORGE_UNIVERSAL = "forgeUniversal"; + public static final String FORGE_DEPENDENCIES = "forgeDependencies"; + + private Configurations() { + } + } + + /** + * Constants related to dependencies. + */ + public static final class Dependencies { + public static final String MIXIN_COMPILE_EXTENSIONS = "net.fabricmc:fabric-mixin-compile-extensions:"; + public static final String DEV_LAUNCH_INJECTOR = "net.fabricmc:dev-launch-injector:"; + public static final String TERMINAL_CONSOLE_APPENDER = "net.minecrell:terminalconsoleappender:"; + public static final String JETBRAINS_ANNOTATIONS = "org.jetbrains:annotations:"; + + private Dependencies() { + } + + /** + * Constants for versions of dependencies. + */ + public static final class Versions { + public static final String MIXIN_COMPILE_EXTENSIONS = "0.3.2.6"; + public static final String DEV_LAUNCH_INJECTOR = "0.2.1+build.8"; + public static final String TERMINAL_CONSOLE_APPENDER = "1.2.0"; + public static final String JETBRAINS_ANNOTATIONS = "19.0.0"; + + private Versions() { + } + } + } + + public static final class MixinArguments { + public static final String IN_MAP_FILE_NAMED_INTERMEDIARY = "inMapFileNamedIntermediary"; + public static final String OUT_MAP_FILE_NAMED_INTERMEDIARY = "outMapFileNamedIntermediary"; + public static final String OUT_REFMAP_FILE = "outRefMapFile"; + public static final String DEFAULT_OBFUSCATION_ENV = "defaultObfuscationEnv"; + + private MixinArguments() { + } + } + + public static final class LaunchWrapper { + public static final String DEFAULT_FABRIC_CLIENT_TWEAKER = "net.fabricmc.loader.launch.FabricClientTweaker"; + public static final String DEFAULT_FABRIC_SERVER_TWEAKER = "net.fabricmc.loader.launch.FabricServerTweaker"; + + private LaunchWrapper() { + } + } } diff --git a/src/main/java/net/fabricmc/loom/util/DependencyProvider.java b/src/main/java/net/fabricmc/loom/util/DependencyProvider.java index 0a7ba787..10da3424 100644 --- a/src/main/java/net/fabricmc/loom/util/DependencyProvider.java +++ b/src/main/java/net/fabricmc/loom/util/DependencyProvider.java @@ -67,12 +67,12 @@ public abstract class DependencyProvider { addDependency(object, "compile"); } - public void addDependency(Object object, String target) { + public Dependency addDependency(Object object, String target) { if (object instanceof File) { object = project.files(object); } - project.getDependencies().add(target, object); + return project.getDependencies().add(target, object); } public void register(LoomDependencyManager dependencyManager) { @@ -133,6 +133,10 @@ public abstract class DependencyProvider { } public Set resolve() { + if (dependency instanceof SelfResolvingDependency) { + return ((SelfResolvingDependency) dependency).resolve(); + } + return sourceConfiguration.files(dependency); } @@ -171,12 +175,14 @@ public abstract class DependencyProvider { public static class FileDependencyInfo extends DependencyInfo { protected final Map classifierToFile = new HashMap<>(); + protected final Set resolvedFiles; protected final String group, name, version; FileDependencyInfo(Project project, SelfResolvingDependency dependency, Configuration configuration) { super(project, dependency, configuration); Set files = dependency.resolve(); + this.resolvedFiles = files; switch (files.size()) { case 0: //Don't think Gradle would ever let you do this throw new IllegalStateException("Empty dependency?"); @@ -259,5 +265,10 @@ public abstract class DependencyProvider { public String getResolvedDepString() { return getDepString(); } + + @Override + public Set resolve() { + return this.resolvedFiles; + } } } diff --git a/src/main/java/net/fabricmc/loom/util/FabricApiExtension.java b/src/main/java/net/fabricmc/loom/util/FabricApiExtension.java index 4a6f15a1..71cf0e62 100644 --- a/src/main/java/net/fabricmc/loom/util/FabricApiExtension.java +++ b/src/main/java/net/fabricmc/loom/util/FabricApiExtension.java @@ -92,8 +92,6 @@ public class FabricApiExtension { throw new RuntimeException("Failed to find artifact or version"); } - project.getLogger().lifecycle(artifact.getTextContent() + " : " + version.getTextContent()); - versionMap.put(artifact.getTextContent(), version.getTextContent()); } diff --git a/src/main/java/net/fabricmc/loom/util/LineNumberRemapper.java b/src/main/java/net/fabricmc/loom/util/LineNumberRemapper.java index 95fd976e..74cb0d6c 100644 --- a/src/main/java/net/fabricmc/loom/util/LineNumberRemapper.java +++ b/src/main/java/net/fabricmc/loom/util/LineNumberRemapper.java @@ -45,7 +45,6 @@ import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Opcodes; import net.fabricmc.loom.util.progress.ProgressLogger; @@ -124,7 +123,7 @@ public class LineNumberRemapper { ClassReader reader = new ClassReader(is); ClassWriter writer = new ClassWriter(0); - reader.accept(new LineNumberVisitor(Opcodes.ASM7, writer, lineMap.get(idx)), 0); + reader.accept(new LineNumberVisitor(Constants.ASM_VERSION, writer, lineMap.get(idx)), 0); Files.write(dst, writer.toByteArray()); } } diff --git a/src/main/java/net/fabricmc/loom/util/LoomDependencyManager.java b/src/main/java/net/fabricmc/loom/util/LoomDependencyManager.java index 3bcce7fa..59f90727 100644 --- a/src/main/java/net/fabricmc/loom/util/LoomDependencyManager.java +++ b/src/main/java/net/fabricmc/loom/util/LoomDependencyManager.java @@ -139,7 +139,7 @@ public class LoomDependencyManager { if (extension.getInstallerJson() == null) { //If we've not found the installer JSON we've probably skipped remapping Fabric loader, let's go looking project.getLogger().info("Searching through modCompileClasspath for installer JSON"); - final Configuration configuration = project.getConfigurations().getByName(Constants.MOD_COMPILE_CLASSPATH); + final Configuration configuration = project.getConfigurations().getByName(Constants.Configurations.MOD_COMPILE_CLASSPATH); for (File input : configuration.resolve()) { JsonObject jsonObject = ModProcessor.readInstallerJson(input, project); @@ -173,7 +173,7 @@ public class LoomDependencyManager { LoomGradleExtension extension = project.getExtensions().getByType(LoomGradleExtension.class); JsonObject libraries = jsonObject.get("libraries").getAsJsonObject(); - Configuration mcDepsConfig = project.getConfigurations().getByName(Constants.MINECRAFT_DEPENDENCIES); + Configuration mcDepsConfig = project.getConfigurations().getByName(Constants.Configurations.MINECRAFT_DEPENDENCIES); Configuration apDepsConfig = project.getConfigurations().getByName("annotationProcessor"); libraries.get("common").getAsJsonArray().forEach(jsonElement -> { diff --git a/src/main/java/net/fabricmc/loom/util/ModCompileRemapper.java b/src/main/java/net/fabricmc/loom/util/ModCompileRemapper.java index 37626517..640dd459 100644 --- a/src/main/java/net/fabricmc/loom/util/ModCompileRemapper.java +++ b/src/main/java/net/fabricmc/loom/util/ModCompileRemapper.java @@ -35,7 +35,6 @@ import org.gradle.api.artifacts.Configuration; import org.gradle.api.artifacts.Dependency; import org.gradle.api.artifacts.ModuleDependency; import org.gradle.api.artifacts.ResolvedArtifact; -import org.gradle.api.artifacts.component.ModuleComponentIdentifier; import org.gradle.api.artifacts.dsl.DependencyHandler; import org.gradle.api.artifacts.query.ArtifactResolutionQuery; import org.gradle.api.artifacts.result.ArtifactResult; @@ -66,25 +65,16 @@ public class ModCompileRemapper { List modDependencies = new ArrayList<>(); for (ResolvedArtifact artifact : sourceConfig.getResolvedConfiguration().getResolvedArtifacts()) { - String group; - String name; - String version; + // TODO: This collection doesn't appear to include FileCollection dependencies + // Might have to go based on the dependencies, rather than their resolved form? + // File dependencies use SelfResolvingDependency, which appears to be handled differently + String group = artifact.getModuleVersion().getId().getGroup(); + String name = artifact.getModuleVersion().getId().getName(); + String version = artifact.getModuleVersion().getId().getVersion(); String classifierSuffix = artifact.getClassifier() == null ? "" : (":" + artifact.getClassifier()); - if (artifact.getId().getComponentIdentifier() instanceof ModuleComponentIdentifier) { - group = ((ModuleComponentIdentifier) artifact.getId().getComponentIdentifier()).getGroup(); - name = ((ModuleComponentIdentifier) artifact.getId().getComponentIdentifier()).getModule(); - version = ((ModuleComponentIdentifier) artifact.getId().getComponentIdentifier()).getVersion(); - } else { - group = "net.fabricmc.synthetic"; - name = artifact.getId().getComponentIdentifier().getDisplayName().replace('.', '-').replace(" :", "-"); - version = "0.1.0"; - } - - final String notation = group + ":" + name + ":" + version + classifierSuffix; - - if (!isFabricMod(logger, artifact, notation)) { - addToRegularCompile(project, regularConfig, notation); + if (!isFabricMod(logger, artifact)) { + addToRegularCompile(project, regularConfig, artifact); continue; } @@ -122,12 +112,12 @@ public class ModCompileRemapper { /** * Checks if an artifact is a fabric mod, according to the presence of a fabric.mod.json. */ - private static boolean isFabricMod(Logger logger, ResolvedArtifact artifact, String notation) { + private static boolean isFabricMod(Logger logger, ResolvedArtifact artifact) { File input = artifact.getFile(); try (ZipFile zipFile = new ZipFile(input)) { if (zipFile.getEntry("fabric.mod.json") != null) { - logger.info("Found Fabric mod in modCompile: {}", notation); + logger.info("Found Fabric mod in modCompile: {}", artifact.getId()); return true; } @@ -137,10 +127,11 @@ public class ModCompileRemapper { } } - private static void addToRegularCompile(Project project, Configuration regularCompile, String notation) { - project.getLogger().info(":providing " + notation); + private static void addToRegularCompile(Project project, Configuration regularCompile, ResolvedArtifact artifact) { + project.getLogger().info(":providing " + artifact); DependencyHandler dependencies = project.getDependencies(); - Dependency dep = dependencies.module(notation); + Dependency dep = dependencies.module(artifact.getModuleVersion().toString() + + (artifact.getClassifier() == null ? "" : ':' + artifact.getClassifier())); // the owning module of the artifact if (dep instanceof ModuleDependency) { ((ModuleDependency) dep).setTransitive(false); diff --git a/src/main/java/net/fabricmc/loom/util/ModProcessor.java b/src/main/java/net/fabricmc/loom/util/ModProcessor.java index b5357cf1..1932f21f 100644 --- a/src/main/java/net/fabricmc/loom/util/ModProcessor.java +++ b/src/main/java/net/fabricmc/loom/util/ModProcessor.java @@ -33,6 +33,7 @@ import java.io.InputStreamReader; import java.io.StringWriter; import java.nio.charset.StandardCharsets; import java.nio.file.Path; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -50,11 +51,13 @@ import org.zeroturnaround.zip.ZipUtil; import org.zeroturnaround.zip.transform.StringZipEntryTransformer; import org.zeroturnaround.zip.transform.ZipEntryTransformerEntry; +import net.fabricmc.accesswidener.AccessWidener; +import net.fabricmc.accesswidener.AccessWidenerReader; +import net.fabricmc.accesswidener.AccessWidenerRemapper; +import net.fabricmc.accesswidener.AccessWidenerWriter; import net.fabricmc.loom.LoomGradleExtension; import net.fabricmc.loom.providers.MappingsProvider; import net.fabricmc.loom.providers.MinecraftMappedProvider; -import net.fabricmc.loom.util.accesswidener.AccessWidener; -import net.fabricmc.loom.util.accesswidener.AccessWidenerRemapper; import net.fabricmc.loom.processors.dependency.ModDependencyInfo; import net.fabricmc.tinyremapper.TinyRemapper; import net.fabricmc.tinyremapper.InputTag; @@ -68,9 +71,15 @@ public class ModProcessor { return; } + ArrayList remapList = new ArrayList<>(); + for (ModDependencyInfo info : processList) { - if (info.requiresRemapping() && info.getRemappedOutput().exists()) { - info.getRemappedOutput().delete(); + if (info.requiresRemapping()) { + if (info.getRemappedOutput().exists()) { + info.getRemappedOutput().delete(); + } + + remapList.add(info); } } @@ -78,12 +87,12 @@ public class ModProcessor { for (ModDependencyInfo info : processList) { if (!info.getRemappedOutput().exists()) { - throw new RuntimeException("Failed to remap mod" + info); + throw new RuntimeException("Failed to find remapped mod" + info); } + } - if (info.requiresRemapping()) { - stripNestedJars(info.getRemappedOutput()); - } + for (ModDependencyInfo info : remapList) { + stripNestedJars(info.getRemappedOutput()); } } @@ -102,13 +111,15 @@ public class ModProcessor { private static byte[] remapAccessWidener(byte[] input, Remapper remapper) { try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(input), StandardCharsets.UTF_8))) { AccessWidener accessWidener = new AccessWidener(); - accessWidener.read(bufferedReader); + AccessWidenerReader accessWidenerReader = new AccessWidenerReader(accessWidener); + accessWidenerReader.read(bufferedReader); AccessWidenerRemapper accessWidenerRemapper = new AccessWidenerRemapper(accessWidener, remapper, "named"); AccessWidener remapped = accessWidenerRemapper.remap(); + AccessWidenerWriter accessWidenerWriter = new AccessWidenerWriter(remapped); try (StringWriter writer = new StringWriter()) { - remapped.write(writer); + accessWidenerWriter.write(writer); return writer.toString().getBytes(StandardCharsets.UTF_8); } } catch (IOException e) { diff --git a/src/main/java/net/fabricmc/loom/util/NestedJars.java b/src/main/java/net/fabricmc/loom/util/NestedJars.java index 3ca54fa8..2d57c8c0 100644 --- a/src/main/java/net/fabricmc/loom/util/NestedJars.java +++ b/src/main/java/net/fabricmc/loom/util/NestedJars.java @@ -29,6 +29,7 @@ import java.io.IOException; import java.nio.file.Path; import java.util.ArrayList; import java.util.Collection; +import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Set; @@ -99,14 +100,20 @@ public class NestedJars { private static List getContainedJars(Project project) { List fileList = new ArrayList<>(); - ResolvedConfiguration configuration = project.getConfigurations().getByName(Constants.INCLUDE).getResolvedConfiguration(); - Set dependencies = configuration.getFirstLevelModuleDependencies(); + Configuration configuration = project.getConfigurations().getByName(Constants.Configurations.INCLUDE); + ResolvedConfiguration resolvedConfiguration = configuration.getResolvedConfiguration(); + Set dependencies = resolvedConfiguration.getFirstLevelModuleDependencies(); - for (ResolvedDependency dependency : dependencies) { + // Bit ugly doing this, id guess there is a better way but this works. + Set projectDeps = new HashSet<>(); + + for (Dependency dependency : configuration.getDependencies()) { if (dependency instanceof ProjectDependency) { ProjectDependency projectDependency = (ProjectDependency) dependency; Project dependencyProject = projectDependency.getDependencyProject(); + projectDeps.add(dependency.getGroup() + ":" + dependency.getName() + ":" + dependency.getVersion()); + // TODO change this to allow just normal jar tasks, so a project can have a none loom sub project Collection remapJarTasks = dependencyProject.getTasksByName("remapJar", false); Collection jarTasks = dependencyProject.getTasksByName("jar", false); @@ -118,6 +125,12 @@ public class NestedJars { fileList.add(((AbstractArchiveTask) task).getArchivePath()); } } + } + } + + for (ResolvedDependency dependency : dependencies) { + if (projectDeps.contains(dependency.getModuleGroup() + ":" + dependency.getModuleName() + ":" + dependency.getModuleVersion())) { + continue; } else { fileList.addAll(prepareForNesting( dependency @@ -147,7 +160,7 @@ public class NestedJars { public static List getRequiredTasks(Project project) { List remapTasks = new ArrayList<>(); - Configuration configuration = project.getConfigurations().getByName(Constants.INCLUDE); + Configuration configuration = project.getConfigurations().getByName(Constants.Configurations.INCLUDE); DependencySet dependencies = configuration.getDependencies(); for (Dependency dependency : dependencies) { @@ -211,6 +224,10 @@ public class NestedJars { jsonObject.addProperty("version", dependency.getModuleVersion()); jsonObject.addProperty("name", dependency.getModuleName()); + JsonObject custom = new JsonObject(); + custom.addProperty("fabric-loom:generated", true); + jsonObject.add("custom", custom); + return GSON.toJson(jsonObject); } diff --git a/src/main/java/net/fabricmc/loom/util/RunConfig.java b/src/main/java/net/fabricmc/loom/util/RunConfig.java index 801e504a..74c98e1b 100644 --- a/src/main/java/net/fabricmc/loom/util/RunConfig.java +++ b/src/main/java/net/fabricmc/loom/util/RunConfig.java @@ -113,7 +113,7 @@ public class RunConfig { if ("launchwrapper".equals(extension.getLoaderLaunchMethod())) { runConfig.mainClass = "net.minecraft.launchwrapper.Launch"; - runConfig.programArgs = "--tweakClass " + ("client".equals(mode) ? Constants.DEFAULT_FABRIC_CLIENT_TWEAKER : Constants.DEFAULT_FABRIC_SERVER_TWEAKER); + runConfig.programArgs = "--tweakClass " + ("client".equals(mode) ? Constants.LaunchWrapper.DEFAULT_FABRIC_CLIENT_TWEAKER : Constants.LaunchWrapper.DEFAULT_FABRIC_SERVER_TWEAKER); } else { runConfig.mainClass = "net.fabricmc.devlaunchinjector.Main"; runConfig.programArgs = ""; diff --git a/src/main/java/net/fabricmc/loom/util/SourceRemapper.java b/src/main/java/net/fabricmc/loom/util/SourceRemapper.java index f7f23237..1f901aea 100644 --- a/src/main/java/net/fabricmc/loom/util/SourceRemapper.java +++ b/src/main/java/net/fabricmc/loom/util/SourceRemapper.java @@ -30,16 +30,19 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; import java.util.List; +import java.util.Set; import java.util.function.Consumer; import org.cadixdev.lorenz.MappingSet; import org.cadixdev.mercury.Mercury; import org.cadixdev.mercury.remapper.MercuryRemapper; import org.gradle.api.Project; +import org.gradle.api.artifacts.Dependency; import org.zeroturnaround.zip.ZipUtil; import net.fabricmc.loom.LoomGradleExtension; import net.fabricmc.loom.providers.MappingsProvider; +import net.fabricmc.loom.providers.LaunchProvider; import net.fabricmc.loom.util.progress.ProgressLogger; import net.fabricmc.lorenztiny.TinyMappingsReader; import net.fabricmc.mapping.tree.TinyTree; @@ -176,6 +179,14 @@ public class SourceRemapper { m.getClassPath().add(extension.getMinecraftMappedProvider().getMappedJar().toPath()); m.getClassPath().add(extension.getMinecraftMappedProvider().getIntermediaryJar().toPath()); + Dependency annotationDependency = extension.getDependencyManager().getProvider(LaunchProvider.class).annotationDependency; + Set files = project.getConfigurations().getByName("compileOnly") + .files(annotationDependency); + + for (File file : files) { + m.getClassPath().add(file.toPath()); + } + m.getProcessors().add(MercuryRemapper.create(mappings)); return m; @@ -201,8 +212,9 @@ public class SourceRemapper { public static Mercury createMercuryWithClassPath(Project project, boolean toNamed) { Mercury m = new Mercury(); + m.setGracefulClasspathChecks(true); - for (File file : project.getConfigurations().getByName(Constants.MINECRAFT_DEPENDENCIES).getFiles()) { + for (File file : project.getConfigurations().getByName(Constants.Configurations.MINECRAFT_DEPENDENCIES).getFiles()) { m.getClassPath().add(file.toPath()); } diff --git a/src/main/java/net/fabricmc/loom/util/accesswidener/AccessWidener.java b/src/main/java/net/fabricmc/loom/util/accesswidener/AccessWidener.java deleted file mode 100644 index df061a69..00000000 --- a/src/main/java/net/fabricmc/loom/util/accesswidener/AccessWidener.java +++ /dev/null @@ -1,477 +0,0 @@ -/* - * 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.accesswidener; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.StringWriter; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Set; - -import org.objectweb.asm.Opcodes; - -import net.fabricmc.mappings.EntryTriple; - -public class AccessWidener { - public String namespace; - public Map classAccess = new HashMap<>(); - public Map methodAccess = new HashMap<>(); - public Map fieldAccess = new HashMap<>(); - private final Set classes = new LinkedHashSet<>(); - - public void read(BufferedReader reader) throws IOException { - String headerStr = reader.readLine(); - - if (headerStr == null) { - throw new RuntimeException("Cannot read empty or invalid access widener"); - } - - String[] header = headerStr.split("\\s+"); - - if (header.length != 3 || !header[0].equals("accessWidener")) { - throw new UnsupportedOperationException("Invalid access access widener header"); - } - - if (!header[1].equals("v1")) { - throw new RuntimeException(String.format("Unsupported access widener format (%s)", header[1])); - } - - if (namespace != null) { - if (!namespace.equals(header[2])) { - throw new RuntimeException(String.format("Namespace mismatch, expected %s got %s", namespace, header[2])); - } - } - - namespace = header[2]; - - String line; - - Set targets = new LinkedHashSet<>(); - - while ((line = reader.readLine()) != null) { - // Comment handling - int commentPos = line.indexOf('#'); - - if (commentPos >= 0) { - line = line.substring(0, commentPos).trim(); - } - - if (line.isEmpty()) continue; - - String[] split = line.split("\\s+"); - - if (split.length != 3 && split.length != 5) { - throw new RuntimeException(String.format("Invalid line (%s)", line)); - } - - String access = split[0]; - - targets.add(split[2].replaceAll("/", ".")); - - switch (split[1]) { - case "class": - if (split.length != 3) { - throw new RuntimeException(String.format("Expected (\tclass\t) got (%s)", line)); - } - - classAccess.put(split[2], applyAccess(access, classAccess.getOrDefault(split[2], ClassAccess.DEFAULT), null)); - break; - case "field": - if (split.length != 5) { - throw new RuntimeException(String.format("Expected (\tfield\t\t\t) got (%s)", line)); - } - - addOrMerge(fieldAccess, new EntryTriple(split[2], split[3], split[4]), access, FieldAccess.DEFAULT); - break; - case "method": - if (split.length != 5) { - throw new RuntimeException(String.format("Expected (\tmethod\t\t\t) got (%s)", line)); - } - - addOrMerge(methodAccess, new EntryTriple(split[2], split[3], split[4]), access, MethodAccess.DEFAULT); - break; - default: - throw new UnsupportedOperationException("Unsupported type " + split[1]); - } - } - - Set parentClasses = new LinkedHashSet<>(); - - //Also transform all parent classes - for (String clazz : targets) { - while (clazz.contains("$")) { - clazz = clazz.substring(0, clazz.lastIndexOf("$")); - parentClasses.add(clazz); - } - } - - classes.addAll(targets); - classes.addAll(parentClasses); - } - - // Could possibly be cleaner but should do its job for now - public void write(StringWriter writer) { - writer.write("accessWidener\tv1\t"); - writer.write(namespace); - writer.write("\n"); - - for (Map.Entry entry : classAccess.entrySet()) { - for (String s : getAccesses(entry.getValue())) { - writer.write(s); - writer.write("\tclass\t"); - writer.write(entry.getKey()); - writer.write("\n"); - } - } - - for (Map.Entry entry : methodAccess.entrySet()) { - writeEntry(writer, "method", entry.getKey(), entry.getValue()); - } - - for (Map.Entry entry : fieldAccess.entrySet()) { - writeEntry(writer, "field", entry.getKey(), entry.getValue()); - } - } - - private void writeEntry(StringWriter writer, String type, EntryTriple entryTriple, Access access) { - for (String s : getAccesses(access)) { - writer.write(s); - writer.write("\t"); - writer.write(type); - writer.write("\t"); - writer.write(entryTriple.getOwner()); - writer.write("\t"); - writer.write(entryTriple.getName()); - writer.write("\t"); - writer.write(entryTriple.getDesc()); - writer.write("\n"); - } - } - - private List getAccesses(Access access) { - List accesses = new ArrayList<>(); - - if (access == ClassAccess.ACCESSIBLE || access == MethodAccess.ACCESSIBLE || access == FieldAccess.ACCESSIBLE || access == MethodAccess.ACCESSIBLE_EXTENDABLE || access == ClassAccess.ACCESSIBLE_EXTENDABLE || access == FieldAccess.ACCESSIBLE_MUTABLE) { - accesses.add("accessible"); - } - - if (access == ClassAccess.EXTENDABLE || access == MethodAccess.EXTENDABLE || access == MethodAccess.ACCESSIBLE_EXTENDABLE || access == ClassAccess.ACCESSIBLE_EXTENDABLE) { - accesses.add("extendable"); - } - - if (access == FieldAccess.MUTABLE || access == FieldAccess.ACCESSIBLE_MUTABLE) { - accesses.add("mutable"); - } - - return accesses; - } - - void addOrMerge(Map map, EntryTriple entry, Access access) { - if (entry == null || access == null) { - throw new RuntimeException("Input entry or access is null"); - } - - Access merged = null; - - if (access instanceof ClassAccess) { - merged = ClassAccess.DEFAULT; - } else if (access instanceof MethodAccess) { - merged = MethodAccess.DEFAULT; - } else if (access instanceof FieldAccess) { - merged = FieldAccess.DEFAULT; - } - - merged = mergeAccess(merged, access); - - map.put(entry, merged); - } - - void addOrMerge(Map map, EntryTriple entry, String access, Access defaultAccess) { - if (entry == null || access == null) { - throw new RuntimeException("Input entry or access is null"); - } - - map.put(entry, applyAccess(access, map.getOrDefault(entry, defaultAccess), entry)); - } - - public void merge(AccessWidener other) { - if (namespace == null) { - namespace = other.namespace; - } else if (!namespace.equals(other.namespace)) { - throw new RuntimeException("Namespace mismatch"); - } - - for (Map.Entry entry : other.classAccess.entrySet()) { - if (classAccess.containsKey(entry.getKey())) { - classAccess.replace(entry.getKey(), mergeAccess(classAccess.get(entry.getKey()), entry.getValue())); - } else { - classAccess.put(entry.getKey(), entry.getValue()); - } - } - - for (Map.Entry entry : other.methodAccess.entrySet()) { - addOrMerge(methodAccess, entry.getKey(), entry.getValue()); - } - - for (Map.Entry entry : other.fieldAccess.entrySet()) { - addOrMerge(fieldAccess, entry.getKey(), entry.getValue()); - } - } - - private Access applyAccess(String input, Access access, EntryTriple entryTriple) { - switch (input.toLowerCase(Locale.ROOT)) { - case "accessible": - makeClassAccessible(entryTriple); - return access.makeAccessible(); - case "extendable": - makeClassExtendable(entryTriple); - return access.makeExtendable(); - case "mutable": - return access.makeMutable(); - default: - throw new UnsupportedOperationException("Unknown access type:" + input); - } - } - - private void makeClassAccessible(EntryTriple entryTriple) { - if (entryTriple == null) return; - classAccess.put(entryTriple.getOwner(), applyAccess("accessible", classAccess.getOrDefault(entryTriple.getOwner(), ClassAccess.DEFAULT), null)); - } - - private void makeClassExtendable(EntryTriple entryTriple) { - if (entryTriple == null) return; - classAccess.put(entryTriple.getOwner(), applyAccess("extendable", classAccess.getOrDefault(entryTriple.getOwner(), ClassAccess.DEFAULT), null)); - } - - private static Access mergeAccess(Access a, Access b) { - Access access = a; - - if (b == ClassAccess.ACCESSIBLE || b == MethodAccess.ACCESSIBLE || b == FieldAccess.ACCESSIBLE || b == MethodAccess.ACCESSIBLE_EXTENDABLE || b == ClassAccess.ACCESSIBLE_EXTENDABLE || b == FieldAccess.ACCESSIBLE_MUTABLE) { - access = access.makeAccessible(); - } - - if (b == ClassAccess.EXTENDABLE || b == MethodAccess.EXTENDABLE || b == MethodAccess.ACCESSIBLE_EXTENDABLE || b == ClassAccess.ACCESSIBLE_EXTENDABLE) { - access = access.makeExtendable(); - } - - if (b == FieldAccess.MUTABLE || b == FieldAccess.ACCESSIBLE_MUTABLE) { - access = access.makeMutable(); - } - - return access; - } - - public Access getClassAccess(String className) { - return classAccess.getOrDefault(className, ClassAccess.DEFAULT); - } - - public Access getFieldAccess(EntryTriple entryTriple) { - return fieldAccess.getOrDefault(entryTriple, FieldAccess.DEFAULT); - } - - public Access getMethodAccess(EntryTriple entryTriple) { - return methodAccess.getOrDefault(entryTriple, MethodAccess.DEFAULT); - } - - public Set getTargets() { - return classes; - } - - private static int makePublic(int i) { - return (i & ~(Opcodes.ACC_PRIVATE | Opcodes.ACC_PROTECTED)) | Opcodes.ACC_PUBLIC; - } - - private static int makeProtected(int i) { - if ((i & Opcodes.ACC_PUBLIC) != 0) { - // Return i if public - return i; - } - - return (i & ~(Opcodes.ACC_PRIVATE)) | Opcodes.ACC_PROTECTED; - } - - private static int makeFinalIfPrivate(int access, String name, int ownerAccess) { - // Dont make constructors final - if (name.equals("")) { - return access; - } - - // Skip interface and static methods - if ((ownerAccess & Opcodes.ACC_INTERFACE) != 0 || (access & Opcodes.ACC_STATIC) != 0) { - return access; - } - - if ((access & Opcodes.ACC_PRIVATE) != 0) { - return access | Opcodes.ACC_FINAL; - } - - return access; - } - - private static int removeFinal(int i) { - return i & ~Opcodes.ACC_FINAL; - } - - public interface Access extends AccessOperator { - Access makeAccessible(); - - Access makeExtendable(); - - Access makeMutable(); - } - - public enum ClassAccess implements Access { - DEFAULT((access, name, ownerAccess) -> access), - ACCESSIBLE((access, name, ownerAccess) -> makePublic(access)), - EXTENDABLE((access, name, ownerAccess) -> makePublic(removeFinal(access))), - ACCESSIBLE_EXTENDABLE((access, name, ownerAccess) -> makePublic(removeFinal(access))); - - private final AccessOperator operator; - - ClassAccess(AccessOperator operator) { - this.operator = operator; - } - - @Override - public Access makeAccessible() { - if (this == EXTENDABLE || this == ACCESSIBLE_EXTENDABLE) { - return ACCESSIBLE_EXTENDABLE; - } - - return ACCESSIBLE; - } - - @Override - public Access makeExtendable() { - if (this == ACCESSIBLE || this == ACCESSIBLE_EXTENDABLE) { - return ACCESSIBLE_EXTENDABLE; - } - - return EXTENDABLE; - } - - @Override - public Access makeMutable() { - throw new UnsupportedOperationException("Classes cannot be made mutable"); - } - - @Override - public int apply(int access, String targetName, int ownerAccess) { - return operator.apply(access, targetName, ownerAccess); - } - } - - public enum MethodAccess implements Access { - DEFAULT((access, name, ownerAccess) -> access), - ACCESSIBLE((access, name, ownerAccess) -> makePublic(makeFinalIfPrivate(access, name, ownerAccess))), - EXTENDABLE((access, name, ownerAccess) -> makeProtected(removeFinal(access))), - ACCESSIBLE_EXTENDABLE((access, name, owner) -> makePublic(removeFinal(access))); - - private final AccessOperator operator; - - MethodAccess(AccessOperator operator) { - this.operator = operator; - } - - @Override - public Access makeAccessible() { - if (this == EXTENDABLE || this == ACCESSIBLE_EXTENDABLE) { - return ACCESSIBLE_EXTENDABLE; - } - - return ACCESSIBLE; - } - - @Override - public Access makeExtendable() { - if (this == ACCESSIBLE || this == ACCESSIBLE_EXTENDABLE) { - return ACCESSIBLE_EXTENDABLE; - } - - return EXTENDABLE; - } - - @Override - public Access makeMutable() { - throw new UnsupportedOperationException("Methods cannot be made mutable"); - } - - @Override - public int apply(int access, String targetName, int ownerAccess) { - return operator.apply(access, targetName, ownerAccess); - } - } - - public enum FieldAccess implements Access { - DEFAULT((access, name, ownerAccess) -> access), - ACCESSIBLE((access, name, ownerAccess) -> makePublic(access)), - MUTABLE((access, name, ownerAccess) -> removeFinal(access)), - ACCESSIBLE_MUTABLE((access, name, ownerAccess) -> makePublic(removeFinal(access))); - - private final AccessOperator operator; - - FieldAccess(AccessOperator operator) { - this.operator = operator; - } - - @Override - public Access makeAccessible() { - if (this == MUTABLE || this == ACCESSIBLE_MUTABLE) { - return ACCESSIBLE_MUTABLE; - } - - return ACCESSIBLE; - } - - @Override - public Access makeExtendable() { - throw new UnsupportedOperationException("Fields cannot be made extendable"); - } - - @Override - public Access makeMutable() { - if (this == ACCESSIBLE || this == ACCESSIBLE_MUTABLE) { - return ACCESSIBLE_MUTABLE; - } - - return MUTABLE; - } - - @Override - public int apply(int access, String targetName, int ownerAccess) { - return operator.apply(access, targetName, ownerAccess); - } - } - - @FunctionalInterface - public interface AccessOperator { - int apply(int access, String targetName, int ownerAccess); - } -} diff --git a/src/main/java/net/fabricmc/loom/util/accesswidener/AccessWidenerJarProcessor.java b/src/main/java/net/fabricmc/loom/util/accesswidener/AccessWidenerJarProcessor.java index ff2cc2b4..40e20a80 100644 --- a/src/main/java/net/fabricmc/loom/util/accesswidener/AccessWidenerJarProcessor.java +++ b/src/main/java/net/fabricmc/loom/util/accesswidener/AccessWidenerJarProcessor.java @@ -41,29 +41,35 @@ import org.gradle.api.Project; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.FieldVisitor; -import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Opcodes; import org.objectweb.asm.commons.Remapper; import org.zeroturnaround.zip.ZipUtil; import org.zeroturnaround.zip.transform.ByteArrayZipEntryTransformer; import org.zeroturnaround.zip.transform.ZipEntryTransformer; import org.zeroturnaround.zip.transform.ZipEntryTransformerEntry; -import net.fabricmc.mappings.EntryTriple; +import net.fabricmc.accesswidener.AccessWidener; +import net.fabricmc.accesswidener.AccessWidenerRemapper; +import net.fabricmc.accesswidener.AccessWidenerReader; +import net.fabricmc.accesswidener.AccessWidenerVisitor; +import net.fabricmc.accesswidener.AccessWidenerWriter; import net.fabricmc.loom.LoomGradleExtension; -import net.fabricmc.loom.util.Checksum; import net.fabricmc.loom.processors.JarProcessor; +import net.fabricmc.loom.util.Constants; +import net.fabricmc.loom.util.Checksum; import net.fabricmc.tinyremapper.TinyRemapper; public class AccessWidenerJarProcessor implements JarProcessor { private AccessWidener accessWidener = new AccessWidener(); - private Project project; + private AccessWidenerReader accessWidenerReader = new AccessWidenerReader(accessWidener); + private final Project project; private byte[] inputHash; - @Override - public void setup(Project project) { + public AccessWidenerJarProcessor(Project project) { this.project = project; + } + + @Override + public void setup() { LoomGradleExtension loomGradleExtension = project.getExtensions().getByType(LoomGradleExtension.class); if (!loomGradleExtension.accessWidener.exists()) { @@ -73,13 +79,13 @@ public class AccessWidenerJarProcessor implements JarProcessor { inputHash = Checksum.sha256(loomGradleExtension.accessWidener); try (BufferedReader reader = new BufferedReader(new FileReader(loomGradleExtension.accessWidener))) { - accessWidener.read(reader); + accessWidenerReader.read(reader); } catch (IOException e) { throw new RuntimeException("Failed to read project access widener file"); } //Remap accessWidener if its not named, allows for AE's to be written in intermediary - if (!accessWidener.namespace.equals("named")) { + if (!accessWidener.getNamespace().equals("named")) { try { TinyRemapper tinyRemapper = loomGradleExtension.getMinecraftMappedProvider().getTinyRemapper("srg", "named"); tinyRemapper.readClassPath(loomGradleExtension.getMinecraftMappedProvider().getRemapClasspath()); @@ -113,10 +119,11 @@ public class AccessWidenerJarProcessor implements JarProcessor { protected byte[] transform(ZipEntry zipEntry, byte[] input) { ClassReader reader = new ClassReader(input); ClassWriter writer = new ClassWriter(0); + ClassVisitor classVisitor = AccessWidenerVisitor.createClassVisitor(Constants.ASM_VERSION, writer, accessWidener); project.getLogger().lifecycle("Applying access widener to " + className); - reader.accept(new AccessTransformer(writer), 0); + reader.accept(classVisitor, 0); return writer.toByteArray(); } }; @@ -142,9 +149,10 @@ public class AccessWidenerJarProcessor implements JarProcessor { public byte[] getRemappedAccessWidener(Remapper asmRemapper) throws IOException { AccessWidenerRemapper remapper = new AccessWidenerRemapper(accessWidener, asmRemapper, "intermediary"); AccessWidener remapped = remapper.remap(); + AccessWidenerWriter accessWidenerWriter = new AccessWidenerWriter(remapped); try (StringWriter writer = new StringWriter()) { - remapped.write(writer); + accessWidenerWriter.write(writer); return writer.toString().getBytes(); } } @@ -175,78 +183,4 @@ public class AccessWidenerJarProcessor implements JarProcessor { return !Arrays.equals(inputHash, hash); // TODO how do we know if the current jar as the correct access applied? save the hash of the input? } - - private class AccessTransformer extends ClassVisitor { - private String className; - private int classAccess; - - private AccessTransformer(ClassVisitor classVisitor) { - super(Opcodes.ASM7, classVisitor); - } - - @Override - public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { - className = name; - classAccess = access; - super.visit( - version, - accessWidener.getClassAccess(name).apply(access, name, classAccess), - name, - signature, - superName, - interfaces - ); - } - - @Override - public void visitInnerClass(String name, String outerName, String innerName, int access) { - super.visitInnerClass( - name, - outerName, - innerName, - accessWidener.getClassAccess(name).apply(access, name, classAccess) - ); - } - - @Override - public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) { - return super.visitField( - accessWidener.getFieldAccess(new EntryTriple(className, name, descriptor)).apply(access, name, classAccess), - name, - descriptor, - signature, - value - ); - } - - @Override - public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { - return new AccessWidenerMethodVisitor(super.visitMethod( - accessWidener.getMethodAccess(new EntryTriple(className, name, descriptor)).apply(access, name, classAccess), - name, - descriptor, - signature, - exceptions - )); - } - - private class AccessWidenerMethodVisitor extends MethodVisitor { - AccessWidenerMethodVisitor(MethodVisitor methodVisitor) { - super(Opcodes.ASM7, methodVisitor); - } - - @Override - public void visitMethodInsn(int opcode, String owner, String name, String descriptor, boolean isInterface) { - if (opcode == Opcodes.INVOKESPECIAL && owner.equals(className) && !name.equals("")) { - AccessWidener.Access methodAccess = accessWidener.getMethodAccess(new EntryTriple(owner, name, descriptor)); - - if (methodAccess != AccessWidener.MethodAccess.DEFAULT) { - opcode = Opcodes.INVOKEVIRTUAL; - } - } - - super.visitMethodInsn(opcode, owner, name, descriptor, isInterface); - } - } - } } diff --git a/src/main/java/net/fabricmc/loom/util/accesswidener/AccessWidenerRemapper.java b/src/main/java/net/fabricmc/loom/util/accesswidener/AccessWidenerRemapper.java deleted file mode 100644 index 20dbf5f1..00000000 --- a/src/main/java/net/fabricmc/loom/util/accesswidener/AccessWidenerRemapper.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * 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.accesswidener; - -import java.util.Map; - -import org.objectweb.asm.commons.Remapper; - -import net.fabricmc.mappings.EntryTriple; - -public class AccessWidenerRemapper { - private final AccessWidener input; - private final String to; - private final Remapper remapper; - - public AccessWidenerRemapper(AccessWidener input, Remapper remapper, String to) { - this.input = input; - this.to = to; - this.remapper = remapper; - } - - public AccessWidener remap() { - // Dont remap if we dont need to - if (input.namespace.equals(to)) { - return input; - } - - AccessWidener remapped = new AccessWidener(); - remapped.namespace = to; - - for (Map.Entry entry : input.classAccess.entrySet()) { - remapped.classAccess.put(remapper.map(entry.getKey()), entry.getValue()); - } - - for (Map.Entry entry : input.methodAccess.entrySet()) { - remapped.addOrMerge(remapped.methodAccess, remapMethod(entry.getKey()), entry.getValue()); - } - - for (Map.Entry entry : input.fieldAccess.entrySet()) { - remapped.addOrMerge(remapped.fieldAccess, remapField(entry.getKey()), entry.getValue()); - } - - return remapped; - } - - private EntryTriple remapMethod(EntryTriple entryTriple) { - return new EntryTriple( - remapper.map(entryTriple.getOwner()), - remapper.mapMethodName(entryTriple.getOwner(), entryTriple.getName(), entryTriple.getDesc()), - remapper.mapDesc(entryTriple.getDesc()) - ); - } - - private EntryTriple remapField(EntryTriple entryTriple) { - return new EntryTriple( - remapper.map(entryTriple.getOwner()), - remapper.mapFieldName(entryTriple.getOwner(), entryTriple.getName(), entryTriple.getDesc()), - remapper.mapDesc(entryTriple.getDesc()) - ); - } -} diff --git a/src/main/java/net/fabricmc/loom/util/mappings/MojangMappingsDependency.java b/src/main/java/net/fabricmc/loom/util/mappings/MojangMappingsDependency.java new file mode 100644 index 00000000..b84d8d2b --- /dev/null +++ b/src/main/java/net/fabricmc/loom/util/mappings/MojangMappingsDependency.java @@ -0,0 +1,274 @@ +/* + * 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.mappings; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.StringWriter; +import java.io.Writer; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Collections; +import java.util.Set; +import java.util.function.Consumer; + +import org.cadixdev.lorenz.MappingSet; +import org.cadixdev.lorenz.io.TextMappingsWriter; +import org.cadixdev.lorenz.io.proguard.ProGuardReader; +import org.cadixdev.lorenz.model.ClassMapping; +import org.cadixdev.lorenz.model.FieldMapping; +import org.cadixdev.lorenz.model.InnerClassMapping; +import org.cadixdev.lorenz.model.MethodMapping; +import org.cadixdev.lorenz.model.TopLevelClassMapping; +import org.gradle.api.Project; +import org.gradle.api.artifacts.Dependency; +import org.gradle.api.artifacts.SelfResolvingDependency; +import org.gradle.api.tasks.TaskDependency; +import org.zeroturnaround.zip.ByteSource; +import org.zeroturnaround.zip.ZipEntrySource; +import org.zeroturnaround.zip.ZipUtil; + +import net.fabricmc.loom.LoomGradleExtension; +import net.fabricmc.loom.util.DownloadUtil; +import net.fabricmc.loom.util.MinecraftVersionInfo; +import net.fabricmc.lorenztiny.TinyMappingsReader; +import net.fabricmc.mapping.tree.TinyMappingFactory; + +public class MojangMappingsDependency implements SelfResolvingDependency { + public static final String GROUP = "net.minecraft"; + public static final String MODULE = "mappings"; + // Keys in dependency manifest + private static final String MANIFEST_CLIENT_MAPPINGS = "client_mappings"; + private static final String MANIFEST_SERVER_MAPPINGS = "server_mappings"; + + private final Project project; + private final LoomGradleExtension extension; + + public MojangMappingsDependency(Project project, LoomGradleExtension extension) { + this.project = project; + this.extension = extension; + } + + @Override + public Set resolve() { + Path mappingsDir = extension.getMappingsProvider().getMappingsDir(); + Path mappingsFile = mappingsDir.resolve(String.format("%s.%s-%s.tiny", GROUP, MODULE, getVersion())); + Path clientMappings = mappingsDir.resolve(String.format("%s.%s-%s-client.map", GROUP, MODULE, getVersion())); + Path serverMappings = mappingsDir.resolve(String.format("%s.%s-%s-server.map", GROUP, MODULE, getVersion())); + + if (!Files.exists(mappingsFile) || project.getGradle().getStartParameter().isRefreshDependencies()) { + MappingSet mappingSet; + + try { + mappingSet = getMappingsSet(clientMappings, serverMappings); + + try (Writer writer = new StringWriter()) { + new TinyWriter(writer, "intermediary", "named").write(mappingSet); + Files.deleteIfExists(mappingsFile); + + ZipUtil.pack(new ZipEntrySource[] { + new ByteSource("mappings/mappings.tiny", writer.toString().getBytes(StandardCharsets.UTF_8)) + }, mappingsFile.toFile()); + } + } catch (IOException e) { + throw new RuntimeException("Failed to resolve Mojang mappings", e); + } + } + + try (BufferedReader clientBufferedReader = Files.newBufferedReader(clientMappings, StandardCharsets.UTF_8)) { + project.getLogger().warn("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); + project.getLogger().warn("Using of the official minecraft mappings is at your own risk!"); + project.getLogger().warn("Please make sure to read and understand the following license:"); + project.getLogger().warn("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); + String line; + + while ((line = clientBufferedReader.readLine()).startsWith("#")) { + project.getLogger().warn(line); + } + + project.getLogger().warn("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); + } catch (IOException e) { + throw new RuntimeException("Failed to read client mappings", e); + } + + return Collections.singleton(mappingsFile.toFile()); + } + + private MappingSet getMappingsSet(Path clientMappings, Path serverMappings) throws IOException { + MinecraftVersionInfo versionInfo = extension.getMinecraftProvider().getVersionInfo(); + + if (versionInfo.downloads.get(MANIFEST_CLIENT_MAPPINGS) == null) { + throw new RuntimeException("Failed to find official mojang mappings for " + getVersion()); + } + + String clientMappingsUrl = versionInfo.downloads.get(MANIFEST_CLIENT_MAPPINGS).url; + String serverMappingsUrl = versionInfo.downloads.get(MANIFEST_SERVER_MAPPINGS).url; + + DownloadUtil.downloadIfChanged(new URL(clientMappingsUrl), clientMappings.toFile(), project.getLogger()); + DownloadUtil.downloadIfChanged(new URL(serverMappingsUrl), serverMappings.toFile(), project.getLogger()); + + MappingSet mappings = MappingSet.create(); + + try (BufferedReader clientBufferedReader = Files.newBufferedReader(clientMappings, StandardCharsets.UTF_8); + BufferedReader serverBufferedReader = Files.newBufferedReader(serverMappings, StandardCharsets.UTF_8)) { + try (ProGuardReader proGuardReaderClient = new ProGuardReader(clientBufferedReader); + ProGuardReader proGuardReaderServer = new ProGuardReader(serverBufferedReader)) { + proGuardReaderClient.read(mappings); + proGuardReaderServer.read(mappings); + } + } + + MappingSet officialToNamed = mappings.reverse(); + MappingSet intermediaryToOfficial; + + try (BufferedReader reader = Files.newBufferedReader(extension.getMappingsProvider().getIntermediaryTiny(), StandardCharsets.UTF_8)) { + intermediaryToOfficial = new TinyMappingsReader(TinyMappingFactory.loadWithDetection(reader), "intermediary", "official").read(); + } + + MappingSet intermediaryToMojang = MappingSet.create(); + + // Merging. Don't use MappingSet#merge + iterateClasses(intermediaryToOfficial, inputMappings -> { + officialToNamed.getClassMapping(inputMappings.getFullDeobfuscatedName()) + .ifPresent(namedClass -> { + ClassMapping mojangClassMapping = intermediaryToMojang.getOrCreateClassMapping(inputMappings.getFullObfuscatedName()) + .setDeobfuscatedName(namedClass.getFullDeobfuscatedName()); + + for (FieldMapping fieldMapping : inputMappings .getFieldMappings()) { + namedClass.getFieldMapping(fieldMapping.getDeobfuscatedName()) + .ifPresent(namedField -> { + mojangClassMapping.getOrCreateFieldMapping(fieldMapping.getSignature()) + .setDeobfuscatedName(namedField.getDeobfuscatedName()); + }); + } + + for (MethodMapping methodMapping : inputMappings .getMethodMappings()) { + namedClass.getMethodMapping(methodMapping.getDeobfuscatedSignature()) + .ifPresent(namedMethod -> { + mojangClassMapping.getOrCreateMethodMapping(methodMapping.getSignature()) + .setDeobfuscatedName(namedMethod.getDeobfuscatedName()); + }); + } + }); + }); + + return intermediaryToMojang; + } + + @Override + public Set resolve(boolean transitive) { + return resolve(); + } + + @Override + public TaskDependency getBuildDependencies() { + return task -> Collections.emptySet(); + } + + @Override + public String getGroup() { + return GROUP; + } + + @Override + public String getName() { + return MODULE; + } + + @Override + public String getVersion() { + return extension.getMinecraftProvider().getMinecraftVersion(); + } + + @Override + public boolean contentEquals(Dependency dependency) { + if (dependency instanceof MojangMappingsDependency) { + return ((MojangMappingsDependency) dependency).extension.getMinecraftProvider().getMinecraftVersion().equals(getVersion()); + } + + return false; + } + + @Override + public Dependency copy() { + return new MojangMappingsDependency(project, extension); + } + + @Override + public String getReason() { + return null; + } + + @Override + public void because(String s) { + } + + private static void iterateClasses(MappingSet mappings, Consumer> consumer) { + for (TopLevelClassMapping classMapping : mappings.getTopLevelClassMappings()) { + iterateClass(classMapping, consumer); + } + } + + private static void iterateClass(ClassMapping classMapping, Consumer> consumer) { + consumer.accept(classMapping); + + for (InnerClassMapping innerClassMapping : classMapping.getInnerClassMappings()) { + iterateClass(innerClassMapping, consumer); + } + } + + private static class TinyWriter extends TextMappingsWriter { + private final String namespaceFrom; + private final String namespaceTo; + + protected TinyWriter(Writer writer, String namespaceFrom, String namespaceTo) { + super(writer); + this.namespaceFrom = namespaceFrom; + this.namespaceTo = namespaceTo; + } + + @Override + public void write(MappingSet mappings) { + writer.println("tiny\t2\t0\t" + namespaceFrom + "\t" + namespaceTo); + + iterateClasses(mappings, classMapping -> { + writer.println("c\t" + classMapping.getFullObfuscatedName() + "\t" + classMapping.getFullDeobfuscatedName()); + + for (FieldMapping fieldMapping : classMapping.getFieldMappings()) { + fieldMapping.getType().ifPresent(fieldType -> { + writer.println("\tf\t" + fieldType + "\t" + fieldMapping.getObfuscatedName() + "\t" + fieldMapping.getDeobfuscatedName()); + }); + } + + for (MethodMapping methodMapping : classMapping.getMethodMappings()) { + writer.println("\tm\t" + methodMapping.getSignature().getDescriptor() + "\t" + methodMapping.getObfuscatedName() + "\t" + methodMapping.getDeobfuscatedName()); + } + }); + } + } +} diff --git a/src/main/java/net/fabricmc/loom/util/mixin/AnnotationProcessorInvoker.java b/src/main/java/net/fabricmc/loom/util/mixin/AnnotationProcessorInvoker.java index 8daa0dda..2d7934d7 100644 --- a/src/main/java/net/fabricmc/loom/util/mixin/AnnotationProcessorInvoker.java +++ b/src/main/java/net/fabricmc/loom/util/mixin/AnnotationProcessorInvoker.java @@ -72,10 +72,10 @@ public abstract class AnnotationProcessorInvoker { try { LoomGradleExtension extension = project.getExtensions().getByType(LoomGradleExtension.class); Map args = new HashMap() {{ - put("inMapFileNamedIntermediary", extension.getMappingsProvider().tinyMappings.getCanonicalPath()); - put("outMapFileNamedIntermediary", extension.getMappingsProvider().mappingsMixinExport.getCanonicalPath()); - put("outRefMapFile", getRefmapDestination(task, extension)); - put("defaultObfuscationEnv", "named:intermediary"); + put(Constants.MixinArguments.IN_MAP_FILE_NAMED_INTERMEDIARY, extension.getMappingsProvider().tinyMappings.getCanonicalPath()); + put(Constants.MixinArguments.OUT_MAP_FILE_NAMED_INTERMEDIARY, extension.getNextMixinMappings().getCanonicalPath()); + put(Constants.MixinArguments.OUT_REFMAP_FILE, getRefmapDestination(task, extension)); + put(Constants.MixinArguments.DEFAULT_OBFUSCATION_ENV, "named:intermediary"); }}; project.getLogger().debug("Outputting refmap to dir: " + getDestinationDir(task) + " for compile task: " + task); @@ -94,14 +94,14 @@ public abstract class AnnotationProcessorInvoker { project.getLogger().info("Adding mixin to classpath of AP config: " + processorConfig.getName()); // Pass named MC classpath to mixin AP classpath processorConfig.extendsFrom( - configs.getByName(Constants.MINECRAFT_NAMED), - configs.getByName(Constants.MOD_COMPILE_CLASSPATH_MAPPED), - configs.getByName(Constants.MAPPINGS_FINAL) + configs.getByName(Constants.Configurations.MINECRAFT_NAMED), + configs.getByName(Constants.Configurations.MOD_COMPILE_CLASSPATH_MAPPED), + configs.getByName(Constants.Configurations.MAPPINGS_FINAL) ); // Add Mixin and mixin extensions (fabric-mixin-compile-extensions pulls mixin itself too) project.getDependencies().add(processorConfig.getName(), - "net.fabricmc:fabric-mixin-compile-extensions:" + Constants.MIXIN_COMPILE_EXTENSIONS_VERSION); + Constants.Dependencies.MIXIN_COMPILE_EXTENSIONS + Constants.Dependencies.Versions.MIXIN_COMPILE_EXTENSIONS); } } diff --git a/src/main/resources/eclipse_run_config_template.xml b/src/main/resources/eclipse_run_config_template.xml index c55b7b72..c8697299 100644 --- a/src/main/resources/eclipse_run_config_template.xml +++ b/src/main/resources/eclipse_run_config_template.xml @@ -1,7 +1,7 @@ - + @@ -12,5 +12,5 @@ - + diff --git a/src/test/groovy/net/fabricmc/loom/BuildUtils.groovy b/src/test/groovy/net/fabricmc/loom/BuildUtils.groovy index bb2ca787..9a3083d6 100644 --- a/src/test/groovy/net/fabricmc/loom/BuildUtils.groovy +++ b/src/test/groovy/net/fabricmc/loom/BuildUtils.groovy @@ -3,7 +3,7 @@ package net.fabricmc.loom /** * Created by Mitchell Skaggs on 6/12/2019. */ -static String genBuildFile() { +static String genBuildFile(String mappingsDep = "\"net.fabricmc:yarn:\${project.yarn_mappings}\"") { """ plugins { id 'fabric-loom' @@ -23,7 +23,7 @@ minecraft { dependencies { //to change the versions see the gradle.properties file minecraft "com.mojang:minecraft:\${project.minecraft_version}" - mappings "net.fabricmc:yarn:\${project.yarn_mappings}" + mappings ${mappingsDep} modCompile "net.fabricmc:fabric-loader:\${project.loader_version}" // Fabric API. This is technically optional, but you probably want it anyway. diff --git a/src/test/groovy/net/fabricmc/loom/EmptyBuildFunctionalTest.groovy b/src/test/groovy/net/fabricmc/loom/EmptyBuildFunctionalTest.groovy index 8a722cde..6980d780 100644 --- a/src/test/groovy/net/fabricmc/loom/EmptyBuildFunctionalTest.groovy +++ b/src/test/groovy/net/fabricmc/loom/EmptyBuildFunctionalTest.groovy @@ -44,9 +44,8 @@ class EmptyBuildFunctionalTest extends Specification { result.task(":build").outcome == SUCCESS where: - mcVersion | yarnVersion | loaderVersion | fabricVersion - '1.14' | '1.14+build.21' | '0.4.8+build.155' | '0.3.0+build.183' - '1.14.1' | '1.14.1+build.10' | '0.4.8+build.155' | '0.3.0+build.183' - '1.14.2' | '1.14.2+build.7' | '0.4.8+build.155' | '0.3.0+build.183' + mcVersion | yarnVersion | loaderVersion | fabricVersion + '1.14' | '1.14+build.21' | '0.4.8+build.155' | '0.3.0+build.183' + '1.16.2' | '1.16.2+build.26:v2' | '0.9.2+build.206' | '0.19.0+build.398-1.16' } } diff --git a/src/test/groovy/net/fabricmc/loom/EmptyBuildMojangFunctionalTest.groovy b/src/test/groovy/net/fabricmc/loom/EmptyBuildMojangFunctionalTest.groovy new file mode 100644 index 00000000..a49c3880 --- /dev/null +++ b/src/test/groovy/net/fabricmc/loom/EmptyBuildMojangFunctionalTest.groovy @@ -0,0 +1,50 @@ +package net.fabricmc.loom + +import org.gradle.testkit.runner.GradleRunner +import org.junit.Rule +import org.junit.rules.TemporaryFolder +import spock.lang.Specification +import spock.lang.Unroll + +import static net.fabricmc.loom.BuildUtils.* +import static org.gradle.testkit.runner.TaskOutcome.SUCCESS + +/** + * Created by Mitchell Skaggs on 6/10/2019. + */ +class EmptyBuildMojangFunctionalTest extends Specification { + @Rule + TemporaryFolder testProjectDir = new TemporaryFolder() + File settingsFile + File buildFile + File propsFile + + def setup() { + settingsFile = testProjectDir.newFile('settings.gradle') + buildFile = testProjectDir.newFile('build.gradle') + propsFile = testProjectDir.newFile('gradle.properties') + } + + @Unroll + def "empty build succeeds using Minecraft #mcVersion"() { + given: + settingsFile << genSettingsFile("empty-build-functional-test") + propsFile << genPropsFile(mcVersion, "nope", loaderVersion, fabricVersion) + buildFile << genBuildFile("minecraft.officialMojangMappings()") + + when: + def result = GradleRunner.create() + .withProjectDir(testProjectDir.root) + .withArguments('build',"--stacktrace") + .withPluginClasspath() + .forwardOutput() + .build() + + then: + result.task(":build").outcome == SUCCESS + + where: + mcVersion | loaderVersion | fabricVersion + '1.16.2' | '0.9.2+build.206' | '0.19.0+build.398-1.16' + } +} diff --git a/src/test/groovy/net/fabricmc/loom/MixinBuildFunctionalTest.groovy b/src/test/groovy/net/fabricmc/loom/MixinBuildFunctionalTest.groovy index 40419199..b183fce6 100644 --- a/src/test/groovy/net/fabricmc/loom/MixinBuildFunctionalTest.groovy +++ b/src/test/groovy/net/fabricmc/loom/MixinBuildFunctionalTest.groovy @@ -40,13 +40,7 @@ class MixinBuildFunctionalTest extends Specification { modMixinsJavaFile = testProjectDir.newFile("src/main/java/net/fabricmc/example/mixin/ExampleMixin.java") } - /** - * Why it's ignored: - *

- * When doing mixin annotation processing, a {@link ServiceLoader} is used to find implementations of {@link org.spongepowered.tools.obfuscation.service.IObfuscationService}. The classpath isn't passed to the build properly in this case, causing the Fabric-specific {@link net.fabricmc.loom.mixin.ObfuscationServiceFabric} to not be loaded. This causes the mixin to fail to compile because it doesn't know how to be reobfuscated. - */ @Unroll - @Ignore("fails because the annotation processor classpath doesn't include fabric-mixin-compile-extensions, so it doesn't know how to remap anything") def "mixin build succeeds using Minecraft #mcVersion"() { given: settingsFile << genSettingsFile("mixin-build-functional-test") @@ -69,9 +63,7 @@ class MixinBuildFunctionalTest extends Specification { result.task(":build").outcome == SUCCESS where: - mcVersion | yarnVersion | loaderVersion | fabricVersion - '1.14' | '1.14+build.21' | '0.4.8+build.155' | '0.3.0+build.184' - '1.14.1' | '1.14.1+build.10' | '0.4.8+build.155' | '0.3.0+build.184' - '1.14.2' | '1.14.2+build.7' | '0.4.8+build.155' | '0.3.0+build.184' + mcVersion | yarnVersion | loaderVersion | fabricVersion + '1.14' | '1.14+build.21' | '0.4.8+build.155' | '0.3.0+build.184' } } diff --git a/src/test/groovy/net/fabricmc/loom/SimpleBuildFunctionalTest.groovy b/src/test/groovy/net/fabricmc/loom/SimpleBuildFunctionalTest.groovy index 784a2de8..b1182d9f 100644 --- a/src/test/groovy/net/fabricmc/loom/SimpleBuildFunctionalTest.groovy +++ b/src/test/groovy/net/fabricmc/loom/SimpleBuildFunctionalTest.groovy @@ -58,7 +58,5 @@ class SimpleBuildFunctionalTest extends Specification { mcVersion | yarnVersion | loaderVersion | fabricVersion '19w45a' | '19w45a+build.2:v2' | '0.6.2+build.166' | '0.4.9+build.258-1.15' '1.14' | '1.14+build.21' | '0.4.8+build.155' | '0.3.0+build.184' - '1.14.1' | '1.14.1+build.10' | '0.4.8+build.155' | '0.3.0+build.184' - '1.14.2' | '1.14.2+build.7' | '0.4.8+build.155' | '0.3.0+build.184' } }