Merge remote-tracking branch 'FabricMC/dev/0.10' into dev/0.10.0

# Conflicts:
#	build.gradle
#	src/main/java/net/fabricmc/loom/LoomGradleExtension.java
#	src/main/java/net/fabricmc/loom/api/LoomGradleExtensionAPI.java
#	src/main/java/net/fabricmc/loom/configuration/accesswidener/AccessWidenerJarProcessor.java
#	src/main/java/net/fabricmc/loom/configuration/mods/ModProcessor.java
#	src/main/java/net/fabricmc/loom/configuration/providers/mappings/LayeredMappingSpecBuilderImpl.java
#	src/main/java/net/fabricmc/loom/configuration/providers/mappings/MappingsProviderImpl.java
#	src/main/java/net/fabricmc/loom/configuration/providers/mappings/mojmap/MojangMappingLayer.java
#	src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftMappedProvider.java
#	src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionApiImpl.java
#	src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionImpl.java
#	src/main/java/net/fabricmc/loom/extension/MinecraftGradleExtension.java
#	src/main/java/net/fabricmc/loom/task/MigrateMappingsTask.java
#	src/main/java/net/fabricmc/loom/task/RemapJarTask.java
#	src/main/java/net/fabricmc/loom/task/RemapSourcesJarTask.java
#	src/main/java/net/fabricmc/loom/util/SourceRemapper.java
#	src/main/java/net/fabricmc/loom/util/TinyRemapperMappingsHelper.java
#	src/test/groovy/net/fabricmc/loom/test/unit/layeredmappings/LayeredMappingSpecBuilderTest.groovy
This commit is contained in:
shedaniel
2021-09-17 02:23:45 +08:00
57 changed files with 1437 additions and 501 deletions

View File

