Merge remote-tracking branch 'upstream/dev/0.5' into forge

# Conflicts:
#	src/main/java/net/fabricmc/loom/AbstractPlugin.java
#	src/main/java/net/fabricmc/loom/LoomGradleExtension.java
#	src/main/java/net/fabricmc/loom/providers/MappingsProvider.java
#	src/main/java/net/fabricmc/loom/task/RemapJarTask.java
#	src/main/java/net/fabricmc/loom/util/Constants.java
This commit is contained in:
Juuxel
2020-11-29 22:50:37 +02:00
37 changed files with 793 additions and 882 deletions

View File

@@ -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<Project> {
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<Project> {
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<Project> {
}
});
});
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<Project> {
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<Project> {
depNode.appendNode("artifactId", dependency.getName());
depNode.appendNode("version", dependency.getVersion());
depNode.appendNode("scope", entry.getMavenScope());
if (dependency instanceof ModuleDependency) {
final Set<ExcludeRule> 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());
}
}
}
}
}));
}

View File

@@ -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<LoomDecompiler> decompilers = new ArrayList<>();
private final List<JarProcessor> 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<File> 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<MappingSet> 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<JarProcessor> 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<File> getAllMixinMappings() {
return Collections.unmodifiableSet(mixinMappings);
}
}

View File

@@ -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);
}

View File

@@ -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<JarProcessor> jarProcessors;
public JarProcessorManager(Project project) {
this.project = project;
this.extension = project.getExtensions().getByType(LoomGradleExtension.class);
jarProcessors = setupProcessors();
public JarProcessorManager(List<JarProcessor> jarProcessors) {
this.jarProcessors = jarProcessors;
}
//TODO possibly expand via an API?
private List<JarProcessor> setupProcessors() {
List<JarProcessor> 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() {

View File

@@ -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)));
}

View File

@@ -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<Runnable> 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<String> inputConfigurations = new ArrayList<>();
inputConfigurations.add(Constants.Configurations.MINECRAFT_DEPENDENCIES);
inputConfigurations.addAll(Constants.MOD_COMPILE_ENTRIES.stream().map(RemappedConfigurationEntry::getSourceConfiguration).collect(Collectors.toList()));
List<File> 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 {

View File

@@ -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;
}
}

View File

@@ -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()));
}
}
}

View File

@@ -141,7 +141,7 @@ public class MinecraftMappedProvider extends DependencyProvider {
protected void addDependencies(DependencyInfo dependency, Consumer<Runnable> 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;
}
}

View File

@@ -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;
}
}

View File

@@ -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<File> 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");

View File

@@ -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");
}
});
}

View File

@@ -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<RemappedConfigurationEntry> 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() {
}
}
}

View File

@@ -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<File> 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<String, File> classifierToFile = new HashMap<>();
protected final Set<File> resolvedFiles;
protected final String group, name, version;
FileDependencyInfo(Project project, SelfResolvingDependency dependency, Configuration configuration) {
super(project, dependency, configuration);
Set<File> 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<File> resolve() {
return this.resolvedFiles;
}
}
}

View File

@@ -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());
}

View File

@@ -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());
}
}

View File

@@ -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 -> {

View File

@@ -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<ModDependencyInfo> 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);

View File

@@ -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<ModDependencyInfo> 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) {

View File

@@ -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<File> getContainedJars(Project project) {
List<File> fileList = new ArrayList<>();
ResolvedConfiguration configuration = project.getConfigurations().getByName(Constants.INCLUDE).getResolvedConfiguration();
Set<ResolvedDependency> dependencies = configuration.getFirstLevelModuleDependencies();
Configuration configuration = project.getConfigurations().getByName(Constants.Configurations.INCLUDE);
ResolvedConfiguration resolvedConfiguration = configuration.getResolvedConfiguration();
Set<ResolvedDependency> dependencies = resolvedConfiguration.getFirstLevelModuleDependencies();
for (ResolvedDependency dependency : dependencies) {
// Bit ugly doing this, id guess there is a better way but this works.
Set<String> 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<Task> remapJarTasks = dependencyProject.getTasksByName("remapJar", false);
Collection<Task> 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<RemapJarTask> getRequiredTasks(Project project) {
List<RemapJarTask> 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);
}

View File

@@ -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 = "";

View File

@@ -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<File> 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());
}

View File

@@ -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<String, Access> classAccess = new HashMap<>();
public Map<EntryTriple, Access> methodAccess = new HashMap<>();
public Map<EntryTriple, Access> fieldAccess = new HashMap<>();
private final Set<String> 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<String> 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 (<access>\tclass\t<className>) 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 (<access>\tfield\t<className>\t<fieldName>\t<fieldDesc>) 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 (<access>\tmethod\t<className>\t<methodName>\t<methodDesc>) 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<String> 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<String, Access> 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<EntryTriple, Access> entry : methodAccess.entrySet()) {
writeEntry(writer, "method", entry.getKey(), entry.getValue());
}
for (Map.Entry<EntryTriple, Access> 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<String> getAccesses(Access access) {
List<String> 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<EntryTriple, Access> 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<EntryTriple, Access> 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<String, Access> 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<EntryTriple, Access> entry : other.methodAccess.entrySet()) {
addOrMerge(methodAccess, entry.getKey(), entry.getValue());
}
for (Map.Entry<EntryTriple, Access> 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<String> 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("<init>")) {
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);
}
}

View File

@@ -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("<init>")) {
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);
}
}
}
}

View File

@@ -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<String, AccessWidener.Access> entry : input.classAccess.entrySet()) {
remapped.classAccess.put(remapper.map(entry.getKey()), entry.getValue());
}
for (Map.Entry<EntryTriple, AccessWidener.Access> entry : input.methodAccess.entrySet()) {
remapped.addOrMerge(remapped.methodAccess, remapMethod(entry.getKey()), entry.getValue());
}
for (Map.Entry<EntryTriple, AccessWidener.Access> 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())
);
}
}

View File

@@ -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<File> 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<File> 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<ClassMapping<?, ?>> consumer) {
for (TopLevelClassMapping classMapping : mappings.getTopLevelClassMappings()) {
iterateClass(classMapping, consumer);
}
}
private static void iterateClass(ClassMapping<?, ?> classMapping, Consumer<ClassMapping<?, ?>> 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());
}
});
}
}
}

View File

@@ -72,10 +72,10 @@ public abstract class AnnotationProcessorInvoker<T extends Task> {
try {
LoomGradleExtension extension = project.getExtensions().getByType(LoomGradleExtension.class);
Map<String, String> args = new HashMap<String, String>() {{
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<T extends Task> {
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);
}
}