Rework how unpick and linenumber maps are applied (#907)

This should hopefully vastly improve debugging, and more imporantly not work in a consistant manner, making debugging issues a lot easier.

This commit contains an intergration test that uses a real debugger to check that breakpoints are being fired as expected.
This commit is contained in:
modmuss
2023-06-16 21:55:04 +01:00
committed by GitHub
parent fe823ddb30
commit 4e593fc5ae
14 changed files with 478 additions and 264 deletions

View File

@@ -57,6 +57,7 @@ import net.fabricmc.loom.configuration.providers.mappings.MappingConfiguration;
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftJarConfiguration;
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftProvider;
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftSourceSets;
import net.fabricmc.loom.configuration.providers.minecraft.mapped.AbstractMappedMinecraftProvider;
import net.fabricmc.loom.configuration.providers.minecraft.mapped.IntermediaryMinecraftProvider;
import net.fabricmc.loom.configuration.providers.minecraft.mapped.NamedMinecraftProvider;
import net.fabricmc.loom.extension.MixinExtension;
@@ -153,8 +154,8 @@ public abstract class CompileConfiguration implements Runnable {
mappingConfiguration.applyToProject(getProject(), mappingsDep);
// Provide the remapped mc jars
final IntermediaryMinecraftProvider<?> intermediaryMinecraftProvider = jarConfiguration.getIntermediaryMinecraftProviderBiFunction().apply(configContext, minecraftProvider);
NamedMinecraftProvider<?> namedMinecraftProvider = jarConfiguration.getNamedMinecraftProviderBiFunction().apply(configContext, minecraftProvider);
final IntermediaryMinecraftProvider<?> intermediaryMinecraftProvider = jarConfiguration.getIntermediaryMinecraftProviderBiFunction().apply(project, minecraftProvider);
NamedMinecraftProvider<?> namedMinecraftProvider = jarConfiguration.getNamedMinecraftProviderBiFunction().apply(project, minecraftProvider);
registerGameProcessors(configContext);
MinecraftJarProcessorManager minecraftJarProcessorManager = MinecraftJarProcessorManager.create(getProject());
@@ -164,11 +165,13 @@ public abstract class CompileConfiguration implements Runnable {
namedMinecraftProvider = jarConfiguration.getProcessedNamedMinecraftProviderBiFunction().apply(namedMinecraftProvider, minecraftJarProcessorManager);
}
final var provideContext = new AbstractMappedMinecraftProvider.ProvideContext(true, extension.refreshDeps(), configContext);
extension.setIntermediaryMinecraftProvider(intermediaryMinecraftProvider);
intermediaryMinecraftProvider.provide(true);
intermediaryMinecraftProvider.provide(provideContext);
extension.setNamedMinecraftProvider(namedMinecraftProvider);
namedMinecraftProvider.provide(true);
namedMinecraftProvider.provide(provideContext);
}
private void registerGameProcessors(ConfigContext configContext) {

View File

@@ -27,13 +27,14 @@ package net.fabricmc.loom.configuration.decompile;
import java.io.File;
import org.gradle.api.Project;
import org.gradle.api.tasks.TaskProvider;
import org.gradle.api.artifacts.ConfigurationContainer;
import net.fabricmc.loom.LoomGradleExtension;
import net.fabricmc.loom.configuration.ConfigContext;
import net.fabricmc.loom.configuration.providers.mappings.MappingConfiguration;
import net.fabricmc.loom.configuration.providers.minecraft.mapped.MappedMinecraftProvider;
import net.fabricmc.loom.task.UnpickJarTask;
import net.fabricmc.loom.task.GenerateSourcesTask;
import net.fabricmc.loom.util.Constants;
public abstract class DecompileConfiguration<T extends MappedMinecraftProvider> {
protected final Project project;
@@ -50,11 +51,13 @@ public abstract class DecompileConfiguration<T extends MappedMinecraftProvider>
public abstract void afterEvaluation();
protected final TaskProvider<UnpickJarTask> createUnpickJarTask(String name, File inputJar, File outputJar) {
return project.getTasks().register(name, UnpickJarTask.class, unpickJarTask -> {
unpickJarTask.getUnpickDefinitions().set(mappingConfiguration.getUnpickDefinitionsFile());
unpickJarTask.getInputJar().set(inputJar);
unpickJarTask.getOutputJar().set(outputJar);
});
protected final void configureUnpick(GenerateSourcesTask task, File unpickOutputJar) {
final ConfigurationContainer configurations = task.getProject().getConfigurations();
task.getUnpickDefinitions().set(mappingConfiguration.getUnpickDefinitionsFile());
task.getUnpickOutputJar().set(unpickOutputJar);
task.getUnpickConstantJar().setFrom(configurations.getByName(Constants.Configurations.MAPPING_CONSTANTS));
task.getUnpickClasspath().setFrom(configurations.getByName(Constants.Configurations.MINECRAFT_COMPILE_LIBRARIES));
task.getUnpickClasspath().from(configurations.getByName(Constants.Configurations.MOD_COMPILE_CLASSPATH_MAPPED));
}
}

View File

@@ -25,11 +25,11 @@
package net.fabricmc.loom.configuration.decompile;
import java.io.File;
import java.nio.file.Path;
import java.util.List;
import net.fabricmc.loom.LoomGradleExtension;
import net.fabricmc.loom.configuration.ConfigContext;
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftJar;
import net.fabricmc.loom.configuration.providers.minecraft.mapped.MappedMinecraftProvider;
import net.fabricmc.loom.task.GenerateSourcesTask;
import net.fabricmc.loom.util.Constants;
@@ -41,36 +41,25 @@ public class SingleJarDecompileConfiguration extends DecompileConfiguration<Mapp
@Override
public final void afterEvaluation() {
List<Path> minecraftJars = minecraftProvider.getMinecraftJarPaths();
final List<MinecraftJar> minecraftJars = minecraftProvider.getMinecraftJars();
assert minecraftJars.size() == 1;
final File namedJar = minecraftJars.get(0).toFile();
File mappedJar = namedJar;
if (mappingConfiguration.hasUnpickDefinitions()) {
File outputJar = new File(extension.getMappingConfiguration().mappingsWorkingDir().toFile(), "minecraft-unpicked.jar");
createUnpickJarTask("unpickJar", namedJar, outputJar);
mappedJar = outputJar;
}
final File inputJar = mappedJar;
final MinecraftJar minecraftJar = minecraftJars.get(0);
LoomGradleExtension.get(project).getDecompilerOptions().forEach(options -> {
final String decompilerName = options.getFormattedName();
String taskName = "genSourcesWith" + decompilerName;
// Decompiler will be passed to the constructor of GenerateSourcesTask
project.getTasks().register(taskName, GenerateSourcesTask.class, options).configure(task -> {
task.getInputJar().set(inputJar);
task.getRuntimeJar().set(namedJar);
task.getInputJarName().set(minecraftJar.getName());
task.getOutputJar().fileValue(GenerateSourcesTask.getMappedJarFileWithSuffix("-sources.jar", minecraftJar.getPath()));
task.dependsOn(project.getTasks().named("validateAccessWidener"));
task.setDescription("Decompile minecraft using %s.".formatted(decompilerName));
task.setGroup(Constants.TaskGroup.FABRIC);
if (mappingConfiguration.hasUnpickDefinitions()) {
task.dependsOn(project.getTasks().named("unpickJar"));
final File outputJar = new File(extension.getMappingConfiguration().mappingsWorkingDir().toFile(), "minecraft-unpicked.jar");
configureUnpick(task, outputJar);
}
});
});

View File

@@ -32,9 +32,9 @@ import org.gradle.api.tasks.TaskProvider;
import net.fabricmc.loom.api.decompilers.DecompilerOptions;
import net.fabricmc.loom.configuration.ConfigContext;
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftJar;
import net.fabricmc.loom.configuration.providers.minecraft.mapped.MappedMinecraftProvider;
import net.fabricmc.loom.task.GenerateSourcesTask;
import net.fabricmc.loom.task.UnpickJarTask;
import net.fabricmc.loom.util.Constants;
public final class SplitDecompileConfiguration extends DecompileConfiguration<MappedMinecraftProvider.Split> {
@@ -44,41 +44,26 @@ public final class SplitDecompileConfiguration extends DecompileConfiguration<Ma
@Override
public void afterEvaluation() {
File commonJarToDecompile = minecraftProvider.getCommonJar().toFile();
File clientOnlyJarToDecompile = minecraftProvider.getClientOnlyJar().toFile();
TaskProvider<UnpickJarTask> unpickCommonJar = null;
TaskProvider<UnpickJarTask> unpickClientOnlyJar = null;
if (mappingConfiguration.hasUnpickDefinitions()) {
commonJarToDecompile = new File(extension.getMappingConfiguration().mappingsWorkingDir().toFile(), "minecraft-common-unpicked.jar");
clientOnlyJarToDecompile = new File(extension.getMappingConfiguration().mappingsWorkingDir().toFile(), "minecraft-clientonly-unpicked.jar");
unpickCommonJar = createUnpickJarTask("unpickCommonJar", minecraftProvider.getCommonJar().toFile(), commonJarToDecompile);
unpickClientOnlyJar = createUnpickJarTask("unpickClientOnlyJar", minecraftProvider.getClientOnlyJar().toFile(), clientOnlyJarToDecompile);
}
// Need to re-declare them as final to access them from the lambada
final File commonJar = commonJarToDecompile;
final File clientOnlyJar = clientOnlyJarToDecompile;
final TaskProvider<UnpickJarTask> unpickCommonJarTask = unpickCommonJar;
final TaskProvider<UnpickJarTask> unpickClientOnlyJarTask = unpickClientOnlyJar;
final MinecraftJar commonJar = minecraftProvider.getCommonJar();
final MinecraftJar clientOnlyJar = minecraftProvider.getClientOnlyJar();
final TaskProvider<Task> commonDecompileTask = createDecompileTasks("Common", task -> {
task.getInputJar().set(commonJar);
task.getRuntimeJar().set(minecraftProvider.getCommonJar().toFile());
task.getInputJarName().set(commonJar.getName());
task.getOutputJar().fileValue(GenerateSourcesTask.getMappedJarFileWithSuffix("-sources.jar", commonJar.getPath()));
if (unpickCommonJarTask != null) {
task.dependsOn(unpickCommonJarTask);
if (mappingConfiguration.hasUnpickDefinitions()) {
File unpickJar = new File(extension.getMappingConfiguration().mappingsWorkingDir().toFile(), "minecraft-common-unpicked.jar");
configureUnpick(task, unpickJar);
}
});
final TaskProvider<Task> clientOnlyDecompileTask = createDecompileTasks("ClientOnly", task -> {
task.getInputJar().set(clientOnlyJar);
task.getRuntimeJar().set(minecraftProvider.getClientOnlyJar().toFile());
task.getInputJarName().set(clientOnlyJar.getName());
task.getOutputJar().fileValue(GenerateSourcesTask.getMappedJarFileWithSuffix("-sources.jar", clientOnlyJar.getPath()));
if (unpickCommonJarTask != null) {
task.dependsOn(unpickClientOnlyJarTask);
if (mappingConfiguration.hasUnpickDefinitions()) {
File unpickJar = new File(extension.getMappingConfiguration().mappingsWorkingDir().toFile(), "minecraft-clientonly-unpicked.jar");
configureUnpick(task, unpickJar);
}
// Don't allow them to run at the same time.

View File

@@ -28,6 +28,8 @@ import java.util.List;
import java.util.function.BiFunction;
import java.util.function.Function;
import org.gradle.api.Project;
import net.fabricmc.loom.configuration.ConfigContext;
import net.fabricmc.loom.configuration.decompile.DecompileConfiguration;
import net.fabricmc.loom.configuration.decompile.SingleJarDecompileConfiguration;
@@ -73,8 +75,8 @@ public enum MinecraftJarConfiguration {
);
private final Function<ConfigContext, MinecraftProvider> minecraftProviderFunction;
private final BiFunction<ConfigContext, MinecraftProvider, IntermediaryMinecraftProvider<?>> intermediaryMinecraftProviderBiFunction;
private final BiFunction<ConfigContext, MinecraftProvider, NamedMinecraftProvider<?>> namedMinecraftProviderBiFunction;
private final BiFunction<Project, MinecraftProvider, IntermediaryMinecraftProvider<?>> intermediaryMinecraftProviderBiFunction;
private final BiFunction<Project, MinecraftProvider, NamedMinecraftProvider<?>> namedMinecraftProviderBiFunction;
private final BiFunction<NamedMinecraftProvider<?>, MinecraftJarProcessorManager, ProcessedNamedMinecraftProvider<?, ?>> processedNamedMinecraftProviderBiFunction;
private final BiFunction<ConfigContext, MappedMinecraftProvider, DecompileConfiguration<?>> decompileConfigurationBiFunction;
private final List<String> supportedEnvironments;
@@ -82,15 +84,15 @@ public enum MinecraftJarConfiguration {
@SuppressWarnings("unchecked") // Just a bit of a generic mess :)
<M extends MinecraftProvider, P extends NamedMinecraftProvider<M>, Q extends MappedMinecraftProvider> MinecraftJarConfiguration(
Function<ConfigContext, M> minecraftProviderFunction,
BiFunction<ConfigContext, M, IntermediaryMinecraftProvider<M>> intermediaryMinecraftProviderBiFunction,
BiFunction<ConfigContext, M, P> namedMinecraftProviderBiFunction,
BiFunction<Project, M, IntermediaryMinecraftProvider<M>> intermediaryMinecraftProviderBiFunction,
BiFunction<Project, M, P> namedMinecraftProviderBiFunction,
BiFunction<P, MinecraftJarProcessorManager, ProcessedNamedMinecraftProvider<M, P>> processedNamedMinecraftProviderBiFunction,
BiFunction<ConfigContext, Q, DecompileConfiguration<?>> decompileConfigurationBiFunction,
List<String> supportedEnvironments
) {
this.minecraftProviderFunction = (Function<ConfigContext, MinecraftProvider>) minecraftProviderFunction;
this.intermediaryMinecraftProviderBiFunction = (BiFunction<ConfigContext, MinecraftProvider, IntermediaryMinecraftProvider<?>>) (Object) intermediaryMinecraftProviderBiFunction;
this.namedMinecraftProviderBiFunction = (BiFunction<ConfigContext, MinecraftProvider, NamedMinecraftProvider<?>>) namedMinecraftProviderBiFunction;
this.intermediaryMinecraftProviderBiFunction = (BiFunction<Project, MinecraftProvider, IntermediaryMinecraftProvider<?>>) (Object) intermediaryMinecraftProviderBiFunction;
this.namedMinecraftProviderBiFunction = (BiFunction<Project, MinecraftProvider, NamedMinecraftProvider<?>>) namedMinecraftProviderBiFunction;
this.processedNamedMinecraftProviderBiFunction = (BiFunction<NamedMinecraftProvider<?>, MinecraftJarProcessorManager, ProcessedNamedMinecraftProvider<?, ?>>) (Object) processedNamedMinecraftProviderBiFunction;
this.decompileConfigurationBiFunction = (BiFunction<ConfigContext, MappedMinecraftProvider, DecompileConfiguration<?>>) decompileConfigurationBiFunction;
this.supportedEnvironments = supportedEnvironments;
@@ -100,11 +102,11 @@ public enum MinecraftJarConfiguration {
return minecraftProviderFunction;
}
public BiFunction<ConfigContext, MinecraftProvider, IntermediaryMinecraftProvider<?>> getIntermediaryMinecraftProviderBiFunction() {
public BiFunction<Project, MinecraftProvider, IntermediaryMinecraftProvider<?>> getIntermediaryMinecraftProviderBiFunction() {
return intermediaryMinecraftProviderBiFunction;
}
public BiFunction<ConfigContext, MinecraftProvider, NamedMinecraftProvider<?>> getNamedMinecraftProviderBiFunction() {
public BiFunction<Project, MinecraftProvider, NamedMinecraftProvider<?>> getNamedMinecraftProviderBiFunction() {
return namedMinecraftProviderBiFunction;
}

View File

@@ -53,13 +53,13 @@ import net.fabricmc.tinyremapper.TinyRemapper;
public abstract class AbstractMappedMinecraftProvider<M extends MinecraftProvider> implements MappedMinecraftProvider.ProviderImpl {
protected final M minecraftProvider;
protected final ConfigContext configContext;
private final Project project;
protected final LoomGradleExtension extension;
public AbstractMappedMinecraftProvider(ConfigContext configContext, M minecraftProvider) {
this.configContext = configContext;
public AbstractMappedMinecraftProvider(Project project, M minecraftProvider) {
this.minecraftProvider = minecraftProvider;
this.extension = configContext.extension();
this.project = project;
this.extension = LoomGradleExtension.get(project);
}
public abstract MappingsNamespace getTargetNamespace();
@@ -70,13 +70,13 @@ public abstract class AbstractMappedMinecraftProvider<M extends MinecraftProvide
return Collections.emptyList();
}
public void provide(boolean applyDependencies) throws Exception {
public List<MinecraftJar> provide(ProvideContext context) throws Exception {
final List<RemappedJars> remappedJars = getRemappedJars();
assert !remappedJars.isEmpty();
if (!areOutputsValid(remappedJars) || extension.refreshDeps()) {
if (!areOutputsValid(remappedJars) || context.refreshOutputs()) {
try {
remapInputs(remappedJars);
remapInputs(remappedJars, context.configContext());
} catch (Throwable t) {
cleanOutputs(remappedJars);
@@ -84,17 +84,25 @@ public abstract class AbstractMappedMinecraftProvider<M extends MinecraftProvide
}
}
if (applyDependencies) {
if (context.applyDependencies()) {
final List<String> dependencyTargets = getDependencyTargets();
if (dependencyTargets.isEmpty()) {
return;
if (!dependencyTargets.isEmpty()) {
MinecraftSourceSets.get(getProject()).applyDependencies(
(configuration, name) -> getProject().getDependencies().add(configuration, getDependencyNotation(name)),
dependencyTargets
);
}
}
MinecraftSourceSets.get(getProject()).applyDependencies(
(configuration, name) -> getProject().getDependencies().add(configuration, getDependencyNotation(name)),
dependencyTargets
);
return remappedJars.stream()
.map(RemappedJars::outputJar)
.toList();
}
public record ProvideContext(boolean applyDependencies, boolean refreshOutputs, ConfigContext configContext) {
ProvideContext withApplyDependencies(boolean applyDependencies) {
return new ProvideContext(applyDependencies, refreshOutputs(), configContext());
}
}
@@ -154,15 +162,15 @@ public abstract class AbstractMappedMinecraftProvider<M extends MinecraftProvide
return true;
}
private void remapInputs(List<RemappedJars> remappedJars) throws IOException {
private void remapInputs(List<RemappedJars> remappedJars, ConfigContext configContext) throws IOException {
cleanOutputs(remappedJars);
for (RemappedJars remappedJar : remappedJars) {
remapJar(remappedJar);
remapJar(remappedJar, configContext);
}
}
private void remapJar(RemappedJars remappedJars) throws IOException {
private void remapJar(RemappedJars remappedJars, ConfigContext configContext) throws IOException {
final MappingConfiguration mappingConfiguration = extension.getMappingConfiguration();
final String fromM = remappedJars.sourceNamespace().toString();
final String toM = getTargetNamespace().toString();
@@ -214,12 +222,8 @@ public abstract class AbstractMappedMinecraftProvider<M extends MinecraftProvide
}
}
public ConfigContext getConfigContext() {
return configContext;
}
public Project getProject() {
return getConfigContext().project();
return project;
}
public M getMinecraftProvider() {

View File

@@ -26,8 +26,9 @@ package net.fabricmc.loom.configuration.providers.minecraft.mapped;
import java.util.List;
import org.gradle.api.Project;
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
import net.fabricmc.loom.configuration.ConfigContext;
import net.fabricmc.loom.configuration.providers.minecraft.MergedMinecraftProvider;
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftProvider;
import net.fabricmc.loom.configuration.providers.minecraft.SingleJarEnvType;
@@ -36,8 +37,8 @@ import net.fabricmc.loom.configuration.providers.minecraft.SplitMinecraftProvide
import net.fabricmc.tinyremapper.TinyRemapper;
public abstract sealed class IntermediaryMinecraftProvider<M extends MinecraftProvider> extends AbstractMappedMinecraftProvider<M> permits IntermediaryMinecraftProvider.MergedImpl, IntermediaryMinecraftProvider.SingleJarImpl, IntermediaryMinecraftProvider.SplitImpl {
public IntermediaryMinecraftProvider(ConfigContext configContext, M minecraftProvider) {
super(configContext, minecraftProvider);
public IntermediaryMinecraftProvider(Project project, M minecraftProvider) {
super(project, minecraftProvider);
}
@Override
@@ -51,8 +52,8 @@ public abstract sealed class IntermediaryMinecraftProvider<M extends MinecraftPr
}
public static final class MergedImpl extends IntermediaryMinecraftProvider<MergedMinecraftProvider> implements Merged {
public MergedImpl(ConfigContext configContext, MergedMinecraftProvider minecraftProvider) {
super(configContext, minecraftProvider);
public MergedImpl(Project project, MergedMinecraftProvider minecraftProvider) {
super(project, minecraftProvider);
}
@Override
@@ -64,8 +65,8 @@ public abstract sealed class IntermediaryMinecraftProvider<M extends MinecraftPr
}
public static final class SplitImpl extends IntermediaryMinecraftProvider<SplitMinecraftProvider> implements Split {
public SplitImpl(ConfigContext configContext, SplitMinecraftProvider minecraftProvider) {
super(configContext, minecraftProvider);
public SplitImpl(Project project, SplitMinecraftProvider minecraftProvider) {
super(project, minecraftProvider);
}
@Override
@@ -85,17 +86,17 @@ public abstract sealed class IntermediaryMinecraftProvider<M extends MinecraftPr
public static final class SingleJarImpl extends IntermediaryMinecraftProvider<SingleJarMinecraftProvider> implements SingleJar {
private final SingleJarEnvType env;
private SingleJarImpl(ConfigContext configContext, SingleJarMinecraftProvider minecraftProvider, SingleJarEnvType env) {
super(configContext, minecraftProvider);
private SingleJarImpl(Project project, SingleJarMinecraftProvider minecraftProvider, SingleJarEnvType env) {
super(project, minecraftProvider);
this.env = env;
}
public static SingleJarImpl server(ConfigContext configContext, SingleJarMinecraftProvider minecraftProvider) {
return new SingleJarImpl(configContext, minecraftProvider, SingleJarEnvType.SERVER);
public static SingleJarImpl server(Project project, SingleJarMinecraftProvider minecraftProvider) {
return new SingleJarImpl(project, minecraftProvider, SingleJarEnvType.SERVER);
}
public static SingleJarImpl client(ConfigContext configContext, SingleJarMinecraftProvider minecraftProvider) {
return new SingleJarImpl(configContext, minecraftProvider, SingleJarEnvType.CLIENT);
public static SingleJarImpl client(Project project, SingleJarMinecraftProvider minecraftProvider) {
return new SingleJarImpl(project, minecraftProvider, SingleJarEnvType.CLIENT);
}
@Override

View File

@@ -26,8 +26,9 @@ package net.fabricmc.loom.configuration.providers.minecraft.mapped;
import java.util.List;
import org.gradle.api.Project;
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
import net.fabricmc.loom.configuration.ConfigContext;
import net.fabricmc.loom.configuration.providers.minecraft.MergedMinecraftProvider;
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftProvider;
import net.fabricmc.loom.configuration.providers.minecraft.SingleJarEnvType;
@@ -36,8 +37,8 @@ import net.fabricmc.loom.configuration.providers.minecraft.SplitMinecraftProvide
import net.fabricmc.tinyremapper.TinyRemapper;
public abstract class NamedMinecraftProvider<M extends MinecraftProvider> extends AbstractMappedMinecraftProvider<M> {
public NamedMinecraftProvider(ConfigContext configContext, M minecraftProvider) {
super(configContext, minecraftProvider);
public NamedMinecraftProvider(Project project, M minecraftProvider) {
super(project, minecraftProvider);
}
@Override
@@ -51,8 +52,8 @@ public abstract class NamedMinecraftProvider<M extends MinecraftProvider> extend
}
public static final class MergedImpl extends NamedMinecraftProvider<MergedMinecraftProvider> implements Merged {
public MergedImpl(ConfigContext configContext, MergedMinecraftProvider minecraftProvider) {
super(configContext, minecraftProvider);
public MergedImpl(Project project, MergedMinecraftProvider minecraftProvider) {
super(project, minecraftProvider);
}
@Override
@@ -69,8 +70,8 @@ public abstract class NamedMinecraftProvider<M extends MinecraftProvider> extend
}
public static final class SplitImpl extends NamedMinecraftProvider<SplitMinecraftProvider> implements Split {
public SplitImpl(ConfigContext configContext, SplitMinecraftProvider minecraftProvider) {
super(configContext, minecraftProvider);
public SplitImpl(Project project, SplitMinecraftProvider minecraftProvider) {
super(project, minecraftProvider);
}
@Override
@@ -95,17 +96,17 @@ public abstract class NamedMinecraftProvider<M extends MinecraftProvider> extend
public static final class SingleJarImpl extends NamedMinecraftProvider<SingleJarMinecraftProvider> implements SingleJar {
private final SingleJarEnvType env;
private SingleJarImpl(ConfigContext configContext, SingleJarMinecraftProvider minecraftProvider, SingleJarEnvType env) {
super(configContext, minecraftProvider);
private SingleJarImpl(Project project, SingleJarMinecraftProvider minecraftProvider, SingleJarEnvType env) {
super(project, minecraftProvider);
this.env = env;
}
public static SingleJarImpl server(ConfigContext configContext, SingleJarMinecraftProvider minecraftProvider) {
return new SingleJarImpl(configContext, minecraftProvider, SingleJarEnvType.SERVER);
public static SingleJarImpl server(Project project, SingleJarMinecraftProvider minecraftProvider) {
return new SingleJarImpl(project, minecraftProvider, SingleJarEnvType.SERVER);
}
public static SingleJarImpl client(ConfigContext configContext, SingleJarMinecraftProvider minecraftProvider) {
return new SingleJarImpl(configContext, minecraftProvider, SingleJarEnvType.CLIENT);
public static SingleJarImpl client(Project project, SingleJarMinecraftProvider minecraftProvider) {
return new SingleJarImpl(project, minecraftProvider, SingleJarEnvType.CLIENT);
}
@Override

View File

@@ -29,10 +29,14 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.gradle.api.Project;
import net.fabricmc.loom.configuration.ConfigContext;
import net.fabricmc.loom.configuration.mods.dependency.LocalMavenHelper;
import net.fabricmc.loom.configuration.processors.MinecraftJarProcessorManager;
import net.fabricmc.loom.configuration.processors.ProcessorContextImpl;
@@ -49,26 +53,31 @@ public abstract class ProcessedNamedMinecraftProvider<M extends MinecraftProvide
private final MinecraftJarProcessorManager jarProcessorManager;
public ProcessedNamedMinecraftProvider(P parentMinecraftProvide, MinecraftJarProcessorManager jarProcessorManager) {
super(parentMinecraftProvide.getConfigContext(), parentMinecraftProvide.getMinecraftProvider());
super(parentMinecraftProvide.getProject(), parentMinecraftProvide.getMinecraftProvider());
this.parentMinecraftProvider = parentMinecraftProvide;
this.jarProcessorManager = Objects.requireNonNull(jarProcessorManager);
}
@Override
public void provide(boolean applyDependencies) throws Exception {
parentMinecraftProvider.provide(false);
public List<MinecraftJar> provide(ProvideContext context) throws Exception {
parentMinecraftProvider.provide(context.withApplyDependencies(false));
boolean requiresProcessing = parentMinecraftProvider.getMinecraftJars().stream()
boolean requiresProcessing = context.refreshOutputs() || parentMinecraftProvider.getMinecraftJars().stream()
.map(this::getProcessedPath)
.anyMatch(jarProcessorManager::requiresProcessingJar);
final Map<MinecraftJar, MinecraftJar> minecraftJarOutputMap = parentMinecraftProvider.getMinecraftJars().stream()
.collect(Collectors.toMap(Function.identity(), this::getProcessedJar));
if (requiresProcessing) {
processJars();
processJars(minecraftJarOutputMap, context.configContext());
}
if (applyDependencies) {
if (context.applyDependencies()) {
applyDependencies();
}
return List.copyOf(minecraftJarOutputMap.values());
}
@Override
@@ -76,14 +85,17 @@ public abstract class ProcessedNamedMinecraftProvider<M extends MinecraftProvide
return MavenScope.LOCAL;
}
private void processJars() throws IOException {
for (MinecraftJar minecraftJar : parentMinecraftProvider.getMinecraftJars()) {
final MinecraftJar outputJar = getProcessedJar(minecraftJar);
private void processJars(Map<MinecraftJar, MinecraftJar> minecraftJarMap, ConfigContext configContext) throws IOException {
for (Map.Entry<MinecraftJar, MinecraftJar> entry : minecraftJarMap.entrySet()) {
final MinecraftJar minecraftJar = entry.getKey();
final MinecraftJar outputJar = entry.getValue();
deleteSimilarJars(outputJar.getPath());
final LocalMavenHelper mavenHelper = getMavenHelper(minecraftJar.getName());
final Path outputPath = mavenHelper.copyToMaven(minecraftJar.getPath(), null);
assert outputJar.getPath().equals(outputPath);
jarProcessorManager.processJar(outputPath, new ProcessorContextImpl(configContext, minecraftJar));
}
}

View File

@@ -26,6 +26,7 @@ package net.fabricmc.loom.task;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.io.UncheckedIOException;
import java.io.Writer;
@@ -49,10 +50,13 @@ import org.gradle.api.file.ConfigurableFileCollection;
import org.gradle.api.file.RegularFileProperty;
import org.gradle.api.provider.Property;
import org.gradle.api.services.ServiceReference;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.InputFile;
import org.gradle.api.tasks.InputFiles;
import org.gradle.api.tasks.OutputFile;
import org.gradle.api.tasks.TaskAction;
import org.gradle.process.ExecOperations;
import org.gradle.process.ExecResult;
import org.gradle.work.DisableCachingByDefault;
import org.gradle.workers.WorkAction;
import org.gradle.workers.WorkParameters;
@@ -68,6 +72,8 @@ import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
import net.fabricmc.loom.configuration.ConfigContextImpl;
import net.fabricmc.loom.configuration.processors.MappingProcessorContextImpl;
import net.fabricmc.loom.configuration.processors.MinecraftJarProcessorManager;
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftJar;
import net.fabricmc.loom.configuration.providers.minecraft.mapped.AbstractMappedMinecraftProvider;
import net.fabricmc.loom.decompilers.LineNumberRemapper;
import net.fabricmc.loom.util.Constants;
import net.fabricmc.loom.util.FileSystemUtil;
@@ -90,16 +96,10 @@ public abstract class GenerateSourcesTask extends AbstractLoomTask {
private final DecompilerOptions decompilerOptions;
/**
* The jar to decompile, can be the unpick jar.
* The jar name to decompile, {@link MinecraftJar#getName()}.
*/
@InputFile
public abstract RegularFileProperty getInputJar();
/**
* The jar used at runtime.
*/
@InputFile
public abstract RegularFileProperty getRuntimeJar();
@Input
public abstract Property<String> getInputJarName();
@InputFiles
public abstract ConfigurableFileCollection getClasspath();
@@ -107,9 +107,26 @@ public abstract class GenerateSourcesTask extends AbstractLoomTask {
@OutputFile
public abstract RegularFileProperty getOutputJar();
// Unpick
@InputFile
public abstract RegularFileProperty getUnpickDefinitions();
@InputFiles
public abstract ConfigurableFileCollection getUnpickConstantJar();
@InputFiles
public abstract ConfigurableFileCollection getUnpickClasspath();
@OutputFile
public abstract RegularFileProperty getUnpickOutputJar();
// Injects
@Inject
public abstract WorkerExecutor getWorkerExecutor();
@Inject
public abstract ExecOperations getExecOperations();
@Inject
public abstract WorkerDaemonClientsManager getWorkerDaemonClientsManager();
@@ -124,8 +141,6 @@ public abstract class GenerateSourcesTask extends AbstractLoomTask {
getOutputs().upToDateWhen((o) -> false);
getClasspath().from(decompilerOptions.getClasspath()).finalizeValueOnRead();
dependsOn(decompilerOptions.getClasspath().getBuiltBy());
getOutputJar().fileProvider(getProject().provider(() -> getMappedJarFileWithSuffix("-sources.jar")));
}
@TaskAction
@@ -136,10 +151,20 @@ public abstract class GenerateSourcesTask extends AbstractLoomTask {
throw new UnsupportedOperationException("GenSources task requires a 64bit JVM to run due to the memory requirements.");
}
final MinecraftJar minecraftJar = rebuildInputJar();
// Input jar is the jar to decompile, this may be unpicked.
Path inputJar = minecraftJar.getPath();
// Runtime jar is the jar used to run the game
final Path runtimeJar = inputJar;
if (getUnpickDefinitions().isPresent()) {
inputJar = unpickJar(inputJar);
}
if (!platform.supportsUnixDomainSockets()) {
getProject().getLogger().warn("Decompile worker logging disabled as Unix Domain Sockets is not supported on your operating system.");
doWork(null);
doWork(null, inputJar, runtimeJar);
return;
}
@@ -149,7 +174,7 @@ public abstract class GenerateSourcesTask extends AbstractLoomTask {
try (ThreadedProgressLoggerConsumer loggerConsumer = new ThreadedProgressLoggerConsumer(getProject(), decompilerOptions.getName(), "Decompiling minecraft sources");
IPCServer logReceiver = new IPCServer(ipcPath, loggerConsumer)) {
doWork(logReceiver);
doWork(logReceiver, inputJar, runtimeJar);
} catch (InterruptedException e) {
throw new RuntimeException("Failed to shutdown log receiver", e);
} finally {
@@ -157,18 +182,94 @@ public abstract class GenerateSourcesTask extends AbstractLoomTask {
}
}
private void doWork(@Nullable IPCServer ipcServer) {
// Re-run the named minecraft provider to give us a fresh jar to decompile.
// This prevents re-applying line maps on an existing jar.
private MinecraftJar rebuildInputJar() {
final List<MinecraftJar> minecraftJars;
try (var serviceManager = new ScopedSharedServiceManager()) {
final var configContext = new ConfigContextImpl(getProject(), serviceManager, getExtension());
final var provideContext = new AbstractMappedMinecraftProvider.ProvideContext(false, true, configContext);
minecraftJars = getExtension().getNamedMinecraftProvider().provide(provideContext);
} catch (Exception e) {
throw new RuntimeException("Failed to rebuild input jars", e);
}
for (MinecraftJar minecraftJar : minecraftJars) {
if (minecraftJar.getName().equals(getInputJarName().get())) {
return minecraftJar;
}
}
throw new IllegalStateException("Could not find minecraft jar (%s) but got (%s)".formatted(
getInputJarName().get(),
minecraftJars.stream().map(MinecraftJar::getName).collect(Collectors.joining(", ")))
);
}
private Path unpickJar(Path inputJar) {
final Path outputJar = getUnpickOutputJar().get().getAsFile().toPath();
final List<String> args = getUnpickArgs(inputJar, outputJar);
ExecResult result = getExecOperations().javaexec(spec -> {
spec.getMainClass().set("daomephsta.unpick.cli.Main");
spec.classpath(getProject().getConfigurations().getByName(Constants.Configurations.UNPICK_CLASSPATH));
spec.args(args);
spec.systemProperty("java.util.logging.config.file", writeUnpickLogConfig().getAbsolutePath());
});
result.rethrowFailure();
return outputJar;
}
private List<String> getUnpickArgs(Path inputJar, Path outputJar) {
var fileArgs = new ArrayList<File>();
fileArgs.add(inputJar.toFile());
fileArgs.add(outputJar.toFile());
fileArgs.add(getUnpickDefinitions().get().getAsFile());
fileArgs.add(getUnpickConstantJar().getSingleFile());
// Classpath
for (Path minecraftJar : getExtension().getMinecraftJars(MappingsNamespace.NAMED)) {
fileArgs.add(minecraftJar.toFile());
}
for (File file : getUnpickClasspath()) {
fileArgs.add(file);
}
return fileArgs.stream()
.map(File::getAbsolutePath)
.toList();
}
private File writeUnpickLogConfig() {
final File unpickLoggingConfigFile = getExtension().getFiles().getUnpickLoggingConfigFile();
try (InputStream is = GenerateSourcesTask.class.getClassLoader().getResourceAsStream("unpick-logging.properties")) {
Files.deleteIfExists(unpickLoggingConfigFile.toPath());
Files.copy(Objects.requireNonNull(is), unpickLoggingConfigFile.toPath());
} catch (IOException e) {
throw new org.gradle.api.UncheckedIOException("Failed to copy unpick logging config", e);
}
return unpickLoggingConfigFile;
}
private void doWork(@Nullable IPCServer ipcServer, Path inputJar, Path runtimeJar) {
final String jvmMarkerValue = UUID.randomUUID().toString();
final WorkQueue workQueue = createWorkQueue(jvmMarkerValue);
workQueue.submit(DecompileAction.class, params -> {
params.getDecompilerOptions().set(decompilerOptions.toDto());
params.getInputJar().set(getInputJar());
params.getRuntimeJar().set(getRuntimeJar());
params.getInputJar().set(inputJar.toFile());
params.getRuntimeJar().set(runtimeJar.toFile());
params.getSourcesDestinationJar().set(getOutputJar());
params.getLinemap().set(getMappedJarFileWithSuffix("-sources.lmap"));
params.getLinemapJar().set(getMappedJarFileWithSuffix("-linemapped.jar"));
params.getLinemap().set(getMappedJarFileWithSuffix("-sources.lmap", runtimeJar));
params.getLinemapJar().set(getMappedJarFileWithSuffix("-linemapped.jar", runtimeJar));
params.getMappings().set(getMappings().toFile());
if (ipcServer != null) {
@@ -317,8 +418,8 @@ public abstract class GenerateSourcesTask extends AbstractLoomTask {
}
}
private File getMappedJarFileWithSuffix(String suffix) {
String path = getRuntimeJar().get().getAsFile().getAbsolutePath();
public static File getMappedJarFileWithSuffix(String suffix, Path runtimeJar) {
final String path = runtimeJar.toFile().getAbsolutePath();
if (!path.toLowerCase(Locale.ROOT).endsWith(".jar")) {
throw new RuntimeException("Invalid mapped JAR path: " + path);

View File

@@ -1,118 +0,0 @@
/*
* 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.task;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import javax.inject.Inject;
import org.gradle.api.file.ConfigurableFileCollection;
import org.gradle.api.file.RegularFileProperty;
import org.gradle.api.tasks.InputFile;
import org.gradle.api.tasks.InputFiles;
import org.gradle.api.tasks.Internal;
import org.gradle.api.tasks.JavaExec;
import org.gradle.api.tasks.OutputFile;
import net.fabricmc.loom.LoomGradleExtension;
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
import net.fabricmc.loom.extension.LoomFiles;
import net.fabricmc.loom.util.Constants;
public abstract class UnpickJarTask extends JavaExec {
@InputFile
public abstract RegularFileProperty getInputJar();
@InputFile
public abstract RegularFileProperty getUnpickDefinitions();
@InputFiles
// Only 1 file, but it comes from a configuration
public abstract ConfigurableFileCollection getConstantJar();
@InputFiles
public abstract ConfigurableFileCollection getUnpickClasspath();
@OutputFile
public abstract RegularFileProperty getOutputJar();
@Inject
public UnpickJarTask() {
classpath(getProject().getConfigurations().getByName(Constants.Configurations.UNPICK_CLASSPATH));
getMainClass().set("daomephsta.unpick.cli.Main");
getConstantJar().setFrom(getProject().getConfigurations().getByName(Constants.Configurations.MAPPING_CONSTANTS));
getUnpickClasspath().setFrom(getProject().getConfigurations().getByName(Constants.Configurations.MINECRAFT_COMPILE_LIBRARIES));
getUnpickClasspath().from(getProject().getConfigurations().getByName(Constants.Configurations.MOD_COMPILE_CLASSPATH_MAPPED));
}
@Override
public void exec() {
fileArg(getInputJar().get().getAsFile(), getOutputJar().get().getAsFile(), getUnpickDefinitions().get().getAsFile());
fileArg(getConstantJar().getSingleFile());
// Classpath
for (Path minecraftJar : getExtension().getMinecraftJars(MappingsNamespace.NAMED)) {
fileArg(minecraftJar.toFile());
}
for (File file : getUnpickClasspath()) {
fileArg(file);
}
writeUnpickLogConfig();
systemProperty("java.util.logging.config.file", getDirectories().getUnpickLoggingConfigFile().getAbsolutePath());
super.exec();
}
private void writeUnpickLogConfig() {
try (InputStream is = UnpickJarTask.class.getClassLoader().getResourceAsStream("unpick-logging.properties")) {
Files.deleteIfExists(getDirectories().getUnpickLoggingConfigFile().toPath());
Files.copy(is, getDirectories().getUnpickLoggingConfigFile().toPath());
} catch (IOException e) {
throw new RuntimeException("Failed to copy unpick logging config", e);
}
}
private void fileArg(File... files) {
for (File file : files) {
args(file.getAbsolutePath());
}
}
@Internal
protected LoomGradleExtension getExtension() {
return LoomGradleExtension.get(getProject());
}
private LoomFiles getDirectories() {
return getExtension().getFiles();
}
}