@@ -94,15 +94,12 @@ dependencies {
// tinyfile management
implementation ('dev.architectury:tiny-remapper:1.3.11')
implementation ('dev.architectury:mappings-layers-core:1.4.9')
implementation ('net.fabricmc:tiny-mappings-parser:0.3.0+build.17')
implementation 'net.fabricmc:access-widener:1.1.0'
implementation 'net.fabricmc:access-widener:2.0.0'
implementation 'net.fabricmc:mapping-io:0.2.1'
implementation ('net.fabricmc:lorenz-tiny:3.0.0') {
implementation ('net.fabricmc:lorenz-tiny:4.0.0') {
transitive = false
}
implementation ('org.cadixdev:lorenz-io-proguard:0.5.7')
implementation "dev.architectury:refmap-remapper:1.0.5"
// decompilers

View File

@@ -25,6 +25,7 @@
package net.fabricmc.loom;
import java.io.File;
import java.util.List;
import java.util.Set;
import java.util.function.Supplier;
@@ -38,6 +39,7 @@ import org.gradle.api.file.ConfigurableFileCollection;
import net.fabricmc.loom.api.LoomGradleExtensionAPI;
import net.fabricmc.loom.configuration.InstallerData;
import net.fabricmc.loom.configuration.LoomDependencyManager;
import net.fabricmc.loom.configuration.accesswidener.AccessWidenerFile;
import net.fabricmc.loom.configuration.processors.JarProcessorManager;
import net.fabricmc.loom.configuration.providers.MinecraftProviderImpl;
import net.fabricmc.loom.configuration.providers.forge.FieldMigratedMappingsProvider;
@@ -111,6 +113,10 @@ public interface LoomGradleExtension extends LoomGradleExtensionAPI {
@Override
MixinExtension getMixin();
List<AccessWidenerFile> getTransitiveAccessWideners();
void addTransitiveAccessWideners(List<AccessWidenerFile> accessWidenerFiles);
// ===================
// Architectury Loom
// ===================

View File

@@ -43,7 +43,6 @@ import net.fabricmc.loom.configuration.CompileConfiguration;
import net.fabricmc.loom.configuration.FabricApiExtension;
import net.fabricmc.loom.configuration.MavenPublication;
import net.fabricmc.loom.configuration.ide.IdeConfiguration;
import net.fabricmc.loom.configuration.providers.mappings.MappingsCache;
import net.fabricmc.loom.decompilers.DecompilerConfiguration;
import net.fabricmc.loom.extension.LoomFiles;
import net.fabricmc.loom.extension.LoomGradleExtensionImpl;
@@ -78,7 +77,6 @@ public class LoomGradlePlugin implements BootstrappedPlugin {
refreshDeps = project.getGradle().getStartParameter().isRefreshDependencies() || "true".equals(System.getProperty("loom.refresh"));
if (refreshDeps) {
MappingsCache.INSTANCE.invalidate();
project.getLogger().lifecycle("Refresh dependencies is in use, loom will be significantly slower.");
}

View File

@@ -43,11 +43,11 @@ import org.gradle.api.publish.maven.MavenPublication;
import org.jetbrains.annotations.ApiStatus;
import net.fabricmc.loom.api.decompilers.LoomDecompiler;
import net.fabricmc.loom.api.mappings.layered.spec.LayeredMappingSpecBuilder;
import net.fabricmc.loom.configuration.ide.RunConfig;
import net.fabricmc.loom.configuration.ide.RunConfigSettings;
import net.fabricmc.loom.configuration.launch.LaunchProviderSettings;
import net.fabricmc.loom.configuration.processors.JarProcessor;
import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingSpecBuilder;
import net.fabricmc.loom.util.DeprecationHelper;
import net.fabricmc.loom.util.ModPlatform;
@@ -213,6 +213,13 @@ public interface LoomGradleExtensionAPI {
*/
String getModVersion();
/**
* When true loom will apply transitive access wideners from compile dependencies.
*
* @return the property controlling the transitive access wideners
*/
Property<Boolean> getEnableTransitiveAccessWideners();
// ===================
// Architectury Loom
// ===================

View File

@@ -22,16 +22,22 @@
* SOFTWARE.
*/
package net.fabricmc.loom.configuration.providers.mappings;
package net.fabricmc.loom.api.mappings.layered;
import java.io.File;
import java.nio.file.Path;
import org.gradle.api.artifacts.Dependency;
import org.gradle.api.logging.Logger;
import org.jetbrains.annotations.ApiStatus;
import net.fabricmc.loom.configuration.providers.MinecraftProvider;
import net.fabricmc.loom.configuration.providers.mappings.MappingsProvider;
@ApiStatus.Experimental /* Very Experimental and not cleanly separated from the impl atm */
public interface MappingContext {
File mavenFile(String mavenNotation);
Path resolveDependency(Dependency dependency);
Path resolveMavenDependency(String mavenNotation);
MappingsProvider mappingsProvider();
@@ -44,7 +50,7 @@ public interface MappingContext {
/**
* Creates a temporary working dir to be used to store working files.
*/
File workingDirectory(String name);
Path workingDirectory(String name);
Logger getLogger();
}

View File

@@ -22,21 +22,28 @@
* SOFTWARE.
*/
package net.fabricmc.loom.configuration.providers.mappings;
package net.fabricmc.loom.api.mappings.layered;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import org.jetbrains.annotations.ApiStatus;
import net.fabricmc.mappingio.MappingVisitor;
@ApiStatus.Experimental
public interface MappingLayer {
void visit(MappingVisitor mappingVisitor) throws IOException;
default MappingNamespace getSourceNamespace() {
return MappingNamespace.NAMED;
default MappingsNamespace getSourceNamespace() {
return MappingsNamespace.NAMED;
}
/**
* Provides a list of layer classes that this mapping layer depends on. If such a layer is not present an Exception will be thrown when trying to resolve the layer.
* @return A list of MappingLayer classes to depend on.
*/
default List<Class<? extends MappingLayer>> dependsOn() {
return Collections.emptyList();
}

View File

@@ -0,0 +1,56 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2016-2021 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.api.mappings.layered;
import java.util.Locale;
/**
* The standard namespaces used by loom.
*/
public enum MappingsNamespace {
/**
* Official mappings are the names that are used in the vanilla Minecraft game jars, these are usually obfuscated.
*/
OFFICIAL,
/**
* Intermediary mappings have been generated to provide a stable set of names across minecraft versions.
*
* <p>Intermediary is used in a production runtime (outside a dev env) allowing mods to run across multiple versions of the game. Mods are remapped from "named" at build time.
*
* @see <a href="https://github.com/FabricMC/intermediary/">github.com/FabricMC/intermediary/</a>
*/
INTERMEDIARY,
/**
* Named mappings are the developer friendly names used to develop mods against.
*/
NAMED;
@Override
public String toString() {
return name().toLowerCase(Locale.ROOT);
}
}

View File

@@ -0,0 +1,79 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2021 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.api.mappings.layered.spec;
import java.io.File;
import java.nio.file.Path;
import java.util.Objects;
import org.gradle.api.artifacts.Dependency;
import org.gradle.api.file.RegularFileProperty;
import org.jetbrains.annotations.ApiStatus;
import net.fabricmc.loom.api.mappings.layered.MappingContext;
import net.fabricmc.loom.configuration.providers.mappings.utils.DependencyFileSpec;
import net.fabricmc.loom.configuration.providers.mappings.utils.LocalFileSpec;
import net.fabricmc.loom.configuration.providers.mappings.utils.MavenFileSpec;
/**
* FileSpec should be used in MappingsSpec's that take an input file. The input file can either be a local file or a gradle dep.
*/
@ApiStatus.Experimental
public interface FileSpec {
static FileSpec create(Object o) {
Objects.requireNonNull(o, "Object cannot be null");
if (o instanceof String s) {
return createFromMavenDependency(s);
} else if (o instanceof Dependency d) {
return createFromDependency(d);
} else if (o instanceof File f) {
return createFromFile(f);
} else if (o instanceof RegularFileProperty rfp) {
return createFromFile(rfp);
}
throw new UnsupportedOperationException("Cannot create FileSpec from object of type:" + o.getClass().getCanonicalName());
}
static FileSpec createFromMavenDependency(String dependencyNotation) {
return new MavenFileSpec(dependencyNotation);
}
static FileSpec createFromDependency(Dependency dependency) {
return new DependencyFileSpec(dependency);
}
static FileSpec createFromFile(File file) {
return new LocalFileSpec(file);
}
// Note resolved instantly, this is not lazy
static FileSpec createFromFile(RegularFileProperty regularFileProperty) {
return createFromFile(regularFileProperty.getAsFile().get());
}
Path get(MappingContext context);
}

View File

@@ -0,0 +1,50 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2021 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.api.mappings.layered.spec;
import org.gradle.api.Action;
import org.jetbrains.annotations.ApiStatus;
/**
* Used to configure a layered mapping spec.
*/
@ApiStatus.Experimental
public interface LayeredMappingSpecBuilder {
/**
* Add a MappingsSpec layer.
*/
LayeredMappingSpecBuilder addLayer(MappingsSpec<?> mappingSpec);
/**
* Add a layer that uses the official mappings provided by Mojang.
*/
LayeredMappingSpecBuilder officialMojangMappings();
default LayeredMappingSpecBuilder parchment(Object object) {
return parchment(object, parchmentMappingsSpecBuilder -> parchmentMappingsSpecBuilder.setRemovePrefix(true));
}
LayeredMappingSpecBuilder parchment(Object object, Action<ParchmentMappingsSpecBuilder> action);
}

View File

@@ -22,8 +22,21 @@
* SOFTWARE.
*/
package net.fabricmc.loom.configuration.providers.mappings;
package net.fabricmc.loom.api.mappings.layered.spec;
import org.jetbrains.annotations.ApiStatus;
import net.fabricmc.loom.api.mappings.layered.MappingContext;
import net.fabricmc.loom.api.mappings.layered.MappingLayer;
/**
* A MappingsSpec is an immutable set of data used to create the MappingLayer.
*
* <p>The hashCode is used to generate a hash of the full layered mapping spec, used to cache.
*
* <p>Commonly implemented as a record
*/
@ApiStatus.Experimental
public interface MappingsSpec<L extends MappingLayer> {
L createLayer(MappingContext context);
}

View File

@@ -1,7 +1,7 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2016-2021 FabricMC
* Copyright (c) 2021 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
@@ -22,16 +22,14 @@
* SOFTWARE.
*/
package net.fabricmc.loom.configuration.providers.mappings;
package net.fabricmc.loom.api.mappings.layered.spec;
import java.util.Locale;
import org.jetbrains.annotations.ApiStatus;
public enum MappingNamespace {
OFFICIAL,
INTERMEDIARY,
NAMED;
public String stringValue() {
return name().toLowerCase(Locale.ROOT);
}
@ApiStatus.Experimental
public interface ParchmentMappingsSpecBuilder {
/**
* When enabled the "p" prefix will be stripped from parameter names.
*/
ParchmentMappingsSpecBuilder setRemovePrefix(boolean removePrefix);
}

View File

@@ -0,0 +1,66 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2021 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.configuration.accesswidener;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import org.zeroturnaround.zip.ZipUtil;
public record AccessWidenerFile(
String name,
String modId,
byte[] content
) {
/**
* Reads the access-widener contained in a mod jar, or returns null if there is none.
*/
public static AccessWidenerFile fromModJar(Path modJarPath) {
byte[] modJsonBytes = ZipUtil.unpackEntry(modJarPath.toFile(), "fabric.mod.json");
if (modJsonBytes == null) {
return null;
}
JsonObject jsonObject = new Gson().fromJson(new String(modJsonBytes, StandardCharsets.UTF_8), JsonObject.class);
if (!jsonObject.has("accessWidener")) {
return null;
}
String awPath = jsonObject.get("accessWidener").getAsString();
String modId = jsonObject.get("id").getAsString();
byte[] content = ZipUtil.unpackEntry(modJarPath.toFile(), awPath);
return new AccessWidenerFile(
awPath,
modId,
content
);
}
}

View File

@@ -24,46 +24,38 @@
package net.fabricmc.loom.configuration.accesswidener;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.zip.ZipEntry;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.common.hash.Hashing;
import dev.architectury.tinyremapper.TinyRemapper;
import org.gradle.api.Project;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
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.accesswidener.AccessWidener;
import net.fabricmc.accesswidener.AccessWidenerReader;
import net.fabricmc.accesswidener.AccessWidenerRemapper;
import net.fabricmc.accesswidener.AccessWidenerVisitor;
import net.fabricmc.accesswidener.AccessWidenerWriter;
import net.fabricmc.loom.LoomGradleExtension;
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
import net.fabricmc.loom.configuration.processors.JarProcessor;
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftMappedProvider;
import net.fabricmc.loom.util.Checksum;
import net.fabricmc.loom.util.Constants;
public class AccessWidenerJarProcessor implements JarProcessor {
private AccessWidener accessWidener = new AccessWidener();
private AccessWidenerReader accessWidenerReader = new AccessWidenerReader(accessWidener);
// Filename used to store hash of input access widener in processed jar file
private static final String HASH_FILENAME = "aw.sha256";
// The mod's own access widener file
private byte[] modAccessWidener;
private final AccessWidener accessWidener = new AccessWidener();
private final Project project;
// This is a SHA256 hash across the mod's and all transitive AWs
private byte[] inputHash;
public AccessWidenerJarProcessor(Project project) {
@@ -77,121 +69,53 @@ public class AccessWidenerJarProcessor implements JarProcessor {
@Override
public void setup() {
LoomGradleExtension loomGradleExtension = LoomGradleExtension.get(project);
File awPath = loomGradleExtension.getAccessWidenerPath().get().getAsFile();
LoomGradleExtension extension = LoomGradleExtension.get(project);
Path awPath = extension.getAccessWidenerPath().get().getAsFile().toPath();
if (!awPath.exists()) {
throw new RuntimeException("Could not find access widener file @ " + awPath.getAbsolutePath());
}
inputHash = Checksum.sha256(awPath);
try (BufferedReader reader = new BufferedReader(new FileReader(awPath))) {
accessWidenerReader.read(reader);
// Read our own mod's access widener, used later for producing a version remapped to intermediary
try {
modAccessWidener = Files.readAllBytes(awPath);
} catch (NoSuchFileException e) {
throw new RuntimeException("Could not find access widener file @ " + awPath.toAbsolutePath());
} catch (IOException e) {
throw new RuntimeException("Failed to read project access widener file");
throw new RuntimeException("Failed to read access widener: " + awPath);
}
//Remap accessWidener if its not named, allows for AE's to be written in intermediary
if (!accessWidener.getNamespace().equals("named")) {
try {
List<String> validNamespaces = loomGradleExtension.getMappingsProvider().getMappings().getMetadata().getNamespaces();
AccessWidenerReader reader = new AccessWidenerReader(accessWidener);
reader.read(modAccessWidener);
if (!validNamespaces.contains(accessWidener.getNamespace())) {
throw new UnsupportedOperationException(String.format("Access Widener namespace '%s' is not a valid namespace, it must be one of: '%s'", accessWidener.getNamespace(), String.join(", ", validNamespaces)));
}
TinyRemapper tinyRemapper = loomGradleExtension.getMinecraftMappedProvider().getTinyRemapper();
tinyRemapper.replaceMappings(loomGradleExtension.getMinecraftMappedProvider().getMappings(null, "official", "named"));
loomGradleExtension.getMinecraftMappedProvider();
tinyRemapper.readClassPath(MinecraftMappedProvider.getRemapClasspath(project));
AccessWidenerRemapper remapper = new AccessWidenerRemapper(accessWidener, tinyRemapper.getRemapper(), "named");
accessWidener = remapper.remap();
tinyRemapper.finish();
} catch (IOException e) {
throw new RuntimeException("Failed to remap access widener", e);
}
}
inputHash = Hashing.sha256().hashBytes(modAccessWidener).asBytes();
}
@Override
public void process(File file) {
project.getLogger().lifecycle("Processing file: " + file.getName());
ZipUtil.transformEntries(file, getTransformers(accessWidener.getTargets()));
ZipUtil.addEntry(file, "aw.sha256", inputHash);
AccessWidenerTransformer applier = new AccessWidenerTransformer(project.getLogger(), accessWidener);
applier.apply(file);
ZipUtil.addEntry(file, HASH_FILENAME, inputHash);
}
private ZipEntryTransformerEntry[] getTransformers(Set<String> classes) {
return classes.stream()
.map(string -> new ZipEntryTransformerEntry(string.replaceAll("\\.", "/") + ".class", getTransformer(string)))
.toArray(ZipEntryTransformerEntry[]::new);
}
/**
* Get this mods access widener remapped to the intermediary namespace.
*/
public byte[] getRemappedAccessWidener(Remapper asmRemapper, String targetNamespace) throws IOException {
int version = AccessWidenerReader.readVersion(modAccessWidener);
private ZipEntryTransformer getTransformer(String className) {
return new ByteArrayZipEntryTransformer() {
@Override
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);
AccessWidenerWriter writer = new AccessWidenerWriter(version);
AccessWidenerRemapper remapper = new AccessWidenerRemapper(
writer,
asmRemapper,
MappingsNamespace.NAMED.toString(),
targetNamespace
);
AccessWidenerReader reader = new AccessWidenerReader(remapper);
reader.read(modAccessWidener);
project.getLogger().lifecycle("Applying access widener to " + className);
reader.accept(classVisitor, 0);
return writer.toByteArray();
}
};
}
//Called when remapping the mod
public void remapAccessWidener(Path modJarPath, Remapper asmRemapper) throws IOException {
byte[] bytes = getRemappedAccessWidener(asmRemapper);
String path = getAccessWidenerPath(modJarPath);
if (path == null) {
throw new RuntimeException("Failed to find accessWidener in fabric.mod.json");
}
boolean replaced = ZipUtil.replaceEntry(modJarPath.toFile(), path, bytes);
if (!replaced) {
project.getLogger().warn("Failed to replace access widener file at " + path);
}
}
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()) {
accessWidenerWriter.write(writer);
return writer.toString().getBytes();
}
}
public String getAccessWidenerPath(Path modJarPath) {
byte[] modJsonBytes = ZipUtil.unpackEntry(modJarPath.toFile(), "fabric.mod.json");
if (modJsonBytes == null) {
return null;
}
JsonObject jsonObject = new Gson().fromJson(new String(modJsonBytes, StandardCharsets.UTF_8), JsonObject.class);
if (!jsonObject.has("accessWidener")) {
return null;
}
return jsonObject.get("accessWidener").getAsString();
return writer.write();
}
@Override
public boolean isInvalid(File file) {
byte[] hash = ZipUtil.unpackEntry(file, "aw.sha256");
byte[] hash = ZipUtil.unpackEntry(file, HASH_FILENAME);
if (hash == null) {
return true;

View File

@@ -0,0 +1,82 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2021 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.configuration.accesswidener;
import java.io.File;
import java.util.Set;
import java.util.zip.ZipEntry;
import org.gradle.api.logging.Logger;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
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.accesswidener.AccessWidener;
import net.fabricmc.accesswidener.AccessWidenerClassVisitor;
import net.fabricmc.loom.util.Constants;
final class AccessWidenerTransformer {
private final Logger logger;
private final AccessWidener accessWidener;
AccessWidenerTransformer(Logger logger, AccessWidener accessWidener) {
this.logger = logger;
this.accessWidener = accessWidener;
}
/**
* Apply the rules from an access-widener to the given jar or zip file.
*/
void apply(File jarFile) {
logger.lifecycle("Processing file: " + jarFile.getName());
ZipUtil.transformEntries(jarFile, getTransformers(accessWidener.getTargets()));
}
private ZipEntryTransformerEntry[] getTransformers(Set<String> classes) {
return classes.stream()
.map(string -> new ZipEntryTransformerEntry(string.replaceAll("\\.", "/") + ".class", getTransformer(string)))
.toArray(ZipEntryTransformerEntry[]::new);
}
private ZipEntryTransformer getTransformer(String className) {
return new ByteArrayZipEntryTransformer() {
@Override
protected byte[] transform(ZipEntry zipEntry, byte[] input) {
ClassReader reader = new ClassReader(input);
ClassWriter writer = new ClassWriter(0);
ClassVisitor classVisitor = AccessWidenerClassVisitor.createClassVisitor(Constants.ASM_VERSION, writer, accessWidener);
logger.info("Applying access widener to " + className);
reader.accept(classVisitor, 0);
return writer.toByteArray();
}
};
}
}

View File

@@ -0,0 +1,202 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2020-2021 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.configuration.accesswidener;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import com.google.common.base.Preconditions;
import org.gradle.api.Project;
import net.fabricmc.accesswidener.AccessWidener;
import net.fabricmc.accesswidener.AccessWidenerReader;
import net.fabricmc.accesswidener.AccessWidenerRemapper;
import net.fabricmc.accesswidener.AccessWidenerVisitor;
import net.fabricmc.accesswidener.TransitiveOnlyFilter;
import net.fabricmc.loom.LoomGradleExtension;
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
import net.fabricmc.loom.configuration.RemappedConfigurationEntry;
import net.fabricmc.loom.configuration.processors.JarProcessor;
import net.fabricmc.loom.util.Constants;
import net.fabricmc.loom.util.TinyRemapperHelper;
import net.fabricmc.tinyremapper.TinyRemapper;
/**
* Applies transitive access wideners that are inherited from mod and api dependencies.
*/
public class TransitiveAccessWidenerJarProcessor implements JarProcessor {
private final Project project;
private final LoomGradleExtension extension;
private final List<AccessWidenerFile> transitiveAccessWideners;
public TransitiveAccessWidenerJarProcessor(Project project) {
this.project = project;
this.extension = LoomGradleExtension.get(project);
transitiveAccessWideners = getTransitiveAccessWideners();
extension.addTransitiveAccessWideners(transitiveAccessWideners);
}
@Override
public void setup() {
}
public boolean isEmpty() {
return transitiveAccessWideners.isEmpty();
}
@Override
public String getId() {
Preconditions.checkArgument(!isEmpty());
return "loom:transitive_access_wideners:" + transitiveAccessWideners.hashCode();
}
private List<AccessWidenerFile> getTransitiveAccessWideners() {
List<AccessWidenerFile> accessWideners = new ArrayList<>();
for (RemappedConfigurationEntry entry : Constants.MOD_COMPILE_ENTRIES) {
// Only apply global AWs from mods that are part of the compile classpath
if (!entry.compileClasspath()) {
continue;
}
Set<File> artifacts = extension.getLazyConfigurationProvider(entry.sourceConfiguration())
.get()
.resolve();
for (File artifact : artifacts) {
AccessWidenerFile accessWidener = AccessWidenerFile.fromModJar(artifact.toPath());
if (accessWidener == null) {
continue;
}
if (!TransitiveDetectorVisitor.isTransitive(accessWidener.content())) {
// AW does not contain anything transitive, skip over it
continue;
}
accessWideners.add(accessWidener);
}
}
return accessWideners;
}
@Override
public void process(File file) {
Preconditions.checkArgument(!isEmpty());
AccessWidener accessWidener = createAccessWidener();
AccessWidenerTransformer transformer = new AccessWidenerTransformer(project.getLogger(), accessWidener);
transformer.apply(file);
}
private AccessWidener createAccessWidener() {
AccessWidener accessWidener = new AccessWidener();
// For other mods, only consider transitive AWs and remap from intermediary->named
TinyRemapper tinyRemapper = createTinyRemapper();
try {
AccessWidenerRemapper remappingVisitor = new AccessWidenerRemapper(
accessWidener,
tinyRemapper.getRemapper(),
MappingsNamespace.INTERMEDIARY.toString(),
MappingsNamespace.NAMED.toString()
);
AccessWidenerReader transitiveReader = new AccessWidenerReader(new TransitiveOnlyFilter(remappingVisitor));
for (AccessWidenerFile accessWidenerFile : transitiveAccessWideners) {
project.getLogger().info("Reading transitive access widener from {}", accessWidenerFile.modId());
transitiveReader.read(accessWidenerFile.content());
}
} finally {
tinyRemapper.finish();
}
return accessWidener;
}
private TinyRemapper createTinyRemapper() {
try {
TinyRemapper tinyRemapper = TinyRemapperHelper.getTinyRemapper(project, "intermediary", "named");
tinyRemapper.readClassPath(TinyRemapperHelper.getMinecraftDependencies(project));
tinyRemapper.readClassPath(extension.getMinecraftMappedProvider().getIntermediaryJar().toPath());
return tinyRemapper;
} catch (IOException e) {
throw new RuntimeException("Failed to create tiny remapper for intermediary->named", e);
}
}
@Override
public boolean isInvalid(File file) {
// The hash is handled by getId()
return false;
}
private static class TransitiveDetectorVisitor implements AccessWidenerVisitor {
private boolean transitive = false;
@Override
public void visitClass(String name, AccessWidenerReader.AccessType access, boolean transitive) {
if (transitive) {
this.transitive = true;
}
}
@Override
public void visitMethod(String owner, String name, String descriptor, AccessWidenerReader.AccessType access, boolean transitive) {
if (transitive) {
this.transitive = true;
}
}
@Override
public void visitField(String owner, String name, String descriptor, AccessWidenerReader.AccessType access, boolean transitive) {
if (transitive) {
this.transitive = true;
}
}
public static boolean isTransitive(byte[] content) {
if (AccessWidenerReader.readVersion(content) < 2) {
// Transitive AWs are only in v2 or higher, so we can save parsing the file to find out...
return false;
}
TransitiveDetectorVisitor transitiveDetector = new TransitiveDetectorVisitor();
new AccessWidenerReader(transitiveDetector).read(content);
return transitiveDetector.transitive;
}
}
}

View File

@@ -0,0 +1,147 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2021 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.configuration.accesswidener;
import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import org.gradle.api.logging.Logger;
import net.fabricmc.accesswidener.AccessWidenerReader;
import net.fabricmc.accesswidener.AccessWidenerVisitor;
import net.fabricmc.accesswidener.TransitiveOnlyFilter;
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
import net.fabricmc.mappingio.MappingReader;
import net.fabricmc.mappingio.adapter.MappingSourceNsSwitch;
import net.fabricmc.mappingio.format.Tiny2Writer;
import net.fabricmc.mappingio.tree.MappingTree;
import net.fabricmc.mappingio.tree.MemoryMappingTree;
public final class TransitiveAccessWidenerMappingsProcessor {
private TransitiveAccessWidenerMappingsProcessor() {
}
public static void process(Path inputMappings, Path outputMappings, List<AccessWidenerFile> accessWideners, Logger logger) {
MemoryMappingTree mappingTree = new MemoryMappingTree();
try (Reader reader = Files.newBufferedReader(inputMappings, StandardCharsets.UTF_8)) {
MappingReader.read(reader, new MappingSourceNsSwitch(mappingTree, MappingsNamespace.INTERMEDIARY.toString()));
} catch (IOException e) {
throw new RuntimeException("Failed to read mappings", e);
}
if (!MappingsNamespace.INTERMEDIARY.toString().equals(mappingTree.getSrcNamespace())) {
throw new IllegalStateException("Mapping tree must have intermediary src mappings not " + mappingTree.getSrcNamespace());
}
for (AccessWidenerFile accessWidener : accessWideners) {
MappingCommentVisitor mappingCommentVisitor = new MappingCommentVisitor(accessWidener.modId(), mappingTree, logger);
AccessWidenerReader accessWidenerReader = new AccessWidenerReader(new TransitiveOnlyFilter(mappingCommentVisitor));
accessWidenerReader.read(accessWidener.content());
}
try (Writer writer = Files.newBufferedWriter(outputMappings, StandardCharsets.UTF_8)) {
Tiny2Writer tiny2Writer = new Tiny2Writer(writer, false);
mappingTree.accept(new MappingSourceNsSwitch(tiny2Writer, MappingsNamespace.NAMED.toString()));
} catch (IOException e) {
throw new RuntimeException("Failed to write mappings", e);
}
}
private static record MappingCommentVisitor(String modId, MemoryMappingTree mappingTree, Logger logger) implements AccessWidenerVisitor {
@Override
public void visitClass(String name, AccessWidenerReader.AccessType access, boolean transitive) {
MappingTree.ClassMapping classMapping = mappingTree.getClass(name);
if (classMapping == null) {
logger.warn("Failed to find class ({}) to mark access widened by mod ({})", name, modId());
return;
}
classMapping.setComment(appendComment(classMapping.getComment(), access));
}
@Override
public void visitMethod(String owner, String name, String descriptor, AccessWidenerReader.AccessType access, boolean transitive) {
// Access is also applied to the class, so also add the comment to the class
visitClass(owner, access, transitive);
MappingTree.ClassMapping classMapping = mappingTree.getClass(owner);
if (classMapping == null) {
logger.warn("Failed to find class ({}) to mark access widened by mod ({})", owner, modId());
return;
}
MappingTree.MethodMapping methodMapping = classMapping.getMethod(name, descriptor);
if (methodMapping == null) {
logger.warn("Failed to find method ({}) in ({}) to mark access widened by mod ({})", name, owner, modId());
return;
}
methodMapping.setComment(appendComment(methodMapping.getComment(), access));
}
@Override
public void visitField(String owner, String name, String descriptor, AccessWidenerReader.AccessType access, boolean transitive) {
// Access is also applied to the class, so also add the comment to the class
visitClass(owner, access, transitive);
MappingTree.ClassMapping classMapping = mappingTree.getClass(owner);
if (classMapping == null) {
logger.warn("Failed to find class ({}) to mark access widened by mod ({})", name, modId());
return;
}
MappingTree.FieldMapping fieldMapping = classMapping.getField(name, descriptor);
if (fieldMapping == null) {
logger.warn("Failed to find field ({}) in ({}) to mark access widened by mod ({})", name, owner, modId());
return;
}
fieldMapping.setComment(appendComment(fieldMapping.getComment(), access));
}
private String appendComment(String comment, AccessWidenerReader.AccessType access) {
if (comment == null) {
comment = "";
} else {
comment += "\n";
}
comment += "Access widened by %s to %s".formatted(modId(), access);
return comment;
}
}
}

View File

@@ -24,13 +24,9 @@
package net.fabricmc.loom.configuration.mods;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.util.ArrayList;
@@ -56,19 +52,19 @@ 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.LoomGradlePlugin;
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
import net.fabricmc.loom.configuration.RemappedConfigurationEntry;
import net.fabricmc.loom.configuration.processors.dependency.ModDependencyInfo;
import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl;
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftMappedProvider;
import net.fabricmc.loom.util.Constants;
import net.fabricmc.loom.util.LoggerFilter;
import net.fabricmc.loom.util.TinyRemapperMappingsHelper;
import net.fabricmc.loom.util.TinyRemapperHelper;
import net.fabricmc.loom.util.srg.AtRemapper;
import net.fabricmc.loom.util.srg.CoreModClassRemapper;
import net.fabricmc.mapping.tree.TinyTree;
@@ -107,7 +103,7 @@ public class ModProcessor {
private static void stripNestedJars(File file) {
if (!ZipUtil.containsEntry(file, "fabric.mod.json")) return;
// Strip out all contained jar info as we dont want loader to try and load the jars contained in dev.
ZipUtil.transformEntries(file, new ZipEntryTransformerEntry[] {(new ZipEntryTransformerEntry("fabric.mod.json", new StringZipEntryTransformer() {
ZipUtil.transformEntries(file, new ZipEntryTransformerEntry[]{(new ZipEntryTransformerEntry("fabric.mod.json", new StringZipEntryTransformer() {
@Override
protected String transform(ZipEntry zipEntry, String input) {
JsonObject json = LoomGradlePlugin.GSON.fromJson(input, JsonObject.class);
@@ -117,29 +113,28 @@ public class ModProcessor {
}))});
}
/**
* Remap another mod's access widener from intermediary to named, so that loader can apply it in our dev-env.
*/
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();
AccessWidenerReader accessWidenerReader = new AccessWidenerReader(accessWidener);
accessWidenerReader.read(bufferedReader);
int version = AccessWidenerReader.readVersion(input);
AccessWidenerRemapper accessWidenerRemapper = new AccessWidenerRemapper(accessWidener, remapper, "named");
AccessWidener remapped = accessWidenerRemapper.remap();
AccessWidenerWriter accessWidenerWriter = new AccessWidenerWriter(remapped);
try (StringWriter writer = new StringWriter()) {
accessWidenerWriter.write(writer);
return writer.toString().getBytes(StandardCharsets.UTF_8);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
AccessWidenerWriter writer = new AccessWidenerWriter(version);
AccessWidenerRemapper awRemapper = new AccessWidenerRemapper(
writer,
remapper,
MappingsNamespace.INTERMEDIARY.toString(),
MappingsNamespace.NAMED.toString()
);
AccessWidenerReader reader = new AccessWidenerReader(awRemapper);
reader.read(input);
return writer.write();
}
private static void remapJars(Project project, List<ModDependencyInfo> processList) throws IOException {
LoomGradleExtension extension = LoomGradleExtension.get(project);
String fromM = extension.isForge() ? "srg" : "intermediary";
String toM = "named";
String fromM = extension.isForge() ? MappingsNamespace.SRG.toString() : MappingsNamespace.INTERMEDIARY.toString();
String toM = MappingsNamespace.NAMED.toString();
MinecraftMappedProvider mappedProvider = extension.getMinecraftMappedProvider();
MappingsProviderImpl mappingsProvider = extension.getMappingsProvider();
@@ -158,7 +153,7 @@ public class ModProcessor {
TinyRemapper remapper = TinyRemapper.newRemapper()
.logger(project.getLogger()::lifecycle)
.logUnknownInvokeDynamic(false)
.withMappings(TinyRemapperMappingsHelper.create(mappings, fromM, toM, false))
.withMappings(TinyRemapperHelper.create(mappings, fromM, toM, false))
.renameInvalidLocals(false)
.build();

View File

@@ -25,12 +25,15 @@
package net.fabricmc.loom.configuration.providers.mappings;
import java.io.File;
import java.nio.file.Path;
import org.gradle.api.Project;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.artifacts.Dependency;
import org.gradle.api.logging.Logger;
import net.fabricmc.loom.LoomGradleExtension;
import net.fabricmc.loom.api.mappings.layered.MappingContext;
import net.fabricmc.loom.configuration.providers.MinecraftProvider;
public class GradleMappingContext implements MappingContext {
@@ -45,9 +48,14 @@ public class GradleMappingContext implements MappingContext {
}
@Override
public File mavenFile(String mavenNotation) {
Configuration configuration = project.getConfigurations().detachedConfiguration(project.getDependencies().create(mavenNotation));
return configuration.getSingleFile();
public Path resolveDependency(Dependency dependency) {
Configuration configuration = project.getConfigurations().detachedConfiguration(dependency);
return configuration.getSingleFile().toPath();
}
@Override
public Path resolveMavenDependency(String mavenNotation) {
return resolveDependency(project.getDependencies().create(mavenNotation));
}
@Override
@@ -61,8 +69,8 @@ public class GradleMappingContext implements MappingContext {
}
@Override
public File workingDirectory(String name) {
return new File(minecraftProvider().dir("layered/working_dir/" + workingDirName), name);
public Path workingDirectory(String name) {
return new File(minecraftProvider().dir("layered/working_dir/" + workingDirName), name).toPath();
}
@Override

View File

@@ -26,6 +26,8 @@ package net.fabricmc.loom.configuration.providers.mappings;
import java.util.List;
import net.fabricmc.loom.api.mappings.layered.spec.MappingsSpec;
public record LayeredMappingSpec(List<MappingsSpec<?>> layers) {
public String getVersion() {
// TODO something better?

View File

@@ -31,13 +31,17 @@ import java.util.List;
import org.gradle.api.Action;
import org.jetbrains.annotations.Nullable;
import net.fabricmc.loom.api.mappings.layered.spec.FileSpec;
import net.fabricmc.loom.api.mappings.layered.spec.LayeredMappingSpecBuilder;
import net.fabricmc.loom.api.mappings.layered.spec.MappingsSpec;
import net.fabricmc.loom.api.mappings.layered.spec.ParchmentMappingsSpecBuilder;
import net.fabricmc.loom.api.LoomGradleExtensionAPI;
import net.fabricmc.loom.configuration.providers.mappings.crane.CraneMappingsSpec;
import net.fabricmc.loom.configuration.providers.mappings.intermediary.IntermediaryMappingsSpec;
import net.fabricmc.loom.configuration.providers.mappings.mojmap.MojangMappingsSpec;
import net.fabricmc.loom.configuration.providers.mappings.parchment.ParchmentMappingsSpecBuilder;
import net.fabricmc.loom.configuration.providers.mappings.parchment.ParchmentMappingsSpecBuilderImpl;
public class LayeredMappingSpecBuilder {
public class LayeredMappingSpecBuilderImpl implements LayeredMappingSpecBuilder {
private final List<MappingsSpec<?>> layers = new LinkedList<>();
@Nullable
private final LoomGradleExtensionAPI extension;
@@ -46,6 +50,9 @@ public class LayeredMappingSpecBuilder {
this.extension = extension;
}
@Override
public LayeredMappingSpecBuilder addLayer(MappingsSpec<?> mappingSpec) {
layers.add(mappingSpec);
public LayeredMappingSpecBuilder officialMojangMappings() {
layers.add(new MojangMappingsSpec(() -> extension != null && extension.isSilentMojangMappingsLicenseEnabled()));
return this;
@@ -56,11 +63,16 @@ public class LayeredMappingSpecBuilder {
return this;
}
public LayeredMappingSpecBuilder parchment(String mavenNotation, Action<ParchmentMappingsSpecBuilder> action) {
ParchmentMappingsSpecBuilder builder = ParchmentMappingsSpecBuilder.builder(mavenNotation);
@Override
public LayeredMappingSpecBuilder officialMojangMappings() {
return addLayer(new MojangMappingsSpec());
}
@Override
public LayeredMappingSpecBuilder parchment(Object object, Action<ParchmentMappingsSpecBuilder> action) {
ParchmentMappingsSpecBuilderImpl builder = ParchmentMappingsSpecBuilderImpl.builder(FileSpec.create(object));
action.execute(builder);
layers.add(builder.build());
return this;
return addLayer(builder.build());
}
public LayeredMappingSpecBuilder crane(String mavenNotation) {

View File

@@ -54,6 +54,8 @@ import org.zeroturnaround.zip.ZipEntrySource;
import org.zeroturnaround.zip.ZipUtil;
import net.fabricmc.loom.LoomGradlePlugin;
import net.fabricmc.loom.api.mappings.layered.MappingContext;
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
import net.fabricmc.mappingio.adapter.MappingDstNsReorder;
import net.fabricmc.mappingio.adapter.MappingSourceNsSwitch;
import net.fabricmc.mappingio.format.Tiny2Writer;
@@ -87,8 +89,8 @@ public class LayeredMappingsDependency extends AbstractModuleDependency implemen
try (Writer writer = new StringWriter()) {
Tiny2Writer tiny2Writer = new Tiny2Writer(writer, false);
MappingDstNsReorder nsReorder = new MappingDstNsReorder(tiny2Writer, Collections.singletonList(MappingNamespace.NAMED.stringValue()));
MappingSourceNsSwitch nsSwitch = new MappingSourceNsSwitch(nsReorder, MappingNamespace.INTERMEDIARY.stringValue(), true);
MappingDstNsReorder nsReorder = new MappingDstNsReorder(tiny2Writer, Collections.singletonList(MappingsNamespace.NAMED.toString()));
MappingSourceNsSwitch nsSwitch = new MappingSourceNsSwitch(nsReorder, MappingsNamespace.INTERMEDIARY.toString(), true);
mappings.accept(nsSwitch);
Files.deleteIfExists(mappingsFile);

View File

@@ -28,6 +28,10 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import net.fabricmc.loom.api.mappings.layered.MappingContext;
import net.fabricmc.loom.api.mappings.layered.MappingLayer;
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
import net.fabricmc.loom.api.mappings.layered.spec.MappingsSpec;
import net.fabricmc.mappingio.adapter.MappingSourceNsSwitch;
import net.fabricmc.mappingio.tree.MemoryMappingTree;
@@ -55,7 +59,7 @@ public class LayeredMappingsProcessor {
visitedLayers.add(layer.getClass());
// We have to rebuild a new tree to work on when a layer doesnt merge into layered
boolean rebuild = layer.getSourceNamespace() != MappingNamespace.NAMED;
boolean rebuild = layer.getSourceNamespace() != MappingsNamespace.NAMED;
MemoryMappingTree workingTree;
if (rebuild) {
@@ -63,7 +67,7 @@ public class LayeredMappingsProcessor {
// This can be null on the first layer
if (mappingTree.getSrcNamespace() != null) {
var sourceNsSwitch = new MappingSourceNsSwitch(tempTree, layer.getSourceNamespace().stringValue());
var sourceNsSwitch = new MappingSourceNsSwitch(tempTree, layer.getSourceNamespace().toString());
mappingTree.accept(sourceNsSwitch);
}
@@ -80,7 +84,7 @@ public class LayeredMappingsProcessor {
if (rebuild) {
mappingTree = new MemoryMappingTree();
workingTree.accept(new MappingSourceNsSwitch(mappingTree, MappingNamespace.NAMED.stringValue()));
workingTree.accept(new MappingSourceNsSwitch(mappingTree, MappingsNamespace.NAMED.toString()));
}
}

View File

@@ -1,69 +0,0 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2016-2020 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.configuration.providers.mappings;
import java.io.BufferedReader;
import java.io.IOException;
import java.lang.ref.SoftReference;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.Map;
import net.fabricmc.loom.util.StaticPathWatcher;
import net.fabricmc.mapping.tree.TinyMappingFactory;
import net.fabricmc.mapping.tree.TinyTree;
public final class MappingsCache {
public static final MappingsCache INSTANCE = new MappingsCache();
private final Map<Path, SoftReference<TinyTree>> mappingsCache = new HashMap<>();
// TODO: loom doesn't actually use new mappings when the mappings change until the gradle daemons are stopped
public TinyTree get(Path mappingsPath) throws IOException {
mappingsPath = mappingsPath.toAbsolutePath();
if (StaticPathWatcher.INSTANCE.hasFileChanged(mappingsPath)) {
mappingsCache.remove(mappingsPath);
}
SoftReference<TinyTree> ref = mappingsCache.get(mappingsPath);
if (ref != null && ref.get() != null) {
return ref.get();
} else {
try (BufferedReader reader = Files.newBufferedReader(mappingsPath)) {
TinyTree mappings = TinyMappingFactory.loadWithDetection(reader);
ref = new SoftReference<>(mappings);
mappingsCache.put(mappingsPath, ref);
return mappings;
}
}
}
public void invalidate() {
mappingsCache.clear();
}
}

View File

@@ -40,6 +40,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.function.Consumer;
import com.google.common.base.Stopwatch;
@@ -54,8 +55,10 @@ import org.zeroturnaround.zip.ZipUtil;
import net.fabricmc.loom.LoomGradleExtension;
import net.fabricmc.loom.LoomGradlePlugin;
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
import net.fabricmc.loom.configuration.DependencyProvider;
import net.fabricmc.loom.configuration.accesswidener.AccessWidenerJarProcessor;
import net.fabricmc.loom.configuration.accesswidener.TransitiveAccessWidenerJarProcessor;
import net.fabricmc.loom.configuration.processors.JarProcessorManager;
import net.fabricmc.loom.configuration.processors.MinecraftProcessedProvider;
import net.fabricmc.loom.configuration.providers.MinecraftProviderImpl;
@@ -69,10 +72,10 @@ import net.fabricmc.loom.util.srg.MCPReader;
import net.fabricmc.loom.util.srg.SrgMerger;
import net.fabricmc.loom.util.srg.SrgNamedWriter;
import net.fabricmc.mapping.reader.v2.TinyMetadata;
import net.fabricmc.mapping.reader.v2.TinyV2Factory;
import net.fabricmc.mapping.tree.TinyTree;
import net.fabricmc.mappingio.MappingReader;
import net.fabricmc.mappingio.adapter.MappingNsCompleter;
import net.fabricmc.mappingio.adapter.MappingSourceNsSwitch;
import net.fabricmc.mappingio.format.MappingFormat;
import net.fabricmc.mappingio.format.Tiny2Reader;
import net.fabricmc.mappingio.format.Tiny2Writer;
import net.fabricmc.mappingio.tree.MemoryMappingTree;
@@ -103,13 +106,14 @@ public class MappingsProviderImpl extends DependencyProvider implements Mappings
private Path unpickDefinitions;
private boolean hasUnpickDefinitions;
private UnpickMetadata unpickMetadata;
private MemoryMappingTree mappingTree;
public MappingsProviderImpl(Project project) {
super(project);
}
public TinyTree getMappings() throws IOException {
return MappingsCache.INSTANCE.get(tinyMappings);
public MemoryMappingTree getMappings() throws IOException {
return Objects.requireNonNull(mappingTree, "Cannot get mappings before they have been read");
}
public TinyTree getMappingsWithSrg() throws IOException {
@@ -148,6 +152,7 @@ public class MappingsProviderImpl extends DependencyProvider implements Mappings
patchedProvider.provide(dependency, postPopulationScheduler);
}
mappingTree = readMappings();
manipulateMappings(mappingsJar.toPath());
if (getExtension().shouldGenerateSrgTiny()) {
@@ -197,6 +202,14 @@ public class MappingsProviderImpl extends DependencyProvider implements Mappings
extension.getGameJarProcessors().add(new AccessWidenerJarProcessor(getProject()));
}
if (extension.getEnableTransitiveAccessWideners().get()) {
TransitiveAccessWidenerJarProcessor transitiveAccessWidenerJarProcessor = new TransitiveAccessWidenerJarProcessor(getProject());
if (!transitiveAccessWidenerJarProcessor.isEmpty()) {
extension.getGameJarProcessors().add(transitiveAccessWidenerJarProcessor);
}
}
extension.getAccessWidenerPath().finalizeValue();
extension.getGameJarProcessors().finalizeValue();
JarProcessorManager processorManager = new JarProcessorManager(extension.getGameJarProcessors().get());
@@ -305,6 +318,12 @@ public class MappingsProviderImpl extends DependencyProvider implements Mappings
}
}
private MemoryMappingTree readMappings() throws IOException {
MemoryMappingTree mappingTree = new MemoryMappingTree();
MappingReader.read(tinyMappings, mappingTree);
return mappingTree;
}
private void readAndMergeMCP(Path mcpJar, Consumer<Runnable> postPopulationScheduler) throws Exception {
Path intermediaryTinyPath = getIntermediaryTiny();
SrgProvider provider = getExtension().getSrgProvider();
@@ -334,9 +353,8 @@ public class MappingsProviderImpl extends DependencyProvider implements Mappings
private static boolean areMappingsV2(Path path) throws IOException {
try (BufferedReader reader = Files.newBufferedReader(path)) {
TinyV2Factory.readMetadata(reader);
return true;
} catch (IllegalArgumentException | NoSuchFileException e) {
return MappingReader.detectFormat(reader) == MappingFormat.TINY_2;
} catch (NoSuchFileException e) {
// TODO: just check the mappings version when Parser supports V1 in readMetadata()
return false;
}
@@ -354,10 +372,7 @@ public class MappingsProviderImpl extends DependencyProvider implements Mappings
private static boolean doesJarContainV2Mappings(Path path) throws IOException {
try (FileSystem fs = FileSystems.newFileSystem(path, (ClassLoader) null)) {
try (BufferedReader reader = Files.newBufferedReader(fs.getPath("mappings", "mappings.tiny"))) {
TinyV2Factory.readMetadata(reader);
return true;
} catch (IllegalArgumentException e) {
return false;
return MappingReader.detectFormat(reader) == MappingFormat.TINY_2;
}
}
}
@@ -411,7 +426,7 @@ public class MappingsProviderImpl extends DependencyProvider implements Mappings
project.getLogger().info(":merging mappings");
MemoryMappingTree tree = new MemoryMappingTree();
MappingSourceNsSwitch sourceNsSwitch = new MappingSourceNsSwitch(tree, MappingNamespace.OFFICIAL.stringValue());
MappingSourceNsSwitch sourceNsSwitch = new MappingSourceNsSwitch(tree, MappingsNamespace.OFFICIAL.toString());
readIntermediaryTree().accept(sourceNsSwitch);
try (BufferedReader reader = Files.newBufferedReader(from, StandardCharsets.UTF_8)) {
@@ -427,7 +442,7 @@ public class MappingsProviderImpl extends DependencyProvider implements Mappings
private MemoryMappingTree readIntermediaryTree() throws IOException {
MemoryMappingTree tree = new MemoryMappingTree();
MappingNsCompleter nsCompleter = new MappingNsCompleter(tree, Collections.singletonMap(MappingNamespace.NAMED.stringValue(), MappingNamespace.INTERMEDIARY.stringValue()), true);
MappingNsCompleter nsCompleter = new MappingNsCompleter(tree, Collections.singletonMap(MappingsNamespace.NAMED.toString(), MappingsNamespace.INTERMEDIARY.toString()), true);
try (BufferedReader reader = Files.newBufferedReader(getIntermediaryTiny(), StandardCharsets.UTF_8)) {
Tiny2Reader.read(reader, nsCompleter);
@@ -451,7 +466,7 @@ public class MappingsProviderImpl extends DependencyProvider implements Mappings
runCommand(command, intermediaryMappings.toAbsolutePath().toString(),
yarnMappings.toAbsolutePath().toString(),
newMergedMappings.toAbsolutePath().toString(),
"intermediary", "official");
MappingsNamespace.INTERMEDIARY.toString(), MappingsNamespace.OFFICIAL.toString());
} catch (Exception e) {
throw new RuntimeException("Could not merge mappings from " + intermediaryMappings.toString()
+ " with mappings from " + yarnMappings, e);

View File

@@ -32,22 +32,22 @@ import java.nio.file.Files;
import java.util.Collections;
import java.util.function.Supplier;
import net.fabricmc.loom.configuration.providers.mappings.MappingLayer;
import net.fabricmc.loom.configuration.providers.mappings.MappingNamespace;
import net.fabricmc.loom.api.mappings.layered.MappingLayer;
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
import net.fabricmc.mappingio.MappingVisitor;
import net.fabricmc.mappingio.adapter.MappingNsCompleter;
import net.fabricmc.mappingio.format.Tiny2Reader;
public record IntermediaryMappingLayer(Supplier<File> tinyFile) implements MappingLayer {
@Override
public MappingNamespace getSourceNamespace() {
return MappingNamespace.OFFICIAL;
public MappingsNamespace getSourceNamespace() {
return MappingsNamespace.OFFICIAL;
}
@Override
public void visit(MappingVisitor mappingVisitor) throws IOException {
// Populate named with intermediary and add Add a "named" namespace
MappingNsCompleter nsCompleter = new MappingNsCompleter(mappingVisitor, Collections.singletonMap(MappingNamespace.NAMED.stringValue(), MappingNamespace.INTERMEDIARY.stringValue()), true);
MappingNsCompleter nsCompleter = new MappingNsCompleter(mappingVisitor, Collections.singletonMap(MappingsNamespace.NAMED.toString(), MappingsNamespace.INTERMEDIARY.toString()), true);
try (BufferedReader reader = Files.newBufferedReader(tinyFile().get().toPath(), StandardCharsets.UTF_8)) {
Tiny2Reader.read(reader, nsCompleter);

View File

@@ -24,8 +24,8 @@
package net.fabricmc.loom.configuration.providers.mappings.intermediary;
import net.fabricmc.loom.configuration.providers.mappings.MappingContext;
import net.fabricmc.loom.configuration.providers.mappings.MappingsSpec;
import net.fabricmc.loom.api.mappings.layered.MappingContext;
import net.fabricmc.loom.api.mappings.layered.spec.MappingsSpec;
public record IntermediaryMappingsSpec() implements MappingsSpec<IntermediaryMappingLayer> {
@Override

View File

@@ -25,7 +25,6 @@
package net.fabricmc.loom.configuration.providers.mappings.mojmap;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
@@ -35,8 +34,8 @@ import java.util.List;
import org.gradle.api.logging.Logger;
import net.fabricmc.loom.configuration.providers.mappings.MappingLayer;
import net.fabricmc.loom.configuration.providers.mappings.MappingNamespace;
import net.fabricmc.loom.api.mappings.layered.MappingLayer;
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftVersionMeta;
import net.fabricmc.loom.configuration.providers.mappings.intermediary.IntermediaryMappingLayer;
import net.fabricmc.loom.util.HashedDownloadUtil;
@@ -47,33 +46,33 @@ import net.fabricmc.mappingio.format.ProGuardReader;
public record MojangMappingLayer(String minecraftVersion,
MinecraftVersionMeta.Download clientDownload,
MinecraftVersionMeta.Download serverDownload,
File workingDir,
Path workingDir,
Logger logger,
MojangMappingsSpec.SilenceLicenseOption silenceLicense) implements MappingLayer {
@Override
public void visit(MappingVisitor mappingVisitor) throws IOException {
var clientMappings = new File(workingDir(), "%s.client.txt".formatted(minecraftVersion));
var serverMappings = new File(workingDir(), "%s.server.txt".formatted(minecraftVersion));
Path clientMappings = workingDir().resolve("%s.client.txt".formatted(minecraftVersion));
Path serverMappings = workingDir().resolve("%s.server.txt".formatted(minecraftVersion));
download(clientMappings, serverMappings);
if (!silenceLicense.isSilent()) {
printMappingsLicense(clientMappings.toPath());
printMappingsLicense(clientMappings);
}
// Make official the source namespace
MappingSourceNsSwitch nsSwitch = new MappingSourceNsSwitch(mappingVisitor, MappingNamespace.OFFICIAL.stringValue());
MappingSourceNsSwitch nsSwitch = new MappingSourceNsSwitch(mappingVisitor, MappingsNamespace.OFFICIAL.toString());
try (BufferedReader clientBufferedReader = Files.newBufferedReader(clientMappings.toPath(), StandardCharsets.UTF_8);
BufferedReader serverBufferedReader = Files.newBufferedReader(serverMappings.toPath(), StandardCharsets.UTF_8)) {
ProGuardReader.read(clientBufferedReader, MappingNamespace.NAMED.stringValue(), MappingNamespace.OFFICIAL.stringValue(), nsSwitch);
ProGuardReader.read(serverBufferedReader, MappingNamespace.NAMED.stringValue(), MappingNamespace.OFFICIAL.stringValue(), nsSwitch);
try (BufferedReader clientBufferedReader = Files.newBufferedReader(clientMappings, StandardCharsets.UTF_8);
BufferedReader serverBufferedReader = Files.newBufferedReader(serverMappings, StandardCharsets.UTF_8)) {
ProGuardReader.read(clientBufferedReader, MappingsNamespace.NAMED.toString(), MappingsNamespace.OFFICIAL.toString(), nsSwitch);
ProGuardReader.read(serverBufferedReader, MappingsNamespace.NAMED.toString(), MappingsNamespace.OFFICIAL.toString(), nsSwitch);
}
}
private void download(File clientMappings, File serverMappings) throws IOException {
HashedDownloadUtil.downloadIfInvalid(new URL(clientDownload().url()), clientMappings, clientDownload().sha1(), logger(), false);
HashedDownloadUtil.downloadIfInvalid(new URL(serverDownload().url()), serverMappings, serverDownload().sha1(), logger(), false);
private void download(Path clientMappings, Path serverMappings) throws IOException {
HashedDownloadUtil.downloadIfInvalid(new URL(clientDownload().url()), clientMappings.toFile(), clientDownload().sha1(), logger(), false);
HashedDownloadUtil.downloadIfInvalid(new URL(serverDownload().url()), serverMappings.toFile(), serverDownload().sha1(), logger(), false);
}
private void printMappingsLicense(Path clientMappings) {
@@ -95,8 +94,8 @@ public record MojangMappingLayer(String minecraftVersion,
}
@Override
public MappingNamespace getSourceNamespace() {
return MappingNamespace.OFFICIAL;
public MappingsNamespace getSourceNamespace() {
return MappingsNamespace.OFFICIAL;
}
@Override

View File

@@ -24,8 +24,8 @@
package net.fabricmc.loom.configuration.providers.mappings.mojmap;
import net.fabricmc.loom.configuration.providers.mappings.MappingContext;
import net.fabricmc.loom.configuration.providers.mappings.MappingsSpec;
import net.fabricmc.loom.api.mappings.layered.MappingContext;
import net.fabricmc.loom.api.mappings.layered.spec.MappingsSpec;
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftVersionMeta;
public record MojangMappingsSpec(SilenceLicenseOption silenceLicense) implements MappingsSpec<MojangMappingLayer> {

View File

@@ -24,19 +24,19 @@
package net.fabricmc.loom.configuration.providers.mappings.parchment;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.file.Path;
import java.util.Objects;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import net.fabricmc.loom.LoomGradlePlugin;
import net.fabricmc.loom.configuration.providers.mappings.MappingLayer;
import net.fabricmc.loom.configuration.providers.mappings.MappingNamespace;
import net.fabricmc.loom.api.mappings.layered.MappingLayer;
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
import net.fabricmc.mappingio.MappingVisitor;
public record ParchmentMappingLayer(File parchmentFile, boolean removePrefix) implements MappingLayer {
public record ParchmentMappingLayer(Path parchmentFile, boolean removePrefix) implements MappingLayer {
private static final String PARCHMENT_DATA_FILE_NAME = "parchment.json";
@Override
@@ -47,11 +47,11 @@ public record ParchmentMappingLayer(File parchmentFile, boolean removePrefix) im
mappingVisitor = new ParchmentPrefixStripingMappingVisitor(mappingVisitor);
}
parchmentData.visit(mappingVisitor, MappingNamespace.NAMED.stringValue());
parchmentData.visit(mappingVisitor, MappingsNamespace.NAMED.toString());
}
private ParchmentTreeV1 getParchmentData() throws IOException {
try (var zipFile = new ZipFile(parchmentFile())) {
try (var zipFile = new ZipFile(parchmentFile().toFile())) {
ZipEntry zipFileEntry = zipFile.getEntry(PARCHMENT_DATA_FILE_NAME);
Objects.requireNonNull(zipFileEntry, "Could not find %s in parchment data file".formatted(PARCHMENT_DATA_FILE_NAME));

View File

@@ -24,12 +24,13 @@
package net.fabricmc.loom.configuration.providers.mappings.parchment;
import net.fabricmc.loom.configuration.providers.mappings.MappingContext;
import net.fabricmc.loom.configuration.providers.mappings.MappingsSpec;
import net.fabricmc.loom.api.mappings.layered.spec.FileSpec;
import net.fabricmc.loom.api.mappings.layered.MappingContext;
import net.fabricmc.loom.api.mappings.layered.spec.MappingsSpec;
public record ParchmentMappingsSpec(String mavenNotation, boolean removePrefix) implements MappingsSpec<ParchmentMappingLayer> {
public record ParchmentMappingsSpec(FileSpec fileSpec, boolean removePrefix) implements MappingsSpec<ParchmentMappingLayer> {
@Override
public ParchmentMappingLayer createLayer(MappingContext context) {
return new ParchmentMappingLayer(context.mavenFile(mavenNotation()), removePrefix());
return new ParchmentMappingLayer(fileSpec.get(context), removePrefix());
}
}

View File

@@ -24,25 +24,29 @@
package net.fabricmc.loom.configuration.providers.mappings.parchment;
public class ParchmentMappingsSpecBuilder {
private final String mavenNotation;
import net.fabricmc.loom.api.mappings.layered.spec.FileSpec;
import net.fabricmc.loom.api.mappings.layered.spec.ParchmentMappingsSpecBuilder;
public class ParchmentMappingsSpecBuilderImpl implements ParchmentMappingsSpecBuilder {
private final FileSpec fileSpec;
private boolean removePrefix;
private ParchmentMappingsSpecBuilder(String mavenNotation) {
this.mavenNotation = mavenNotation;
private ParchmentMappingsSpecBuilderImpl(FileSpec fileSpec) {
this.fileSpec = fileSpec;
}
public static ParchmentMappingsSpecBuilder builder(String depNotation) {
return new ParchmentMappingsSpecBuilder(depNotation);
public static ParchmentMappingsSpecBuilderImpl builder(FileSpec fileSpec) {
return new ParchmentMappingsSpecBuilderImpl(fileSpec);
}
@Override
public ParchmentMappingsSpecBuilder setRemovePrefix(boolean removePrefix) {
this.removePrefix = removePrefix;
return this;
}
public ParchmentMappingsSpec build() {
return new ParchmentMappingsSpec(mavenNotation, removePrefix);
return new ParchmentMappingsSpec(fileSpec, removePrefix);
}
}

View File

@@ -0,0 +1,69 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2021 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.configuration.providers.mappings.utils;
import java.io.File;
import java.nio.file.Path;
import java.util.Objects;
import java.util.Set;
import org.gradle.api.artifacts.Dependency;
import org.gradle.api.artifacts.SelfResolvingDependency;
import net.fabricmc.loom.api.mappings.layered.MappingContext;
import net.fabricmc.loom.api.mappings.layered.spec.FileSpec;
public record DependencyFileSpec(Dependency dependency) implements FileSpec {
@Override
public Path get(MappingContext context) {
if (dependency instanceof SelfResolvingDependency selfResolvingDependency) {
Set<File> files = selfResolvingDependency.resolve();
if (files.size() == 0) {
throw new RuntimeException("SelfResolvingDependency (%s) resolved no files".formatted(selfResolvingDependency.toString()));
} else if (files.size() > 1) {
throw new RuntimeException("SelfResolvingDependency (%s) resolved too many files (%d) only 1 is expected".formatted(selfResolvingDependency.toString(), files.size()));
}
return files.iterator().next().toPath();
}
return context.resolveDependency(dependency);
}
@Override
public int hashCode() {
return Objects.hash(dependency.getGroup(), dependency.getName(), dependency.getVersion());
}
@Override
public boolean equals(Object obj) {
if (obj instanceof DependencyFileSpec other) {
return other.dependency().contentEquals(this.dependency());
}
return false;
}
}

View File

@@ -0,0 +1,63 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2021 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.configuration.providers.mappings.utils;
import java.io.File;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Objects;
import net.fabricmc.loom.api.mappings.layered.spec.FileSpec;
import net.fabricmc.loom.api.mappings.layered.MappingContext;
import net.fabricmc.loom.util.Checksum;
public class LocalFileSpec implements FileSpec {
private final File file;
private final int hash;
public LocalFileSpec(File file) {
this.file = file;
this.hash = calculateHashCode();
}
private int calculateHashCode() {
if (!file.exists()) {
throw new RuntimeException("Could not find %s, it must be present at spec creation time to calculate mappings hash".formatted(file.getAbsolutePath()));
}
// Use the file hash as part of the spec, this means if the input file changes the mappings will be re-generated.
return Objects.hash(Arrays.hashCode(Checksum.sha256(file)), file.getAbsolutePath());
}
@Override
public Path get(MappingContext context) {
return file.toPath();
}
@Override
public int hashCode() {
return hash;
}
}

View File

@@ -0,0 +1,37 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2021 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.configuration.providers.mappings.utils;
import java.nio.file.Path;
import net.fabricmc.loom.api.mappings.layered.spec.FileSpec;
import net.fabricmc.loom.api.mappings.layered.MappingContext;
public record MavenFileSpec(String dependencyNotation) implements FileSpec {
@Override
public Path get(MappingContext context) {
return context.resolveMavenDependency(dependencyNotation);
}
}

View File

@@ -46,6 +46,7 @@ import dev.architectury.tinyremapper.TinyRemapper;
import org.gradle.api.Project;
import org.jetbrains.annotations.Nullable;
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
import net.fabricmc.loom.configuration.DependencyProvider;
import net.fabricmc.loom.configuration.providers.MinecraftProviderImpl;
import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl;
@@ -56,7 +57,7 @@ import net.fabricmc.loom.util.DownloadUtil;
import net.fabricmc.loom.util.FileSystemUtil;
import net.fabricmc.loom.util.OperatingSystem;
import net.fabricmc.loom.util.ThreadingUtils;
import net.fabricmc.loom.util.TinyRemapperMappingsHelper;
import net.fabricmc.loom.util.TinyRemapperHelper;
import net.fabricmc.loom.util.srg.AtRemapper;
import net.fabricmc.loom.util.srg.CoreModClassRemapper;
import net.fabricmc.loom.util.srg.InnerClassRemapper;
@@ -251,7 +252,7 @@ public class MinecraftMappedProvider extends DependencyProvider {
assetsOut(inputForge, forgeAssets);
}
remap(remapper, vanilla, forge, "official");
remap(remapper, vanilla, forge, MappingsNamespace.OFFICIAL.toString());
}
public static class Info {
@@ -273,9 +274,9 @@ public class MinecraftMappedProvider extends DependencyProvider {
public void remap(TinyRemapper remapper, Info vanilla, @Nullable Info forge, String fromM) throws IOException {
Set<String> classNames = getExtension().isForge() ? InnerClassRemapper.readClassNames(vanilla.input) : null;
for (String toM : getExtension().isForge() ? Arrays.asList("intermediary", "srg", "named") : Arrays.asList("intermediary", "named")) {
Path output = "named".equals(toM) ? vanilla.outputMapped : "srg".equals(toM) ? vanilla.outputSrg : vanilla.outputIntermediary;
Path outputForge = forge == null ? null : "named".equals(toM) ? forge.outputMapped : "srg".equals(toM) ? forge.outputSrg : forge.outputIntermediary;
for (String toM : getExtension().isForge() ? Arrays.asList(MappingsNamespace.INTERMEDIARY.toString(), MappingsNamespace.SRG.toString(), MappingsNamespace.NAMED.toString()) : Arrays.asList(MappingsNamespace.INTERMEDIARY.toString(), MappingsNamespace.NAMED.toString())) {
Path output = MappingsNamespace.NAMED.toString().equals(toM) ? vanilla.outputMapped : MappingsNamespace.SRG.toString().equals(toM) ? vanilla.outputSrg : vanilla.outputIntermediary;
Path outputForge = forge == null ? null : MappingsNamespace.NAMED.toString().equals(toM) ? forge.outputMapped : MappingsNamespace.SRG.toString().equals(toM) ? forge.outputSrg : forge.outputIntermediary;
InputTag vanillaTag = remapper.createInputTag();
InputTag forgeTag = remapper.createInputTag();
Stopwatch stopwatch = Stopwatch.createStarted();
@@ -294,6 +295,7 @@ public class MinecraftMappedProvider extends DependencyProvider {
OutputRemappingHandler.remap(remapper, forge.assets, outputForge, null, forgeTag);
}
// TODO TinyRemapperHelper
getProject().getLogger().lifecycle(":remapped minecraft (TinyRemapper, " + fromM + " -> " + toM + ") in " + stopwatch);
remapper.removeInput();

View File

@@ -126,12 +126,12 @@ public class LineNumberRemapper {
reader.accept(new LineNumberVisitor(Constants.ASM_VERSION, writer, lineMap.get(idx)), 0);
Files.write(dst, writer.toByteArray());
return FileVisitResult.CONTINUE;
}
}
} else {
Files.copy(file, dst, StandardCopyOption.REPLACE_EXISTING);
}
Files.copy(file, dst, StandardCopyOption.REPLACE_EXISTING);
return FileVisitResult.CONTINUE;
}
});

View File

@@ -29,9 +29,7 @@ import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.jetbrains.java.decompiler.struct.StructClass;
import org.jetbrains.java.decompiler.struct.StructField;
@@ -40,48 +38,29 @@ import org.jetbrains.java.decompiler.struct.StructRecordComponent;
import org.objectweb.asm.Opcodes;
import net.fabricmc.fernflower.api.IFabricJavadocProvider;
import net.fabricmc.mapping.tree.ClassDef;
import net.fabricmc.mapping.tree.FieldDef;
import net.fabricmc.mapping.tree.MethodDef;
import net.fabricmc.mapping.tree.ParameterDef;
import net.fabricmc.mapping.tree.TinyMappingFactory;
import net.fabricmc.mapping.tree.TinyTree;
import net.fabricmc.mappings.EntryTriple;
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
import net.fabricmc.mappingio.MappingReader;
import net.fabricmc.mappingio.adapter.MappingSourceNsSwitch;
import net.fabricmc.mappingio.tree.MappingTree;
import net.fabricmc.mappingio.tree.MemoryMappingTree;
public class TinyJavadocProvider implements IFabricJavadocProvider {
private final Map<String, ClassDef> classes = new HashMap<>();
private final Map<EntryTriple, FieldDef> fields = new HashMap<>();
private final Map<EntryTriple, MethodDef> methods = new HashMap<>();
private final String namespace = "named";
private final MappingTree mappingTree;
public TinyJavadocProvider(File tinyFile) {
final TinyTree mappings = readMappings(tinyFile);
for (ClassDef classDef : mappings.getClasses()) {
final String className = classDef.getName(namespace);
classes.put(className, classDef);
for (FieldDef fieldDef : classDef.getFields()) {
fields.put(new EntryTriple(className, fieldDef.getName(namespace), fieldDef.getDescriptor(namespace)), fieldDef);
}
for (MethodDef methodDef : classDef.getMethods()) {
methods.put(new EntryTriple(className, methodDef.getName(namespace), methodDef.getDescriptor(namespace)), methodDef);
}
}
mappingTree = readMappings(tinyFile);
}
@Override
public String getClassDoc(StructClass structClass) {
ClassDef classDef = classes.get(structClass.qualifiedName);
MappingTree.ClassMapping classMapping = mappingTree.getClass(structClass.qualifiedName);
if (classDef == null) {
if (classMapping == null) {
return null;
}
if (!isRecord(structClass)) {
return classDef.getComment();
return classMapping.getComment();
}
/**
@@ -91,30 +70,30 @@ public class TinyJavadocProvider implements IFabricJavadocProvider {
*/
List<String> parts = new ArrayList<>();
if (classDef.getComment() != null) {
parts.add(classDef.getComment());
if (classMapping.getComment() != null) {
parts.add(classMapping.getComment());
}
boolean addedParam = false;
for (StructRecordComponent component : structClass.getRecordComponents()) {
// The component will always match the field name and descriptor
FieldDef fieldDef = fields.get(new EntryTriple(structClass.qualifiedName, component.getName(), component.getDescriptor()));
MappingTree.FieldMapping fieldMapping = classMapping.getField(component.getName(), component.getDescriptor());
if (fieldDef == null) {
if (fieldMapping == null) {
continue;
}
String comment = fieldDef.getComment();
String comment = fieldMapping.getComment();
if (comment != null) {
if (!addedParam && classDef.getComment() != null) {
if (!addedParam && classMapping.getComment() != null) {
//Add a blank line before components when the class has a comment
parts.add("");
addedParam = true;
}
parts.add(String.format("@param %s %s", fieldDef.getName(namespace), comment));
parts.add(String.format("@param %s %s", fieldMapping.getName(MappingsNamespace.NAMED.toString()), comment));
}
}
@@ -132,34 +111,47 @@ public class TinyJavadocProvider implements IFabricJavadocProvider {
return null;
}
FieldDef fieldDef = fields.get(new EntryTriple(structClass.qualifiedName, structField.getName(), structField.getDescriptor()));
return fieldDef != null ? fieldDef.getComment() : null;
MappingTree.ClassMapping classMapping = mappingTree.getClass(structClass.qualifiedName);
if (classMapping == null) {
return null;
}
MappingTree.FieldMapping fieldMapping = classMapping.getField(structField.getName(), structField.getDescriptor());
return fieldMapping != null ? fieldMapping.getComment() : null;
}
@Override
public String getMethodDoc(StructClass structClass, StructMethod structMethod) {
MethodDef methodDef = methods.get(new EntryTriple(structClass.qualifiedName, structMethod.getName(), structMethod.getDescriptor()));
MappingTree.ClassMapping classMapping = mappingTree.getClass(structClass.qualifiedName);
if (methodDef != null) {
if (classMapping == null) {
return null;
}
MappingTree.MethodMapping methodMapping = classMapping.getMethod(structMethod.getName(), structMethod.getDescriptor());
if (methodMapping != null) {
List<String> parts = new ArrayList<>();
if (methodDef.getComment() != null) {
parts.add(methodDef.getComment());
if (methodMapping.getComment() != null) {
parts.add(methodMapping.getComment());
}
boolean addedParam = false;
for (ParameterDef param : methodDef.getParameters()) {
String comment = param.getComment();
for (MappingTree.MethodArgMapping argMapping : methodMapping.getArgs()) {
String comment = argMapping.getComment();
if (comment != null) {
if (!addedParam && methodDef.getComment() != null) {
if (!addedParam && methodMapping.getComment() != null) {
//Add a blank line before params when the method has a comment
parts.add("");
addedParam = true;
}
parts.add(String.format("@param %s %s", param.getName(namespace), comment));
parts.add(String.format("@param %s %s", methodMapping.getName(MappingsNamespace.NAMED.toString()), comment));
}
}
@@ -173,9 +165,13 @@ public class TinyJavadocProvider implements IFabricJavadocProvider {
return null;
}
private static TinyTree readMappings(File input) {
private static MappingTree readMappings(File input) {
try (BufferedReader reader = Files.newBufferedReader(input.toPath())) {
return TinyMappingFactory.loadWithDetection(reader);
MemoryMappingTree mappingTree = new MemoryMappingTree();
MappingSourceNsSwitch nsSwitch = new MappingSourceNsSwitch(mappingTree, MappingsNamespace.NAMED.toString());
MappingReader.read(reader, nsSwitch);
return mappingTree;
} catch (IOException e) {
throw new RuntimeException("Failed to read mappings", e);
}

View File

@@ -53,6 +53,7 @@ import org.gradle.api.tasks.SourceSet;
import net.fabricmc.loom.api.LoomGradleExtensionAPI;
import net.fabricmc.loom.api.MixinExtensionAPI;
import net.fabricmc.loom.api.decompilers.LoomDecompiler;
import net.fabricmc.loom.api.mappings.layered.spec.LayeredMappingSpecBuilder;
import net.fabricmc.loom.api.ForgeExtensionAPI;
import net.fabricmc.loom.configuration.ide.RunConfig;
import net.fabricmc.loom.configuration.ide.RunConfigSettings;
@@ -61,7 +62,7 @@ import net.fabricmc.loom.configuration.launch.LaunchProviderSettings;
import net.fabricmc.loom.configuration.processors.JarProcessor;
import net.fabricmc.loom.configuration.providers.mappings.GradleMappingContext;
import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingSpec;
import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingSpecBuilder;
import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingSpecBuilderImpl;
import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingsDependency;
import net.fabricmc.loom.util.DeprecationHelper;
import net.fabricmc.loom.util.ModPlatform;
@@ -84,6 +85,7 @@ public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionA
protected final Property<Boolean> remapArchives;
protected final Property<String> customManifest;
protected final Property<Boolean> setupRemappedVariants;
protected final Property<Boolean> transitiveAccessWideners;
private final ModVersionParser versionParser;
@@ -122,6 +124,9 @@ public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionA
this.customManifest = project.getObjects().property(String.class);
this.setupRemappedVariants = project.getObjects().property(Boolean.class)
.convention(true);
this.transitiveAccessWideners = project.getObjects().property(Boolean.class)
.convention(true);
this.transitiveAccessWideners.finalizeValueOnRead();
this.versionParser = new ModVersionParser(project);
@@ -174,7 +179,7 @@ public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionA
@Override
public Dependency layered(Action<LayeredMappingSpecBuilder> action) {
LayeredMappingSpecBuilder builder = new LayeredMappingSpecBuilder(this);
LayeredMappingSpecBuilderImpl builder = new LayeredMappingSpecBuilderImpl(this);
action.execute(builder);
LayeredMappingSpec builtSpec = builder.build();
return new LayeredMappingsDependency(new GradleMappingContext(getProject(), builtSpec.getVersion().replace("+", "_").replace(".", "_")), builtSpec, builtSpec.getVersion());
@@ -222,6 +227,11 @@ public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionA
return versionParser.getModVersion();
}
@Override
public Property<Boolean> getEnableTransitiveAccessWideners() {
return transitiveAccessWideners;
}
protected abstract Project getProject();
protected abstract LoomFiles getFiles();

View File

@@ -25,9 +25,11 @@
package net.fabricmc.loom.extension;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
@@ -45,6 +47,7 @@ import net.fabricmc.loom.LoomGradleExtension;
import net.fabricmc.loom.api.ForgeExtensionAPI;
import net.fabricmc.loom.configuration.InstallerData;
import net.fabricmc.loom.configuration.LoomDependencyManager;
import net.fabricmc.loom.configuration.accesswidener.AccessWidenerFile;
import net.fabricmc.loom.configuration.processors.JarProcessorManager;
import net.fabricmc.loom.util.ModPlatform;
@@ -59,6 +62,7 @@ public class LoomGradleExtensionImpl extends LoomGradleExtensionApiImpl implemen
private final MappingSet[] srcMappingCache = new MappingSet[2];
private final Mercury[] srcMercuryCache = new Mercury[2];
private final Map<String, NamedDomainObjectProvider<Configuration>> lazyConfigurations = new HashMap<>();
private final List<AccessWidenerFile> transitiveAccessWideners = new ArrayList<>();
private LoomDependencyManager dependencyManager;
private JarProcessorManager jarProcessorManager;
@@ -176,6 +180,16 @@ public class LoomGradleExtensionImpl extends LoomGradleExtensionApiImpl implemen
return this.mixinApExtension;
}
@Override
public List<AccessWidenerFile> getTransitiveAccessWideners() {
return transitiveAccessWideners;
}
@Override
public void addTransitiveAccessWideners(List<AccessWidenerFile> accessWidenerFiles) {
transitiveAccessWideners.addAll(accessWidenerFiles);
}
@Override
protected String getMinecraftVersion() {
return getMinecraftProvider().minecraftVersion();

View File

@@ -45,11 +45,11 @@ import net.fabricmc.loom.api.ForgeExtensionAPI;
import net.fabricmc.loom.api.LoomGradleExtensionAPI;
import net.fabricmc.loom.api.MixinExtensionAPI;
import net.fabricmc.loom.api.decompilers.LoomDecompiler;
import net.fabricmc.loom.api.mappings.layered.spec.LayeredMappingSpecBuilder;
import net.fabricmc.loom.configuration.ide.RunConfig;
import net.fabricmc.loom.configuration.ide.RunConfigSettings;
import net.fabricmc.loom.configuration.launch.LaunchProviderSettings;
import net.fabricmc.loom.configuration.processors.JarProcessor;
import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingSpecBuilder;
import net.fabricmc.loom.util.DeprecationHelper;
import net.fabricmc.loom.util.ModPlatform;
@@ -163,6 +163,12 @@ public class MinecraftGradleExtension implements LoomGradleExtensionAPI {
throw new UnsupportedOperationException("Use loom extension");
}
@Override
public Property<Boolean> getEnableTransitiveAccessWideners() {
reportDeprecation();
throw new UnsupportedOperationException();
}
@Override
public void silentMojangMappingsLicense() {
reportDeprecation();

View File

@@ -30,6 +30,7 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
import java.util.stream.Collectors;
@@ -42,6 +43,8 @@ import org.gradle.api.tasks.TaskAction;
import net.fabricmc.loom.LoomGradleExtension;
import net.fabricmc.loom.api.decompilers.DecompilationMetadata;
import net.fabricmc.loom.api.decompilers.LoomDecompiler;
import net.fabricmc.loom.configuration.accesswidener.AccessWidenerFile;
import net.fabricmc.loom.configuration.accesswidener.TransitiveAccessWidenerMappingsProcessor;
import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl;
import net.fabricmc.loom.decompilers.LineNumberRemapper;
import net.fabricmc.loom.util.Constants;
@@ -63,11 +66,10 @@ public class GenerateSourcesTask extends AbstractLoomTask {
@TaskAction
public void doTask() throws Throwable {
int threads = Runtime.getRuntime().availableProcessors();
Path javaDocs = getExtension().getMappingsProvider().tinyMappings;
Collection<Path> libraries = getProject().getConfigurations().getByName(Constants.Configurations.MINECRAFT_DEPENDENCIES).getFiles()
.stream().map(File::toPath).collect(Collectors.toSet());
.stream().map(File::toPath).collect(Collectors.toSet());
DecompilationMetadata metadata = new DecompilationMetadata(threads, javaDocs, libraries);
DecompilationMetadata metadata = new DecompilationMetadata(threads, getMappings(), libraries);
Path runtimeJar = getExtension().getMappingsProvider().mappedProvider.getMappedJar().toPath();
Path sourcesDestination = getMappedJarFileWithSuffix("-sources.jar").toPath();
Path linemap = getMappedJarFileWithSuffix("-sources.lmap").toPath();
@@ -93,7 +95,7 @@ public class GenerateSourcesTask extends AbstractLoomTask {
progressLogger.start("Adjusting line numbers", "linemap");
try (StitchUtil.FileSystemDelegate inFs = StitchUtil.getJarFileSystem(oldCompiledJar.toFile(), true);
StitchUtil.FileSystemDelegate outFs = StitchUtil.getJarFileSystem(linemappedJarDestination.toFile(), true)) {
StitchUtil.FileSystemDelegate outFs = StitchUtil.getJarFileSystem(linemappedJarDestination.toFile(), true)) {
remapper.process(progressLogger, inFs.get().getPath("/"), outFs.get().getPath("/"));
}
@@ -121,6 +123,32 @@ public class GenerateSourcesTask extends AbstractLoomTask {
return new File(path.substring(0, path.length() - 4) + suffix);
}
private Path getMappings() {
Path baseMappings = getExtension().getMappingsProvider().tinyMappings;
if (getExtension().getEnableTransitiveAccessWideners().get()) {
List<AccessWidenerFile> accessWideners = getExtension().getTransitiveAccessWideners();
if (accessWideners.isEmpty()) {
return baseMappings;
}
Path outputMappings;
try {
outputMappings = Files.createTempFile("loom-transitive-mappings", ".tiny");
} catch (IOException e) {
throw new RuntimeException("Failed to create temp file", e);
}
TransitiveAccessWidenerMappingsProcessor.process(baseMappings, outputMappings, accessWideners, getProject().getLogger());
return outputMappings;
}
return baseMappings;
}
@InputFile
public File getInputJar() {
return inputJar;

View File

@@ -24,14 +24,12 @@
package net.fabricmc.loom.task;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.Set;
import com.google.common.collect.ImmutableMap;
@@ -49,14 +47,15 @@ import org.gradle.api.tasks.TaskAction;
import org.gradle.api.tasks.options.Option;
import net.fabricmc.loom.LoomGradleExtension;
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
import net.fabricmc.loom.api.mappings.layered.spec.LayeredMappingSpecBuilder;
import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingsDependency;
import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl;
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftMappedProvider;
import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingSpecBuilder;
import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingsDependency;
import net.fabricmc.loom.util.SourceRemapper;
import net.fabricmc.lorenztiny.TinyMappingsJoiner;
import net.fabricmc.mapping.tree.TinyMappingFactory;
import net.fabricmc.mapping.tree.TinyTree;
import net.fabricmc.mappingio.MappingReader;
import net.fabricmc.mappingio.tree.MemoryMappingTree;
public class MigrateMappingsTask extends AbstractLoomTask {
private Path inputDir;
@@ -100,8 +99,8 @@ public class MigrateMappingsTask extends AbstractLoomTask {
MappingsProviderImpl mappingsProvider = extension.getMappingsProvider();
try {
TinyTree currentMappings = mappingsProvider.getMappings();
TinyTree targetMappings = getMappings(mappings);
MemoryMappingTree currentMappings = mappingsProvider.getMappings();
MemoryMappingTree targetMappings = getMappings(mappings);
migrateMappings(project, extension, extension.getMinecraftMappedProvider(), inputDir, outputDir, currentMappings, targetMappings);
project.getLogger().lifecycle(":remapped project written to " + outputDir.toAbsolutePath());
} catch (IOException e) {
@@ -148,27 +147,25 @@ public class MigrateMappingsTask extends AbstractLoomTask {
return Iterables.getOnlyElement(files);
}
private static TinyTree getMappings(File mappings) throws IOException {
Path temp = Files.createTempFile("mappings", ".tiny");
private static MemoryMappingTree getMappings(File mappings) throws IOException {
MemoryMappingTree mappingTree = new MemoryMappingTree();
try (FileSystem fileSystem = FileSystems.newFileSystem(mappings.toPath(), (ClassLoader) null)) {
Files.copy(fileSystem.getPath("mappings/mappings.tiny"), temp, StandardCopyOption.REPLACE_EXISTING);
MappingReader.read(fileSystem.getPath("mappings/mappings.tiny"), mappingTree);
}
try (BufferedReader reader = Files.newBufferedReader(temp)) {
return TinyMappingFactory.loadWithDetection(reader);
}
return mappingTree;
}
private static void migrateMappings(Project project, LoomGradleExtension extension, MinecraftMappedProvider minecraftMappedProvider,
Path inputDir, Path outputDir, TinyTree currentMappings, TinyTree targetMappings
Path inputDir, Path outputDir, MemoryMappingTree currentMappings, MemoryMappingTree targetMappings
) throws IOException {
project.getLogger().info(":joining mappings");
MappingSet mappingSet = new TinyMappingsJoiner(
currentMappings, "named",
targetMappings, "named",
"intermediary"
currentMappings, MappingsNamespace.NAMED.toString(),
targetMappings, MappingsNamespace.NAMED.toString(),
MappingsNamespace.INTERMEDIARY.toString()
).read();
project.getLogger().lifecycle(":remapping");

View File

@@ -86,6 +86,7 @@ import org.zeroturnaround.zip.transform.StreamZipEntryTransformer;
import org.zeroturnaround.zip.transform.ZipEntryTransformerEntry;
import net.fabricmc.loom.LoomGradleExtension;
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
import net.fabricmc.loom.build.JarRemapper;
import net.fabricmc.loom.build.MixinRefmapHelper;
import net.fabricmc.loom.build.nesting.EmptyNestedJarProvider;
@@ -95,12 +96,13 @@ import net.fabricmc.loom.build.nesting.NestedDependencyProvider;
import net.fabricmc.loom.build.nesting.NestedJarPathProvider;
import net.fabricmc.loom.build.nesting.NestedJarProvider;
import net.fabricmc.loom.configuration.JarManifestConfiguration;
import net.fabricmc.loom.configuration.accesswidener.AccessWidenerFile;
import net.fabricmc.loom.configuration.accesswidener.AccessWidenerJarProcessor;
import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl;
import net.fabricmc.loom.util.Constants;
import net.fabricmc.loom.util.FileSystemUtil;
import net.fabricmc.loom.util.SourceRemapper;
import net.fabricmc.loom.util.TinyRemapperMappingsHelper;
import net.fabricmc.loom.util.TinyRemapperHelper;
import net.fabricmc.loom.util.ZipReprocessorUtil;
import net.fabricmc.loom.util.aw2at.Aw2At;
import net.fabricmc.lorenztiny.TinyMappingsReader;
@@ -247,7 +249,7 @@ public class RemapJarTask extends Jar {
if (isMainRemapTask) {
jarRemapper.addToClasspath(getRemapClasspath());
jarRemapper.addMappings(TinyRemapperMappingsHelper.create(extension.shouldGenerateSrgTiny() ? mappingsProvider.getMappingsWithSrg() : mappingsProvider.getMappings(), fromM, toM, false));
jarRemapper.addMappings(TinyRemapperHelper.create(extension.shouldGenerateSrgTiny() ? mappingsProvider.getMappingsWithSrg() : mappingsProvider.getMappings(), fromM, toM, false));
}
for (File mixinMapFile : extension.getAllMixinMappings()) {
@@ -272,15 +274,15 @@ public class RemapJarTask extends Jar {
byte[] data;
try {
data = accessWidenerJarProcessor.getRemappedAccessWidener(remapper);
data = accessWidenerJarProcessor.getRemappedAccessWidener(remapper, toM);
} catch (IOException e) {
throw new RuntimeException("Failed to remap access widener");
throw new RuntimeException("Failed to remap access widener", e);
}
String awPath = accessWidenerJarProcessor.getAccessWidenerPath(remapData.input);
Preconditions.checkNotNull(awPath, "Failed to find accessWidener in fabric.mod.json: " + remapData.input);
AccessWidenerFile awFile = AccessWidenerFile.fromModJar(remapData.input);
Preconditions.checkNotNull(awFile, "Failed to find accessWidener in fabric.mod.json: " + remapData.input);
return Pair.of(awPath, data);
return Pair.of(awFile.name(), data);
}
return null;
@@ -559,7 +561,8 @@ public class RemapJarTask extends Jar {
return this;
}
@ApiStatus.Experimental // This only allows mod jars, proceed with care when trying to pass in configurations with projects, or something that depends on a task.
@ApiStatus.Experimental
// This only allows mod jars, proceed with care when trying to pass in configurations with projects, or something that depends on a task.
public RemapJarTask include(Object... paths) {
Collections.addAll(nestedPaths, paths);
this.addNestedDependencies.set(true);

View File

@@ -32,6 +32,7 @@ import org.gradle.api.tasks.Internal;
import org.gradle.api.tasks.OutputFile;
import org.gradle.api.tasks.TaskAction;
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
import net.fabricmc.loom.util.SourceRemapper;
public class RemapSourcesJarTask extends AbstractLoomTask {
@@ -53,7 +54,7 @@ public class RemapSourcesJarTask extends AbstractLoomTask {
if (sourceRemapper == null) {
if (sourceNamespace.get().equals(targetNamespace.get())) {
SourceRemapper.remapSources(getProject(), getInput().get().getAsFile(), getOutput().get().getAsFile(),
targetNamespace.get().equals("named") ? SourceRemapper.intermediary(getProject()) : "named", targetNamespace.get(), reproducibleFileOrder.get(), preserveFileTimestamps.get());
targetNamespace.get().equals(MappingsNamespace.NAMED.toString()) ? SourceRemapper.intermediary(getProject()) : "named", targetNamespace.get(), reproducibleFileOrder.get(), preserveFileTimestamps.get());
} else {
SourceRemapper.remapSources(getProject(), getInput().get().getAsFile(), getOutput().get().getAsFile(), sourceNamespace.get(), targetNamespace.get(), reproducibleFileOrder.get(), preserveFileTimestamps.get());
}

View File

@@ -53,8 +53,6 @@ public class Constants {
new RemappedConfigurationEntry("modRuntimeOnly", JavaPlugin.RUNTIME_ONLY_CONFIGURATION_NAME, false, true, JavaPlugin.RUNTIME_ELEMENTS_CONFIGURATION_NAME)
);
public static final String SOFTWARE_COMPONENT_NAME = "loom";
private Constants() {
}

View File

@@ -40,11 +40,12 @@ import org.gradle.api.Project;
import org.zeroturnaround.zip.ZipUtil;
import net.fabricmc.loom.LoomGradleExtension;
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
import net.fabricmc.loom.configuration.RemappedConfigurationEntry;
import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl;
import net.fabricmc.loom.util.gradle.ProgressLogger;
import net.fabricmc.lorenztiny.TinyMappingsReader;
import net.fabricmc.mapping.tree.TinyTree;
import net.fabricmc.mappingio.tree.MemoryMappingTree;
import net.fabricmc.stitch.util.StitchUtil;
public class SourceRemapper {
@@ -184,7 +185,7 @@ public class SourceRemapper {
MappingSet mappings = extension.getOrCreateSrcMappingCache(id, () -> {
try {
TinyTree m = extension.shouldGenerateSrgTiny() ? mappingsProvider.getMappingsWithSrg() : mappingsProvider.getMappings();
MemoryMappingTree m = extension.shouldGenerateSrgTiny() ? mappingsProvider.getMappingsWithSrg() : mappingsProvider.getMappings();
project.getLogger().info(":loading " + from + " -> " + to + " source mappings");
return new TinyMappingsReader(m, from, to).read();
} catch (Exception e) {

View File

@@ -0,0 +1,108 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2021 FabricMC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package net.fabricmc.loom.util;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Map;
import com.google.common.collect.ImmutableMap;
import org.gradle.api.Project;
import net.fabricmc.loom.LoomGradleExtension;
import net.fabricmc.mappingio.tree.MappingTree;
import net.fabricmc.tinyremapper.IMappingProvider;
import net.fabricmc.tinyremapper.TinyRemapper;
/**
* Contains shortcuts to create tiny remappers using the mappings accessibly to the project.
*/
public final class TinyRemapperHelper {
private static final Map<String, String> JSR_TO_JETBRAINS = new ImmutableMap.Builder<String, String>()
.put("javax/annotation/Nullable", "org/jetbrains/annotations/Nullable")
.put("javax/annotation/Nonnull", "org/jetbrains/annotations/NotNull")
.put("javax/annotation/concurrent/Immutable", "org/jetbrains/annotations/Unmodifiable")
.build();
private TinyRemapperHelper() {
}
public static TinyRemapper getTinyRemapper(Project project, String fromM, String toM) throws IOException {
LoomGradleExtension extension = LoomGradleExtension.get(project);
return TinyRemapper.newRemapper()
.withMappings(create(extension.getMappingsProvider().getMappings(), fromM, toM, true))
.withMappings(out -> JSR_TO_JETBRAINS.forEach(out::acceptClass))
.renameInvalidLocals(true)
.rebuildSourceFilenames(true)
.build();
}
public static Path[] getMinecraftDependencies(Project project) {
return project.getConfigurations().getByName(Constants.Configurations.MINECRAFT_DEPENDENCIES).getFiles()
.stream().map(File::toPath).toArray(Path[]::new);
}
private static IMappingProvider.Member memberOf(String className, String memberName, String descriptor) {
return new IMappingProvider.Member(className, memberName, descriptor);
}
public static IMappingProvider create(MappingTree mappings, String from, String to, boolean remapLocalVariables) {
return (acceptor) -> {
for (MappingTree.ClassMapping classDef : mappings.getClasses()) {
String className = classDef.getName(from);
acceptor.acceptClass(className, classDef.getName(to));
for (MappingTree.FieldMapping field : classDef.getFields()) {
acceptor.acceptField(memberOf(className, field.getName(from), field.getDesc(from)), field.getName(to));
}
for (MappingTree.MethodMapping method : classDef.getMethods()) {
IMappingProvider.Member methodIdentifier = memberOf(className, method.getName(from), method.getDesc(from));
acceptor.acceptMethod(methodIdentifier, method.getName(to));
if (remapLocalVariables) {
for (MappingTree.MethodArgMapping parameter : method.getArgs()) {
String name = parameter.getName(to);
if (name == null) {
continue;
}
acceptor.acceptMethodArg(methodIdentifier, parameter.getLvIndex(), name);
}
for (MappingTree.MethodVarMapping localVariable : method.getVars()) {
acceptor.acceptMethodVar(methodIdentifier, localVariable.getLvIndex(),
localVariable.getStartOpIdx(), localVariable.getLvtRowIndex(),
localVariable.getName(to));
}
}
}
}
};
}
}

View File

@@ -1,72 +0,0 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2016-2019 FabricMC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package net.fabricmc.loom.util;
import dev.architectury.tinyremapper.IMappingProvider;
import net.fabricmc.mapping.tree.ClassDef;
import net.fabricmc.mapping.tree.FieldDef;
import net.fabricmc.mapping.tree.LocalVariableDef;
import net.fabricmc.mapping.tree.MethodDef;
import net.fabricmc.mapping.tree.ParameterDef;
import net.fabricmc.mapping.tree.TinyTree;
public class TinyRemapperMappingsHelper {
private TinyRemapperMappingsHelper() { }
private static IMappingProvider.Member memberOf(String className, String memberName, String descriptor) {
return new IMappingProvider.Member(className, memberName, descriptor);
}
public static IMappingProvider create(TinyTree mappings, String from, String to, boolean remapLocalVariables) {
return (acceptor) -> {
for (ClassDef classDef : mappings.getClasses()) {
String className = classDef.getName(from);
acceptor.acceptClass(className, classDef.getName(to));
for (FieldDef field : classDef.getFields()) {
acceptor.acceptField(memberOf(className, field.getName(from), field.getDescriptor(from)), field.getName(to));
}
for (MethodDef method : classDef.getMethods()) {
IMappingProvider.Member methodIdentifier = memberOf(className, method.getName(from), method.getDescriptor(from));
acceptor.acceptMethod(methodIdentifier, method.getName(to));
if (remapLocalVariables) {
for (ParameterDef parameter : method.getParameters()) {
acceptor.acceptMethodArg(methodIdentifier, parameter.getLocalVariableIndex(), parameter.getName(to));
}
for (LocalVariableDef localVariable : method.getLocalVariables()) {
acceptor.acceptMethodVar(methodIdentifier, localVariable.getLocalVariableIndex(),
localVariable.getLocalVariableStartOffset(), localVariable.getLocalVariableTableIndex(),
localVariable.getName(to));
}
}
}
}
};
}
}

View File

@@ -25,6 +25,7 @@
package net.fabricmc.loom.test.integration
import net.fabricmc.loom.test.util.GradleProjectTestTrait
import org.zeroturnaround.zip.ZipUtil
import spock.lang.Specification
import spock.lang.Unroll
@@ -48,4 +49,20 @@ class AccessWidenerTest extends Specification implements GradleProjectTestTrait
String expected() {
new File("src/test/resources/accesswidener/expected.accesswidener").text
}
@Unroll
def "transitive accesswidener (gradle #version)"() {
setup:
def gradle = gradleProject(project: "transitiveAccesswidener", version: version)
ZipUtil.pack(new File(gradle.projectDir, "dummyDependency"), new File(gradle.projectDir, "dummy.jar"))
when:
def result = gradle.run(task: "build")
then:
result.task(":build").outcome == SUCCESS
where:
version << STANDARD_TEST_VERSIONS
}
}

View File

@@ -24,8 +24,9 @@
package net.fabricmc.loom.test.unit.layeredmappings
import net.fabricmc.loom.configuration.providers.mappings.utils.MavenFileSpec
import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingSpec
import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingSpecBuilder
import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingSpecBuilderImpl
import net.fabricmc.loom.configuration.providers.mappings.intermediary.IntermediaryMappingsSpec
import net.fabricmc.loom.configuration.providers.mappings.mojmap.MojangMappingsSpec
import net.fabricmc.loom.configuration.providers.mappings.parchment.ParchmentMappingsSpec
@@ -60,7 +61,7 @@ class LayeredMappingSpecBuilderTest extends LayeredMappingsSpecification {
layers[0].class == IntermediaryMappingsSpec
layers[1].class == MojangMappingsSpec
layers[2].class == ParchmentMappingsSpec
parchment.mavenNotation() == "I like cake"
(parchment.fileSpec() as MavenFileSpec).dependencyNotation() == "I like cake"
parchment.removePrefix() == true
}
@@ -80,7 +81,7 @@ class LayeredMappingSpecBuilderTest extends LayeredMappingsSpecification {
layers[0].class == IntermediaryMappingsSpec
layers[1].class == MojangMappingsSpec
layers[2].class == ParchmentMappingsSpec
parchment.mavenNotation() == "I like cake"
(parchment.fileSpec() as MavenFileSpec).dependencyNotation() == "I like cake"
parchment.removePrefix() == false
}
@@ -100,17 +101,17 @@ class LayeredMappingSpecBuilderTest extends LayeredMappingsSpecification {
layers[0].class == IntermediaryMappingsSpec
layers[1].class == MojangMappingsSpec
layers[2].class == ParchmentMappingsSpec
parchment.mavenNotation() == "I really like cake"
(parchment.fileSpec() as MavenFileSpec).dependencyNotation() == "I really like cake"
parchment.removePrefix() == false
}
// Gradle does this big of magic behind the scenes
LayeredMappingSpec layered(@DelegatesTo(LayeredMappingSpecBuilder) Closure cl) {
LayeredMappingSpec layered(@DelegatesTo(LayeredMappingSpecBuilderImpl) Closure cl) {
return layeredAction(ConfigureUtil.configureUsing(cl))
}
LayeredMappingSpec layeredAction(Action<LayeredMappingSpecBuilder> action) {
LayeredMappingSpecBuilder builder = new LayeredMappingSpecBuilder(null)
LayeredMappingSpec layeredAction(Action<LayeredMappingSpecBuilderImpl> action) {
LayeredMappingSpecBuilderImpl builder = new LayeredMappingSpecBuilderImpl(null)
action.execute(builder)
return builder.build()
}

View File

@@ -28,18 +28,20 @@ import groovy.transform.CompileStatic
import net.fabricmc.loom.configuration.providers.MinecraftProvider
import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingSpec
import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingsProcessor
import net.fabricmc.loom.configuration.providers.mappings.MappingContext
import net.fabricmc.loom.configuration.providers.mappings.MappingLayer
import net.fabricmc.loom.configuration.providers.mappings.MappingNamespace
import net.fabricmc.loom.api.mappings.layered.MappingContext
import net.fabricmc.loom.api.mappings.layered.MappingLayer
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace
import net.fabricmc.loom.configuration.providers.mappings.MappingsProvider
import net.fabricmc.loom.configuration.providers.mappings.MappingsSpec
import net.fabricmc.loom.api.mappings.layered.spec.MappingsSpec
import net.fabricmc.mappingio.adapter.MappingDstNsReorder
import net.fabricmc.mappingio.adapter.MappingSourceNsSwitch
import net.fabricmc.mappingio.format.Tiny2Writer
import net.fabricmc.mappingio.tree.MemoryMappingTree
import org.gradle.api.artifacts.Dependency
import org.gradle.api.logging.Logger
import spock.lang.Specification
import java.nio.file.Path
import java.util.zip.ZipFile
abstract class LayeredMappingsSpecification extends Specification implements LayeredMappingsTestConstants {
@@ -94,8 +96,8 @@ abstract class LayeredMappingsSpecification extends Specification implements Lay
MemoryMappingTree reorder(MemoryMappingTree mappingTree) {
def reorderedMappings = new MemoryMappingTree()
def nsReorder = new MappingDstNsReorder(reorderedMappings, Collections.singletonList(MappingNamespace.NAMED.stringValue()))
def nsSwitch = new MappingSourceNsSwitch(nsReorder, MappingNamespace.INTERMEDIARY.stringValue(), true)
def nsReorder = new MappingDstNsReorder(reorderedMappings, Collections.singletonList(MappingsNamespace.NAMED.toString()))
def nsSwitch = new MappingSourceNsSwitch(nsReorder, MappingsNamespace.INTERMEDIARY.toString(), true)
mappingTree.accept(nsSwitch)
return reorderedMappings
}
@@ -103,9 +105,14 @@ abstract class LayeredMappingsSpecification extends Specification implements Lay
@CompileStatic
class TestMappingContext implements MappingContext {
@Override
File mavenFile(String mavenNotation) {
Path resolveDependency(Dependency dependency) {
throw new UnsupportedOperationException("TODO")
}
@Override
Path resolveMavenDependency(String mavenNotation) {
assert mavenFiles.containsKey(mavenNotation)
return mavenFiles.get(mavenNotation)
return mavenFiles.get(mavenNotation).toPath()
}
@Override
@@ -119,8 +126,8 @@ abstract class LayeredMappingsSpecification extends Specification implements Lay
}
@Override
File workingDirectory(String name) {
return new File(tempDir, name)
Path workingDirectory(String name) {
return new File(tempDir, name).toPath()
}
@Override

View File

@@ -24,6 +24,7 @@
package net.fabricmc.loom.test.unit.layeredmappings
import net.fabricmc.loom.api.mappings.layered.spec.FileSpec
import net.fabricmc.loom.configuration.providers.mappings.intermediary.IntermediaryMappingsSpec
import net.fabricmc.loom.configuration.providers.mappings.mojmap.MojangMappingsSpec
import net.fabricmc.loom.configuration.providers.mappings.parchment.ParchmentMappingsSpec
@@ -38,7 +39,7 @@ class ParchmentMappingLayerTest extends LayeredMappingsSpecification {
def mappings = getLayeredMappings(
new IntermediaryMappingsSpec(),
new MojangMappingsSpec(),
new ParchmentMappingsSpec(PARCHMENT_NOTATION, false)
new ParchmentMappingsSpec(FileSpec.create(PARCHMENT_NOTATION), false)
)
def tiny = getTiny(mappings)
def reorderedMappings = reorder(mappings)
@@ -61,7 +62,7 @@ class ParchmentMappingLayerTest extends LayeredMappingsSpecification {
def mappings = getLayeredMappings(
new IntermediaryMappingsSpec(),
new MojangMappingsSpec(),
new ParchmentMappingsSpec(PARCHMENT_NOTATION, true)
new ParchmentMappingsSpec(FileSpec.create(PARCHMENT_NOTATION), true)
)
def tiny = getTiny(mappings)
def reorderedMappings = reorder(mappings)

View File

@@ -1,9 +1,6 @@
accessWidener v1 intermediary
accessible class net/minecraft/class_1928$class_5199
accessible class net/minecraft/class_1735
accessible class net/minecraft/class_1928$class_4314
extendable class net/minecraft/class_1928$class_4314
accessible class net/minecraft/class_5235$class_5238
accessible method net/minecraft/class_1928$class_4314 <init> (Ljava/util/function/Supplier;Ljava/util/function/Function;Ljava/util/function/BiConsumer;Lnet/minecraft/class_1928$class_5199;)V
extendable method net/minecraft/class_1928$class_4314 <init> (Ljava/util/function/Supplier;Ljava/util/function/Function;Ljava/util/function/BiConsumer;Lnet/minecraft/class_1928$class_5199;)V
accessible class net/minecraft/class_1928$class_5199
accessible class net/minecraft/class_5235$class_5238
accessible field net/minecraft/class_1735 field_7873 I

View File

@@ -0,0 +1,18 @@
// This is used by a range of tests that append to this file before running the gradle tasks.
// Can be used for tests that require minimal custom setup
plugins {
id 'fabric-loom'
id 'maven-publish'
}
archivesBaseName = "fabric-example-mod"
version = "1.0.0"
group = "com.example"
dependencies {
minecraft "com.mojang:minecraft:1.17.1"
mappings "net.fabricmc:yarn:1.17.1+build.59:v2"
modImplementation "net.fabricmc:fabric-loader:0.11.6"
modImplementation files("dummy.jar")
}

View File

@@ -0,0 +1,3 @@
accessWidener v2 intermediary
transitive-accessible method net/minecraft/class_1972 method_8775 (Ljava/lang/String;)Lnet/minecraft/class_5321;

View File

@@ -0,0 +1,7 @@
{
"schemaVersion": 1,
"id": "dummy",
"version": "1",
"name": "Dummy Mod",
"accessWidener" : "dummy.accesswidener"
}

View File

@@ -0,0 +1,13 @@
import net.minecraft.world.biome.BiomeKeys;
import net.minecraft.world.biome.Biome;
import net.minecraft.util.registry.RegistryKey;
import net.fabricmc.api.ModInitializer;
public class ExampleMod implements ModInitializer {
@Override
public void onInitialize() {
// BiomeKeys.register has been made public by a transitive AW
RegistryKey<Biome> biomeRegistryKey = BiomeKeys.register("dummy");
}
}