mirror of
https://github.com/architectury/architectury-loom.git
synced 2026-04-02 05:27:43 -05:00
Merge remote-tracking branch 'upstream/dev/0.11' into dev/0.11.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/build/mixin/AnnotationProcessorInvoker.java # src/main/java/net/fabricmc/loom/configuration/CompileConfiguration.java # src/main/java/net/fabricmc/loom/configuration/DependencyProvider.java # src/main/java/net/fabricmc/loom/configuration/LoomDependencyManager.java # src/main/java/net/fabricmc/loom/configuration/mods/ModProcessor.java # src/main/java/net/fabricmc/loom/configuration/processors/MinecraftProcessedProvider.java # src/main/java/net/fabricmc/loom/configuration/providers/mappings/MappingsProviderImpl.java # src/main/java/net/fabricmc/loom/configuration/providers/mappings/intermediary/IntermediaryMappingLayer.java # src/main/java/net/fabricmc/loom/configuration/providers/mappings/intermediary/IntermediaryMappingsSpec.java # src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftMappedProvider.java # src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftProvider.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/task/GenerateSourcesTask.java # src/main/java/net/fabricmc/loom/task/LoomTasks.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/ValidateAccessWidenerTask.java # src/main/java/net/fabricmc/loom/task/launch/GenerateDLIConfigTask.java # src/main/java/net/fabricmc/loom/task/service/MappingsService.java # src/main/java/net/fabricmc/loom/util/Checksum.java # src/main/java/net/fabricmc/loom/util/HashedDownloadUtil.java # src/test/resources/projects/kotlin/build.gradle.kts
This commit is contained in:
@@ -24,7 +24,7 @@
|
||||
|
||||
package net.fabricmc.loom;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@@ -36,9 +36,9 @@ import org.gradle.api.Project;
|
||||
import org.gradle.api.artifacts.Configuration;
|
||||
import org.gradle.api.file.ConfigurableFileCollection;
|
||||
import org.gradle.api.file.FileCollection;
|
||||
import org.gradle.api.tasks.SourceSet;
|
||||
|
||||
import net.fabricmc.loom.api.LoomGradleExtensionAPI;
|
||||
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
|
||||
import net.fabricmc.loom.configuration.InstallerData;
|
||||
import net.fabricmc.loom.configuration.LoomDependencyManager;
|
||||
import net.fabricmc.loom.configuration.accesswidener.AccessWidenerFile;
|
||||
@@ -52,7 +52,9 @@ import net.fabricmc.loom.configuration.providers.forge.McpConfigProvider;
|
||||
import net.fabricmc.loom.configuration.providers.forge.PatchProvider;
|
||||
import net.fabricmc.loom.configuration.providers.forge.SrgProvider;
|
||||
import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftMappedProvider;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftProvider;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.mapped.IntermediaryMinecraftProvider;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.mapped.NamedMinecraftProvider;
|
||||
import net.fabricmc.loom.extension.LoomFiles;
|
||||
import net.fabricmc.loom.extension.MixinExtension;
|
||||
|
||||
@@ -90,21 +92,31 @@ public interface LoomGradleExtension extends LoomGradleExtensionAPI {
|
||||
|
||||
JarProcessorManager getJarProcessorManager();
|
||||
|
||||
default MinecraftProviderImpl getMinecraftProvider() {
|
||||
return getDependencyManager().getProvider(MinecraftProviderImpl.class);
|
||||
MinecraftProvider getMinecraftProvider();
|
||||
|
||||
void setMinecraftProvider(MinecraftProvider minecraftProvider);
|
||||
|
||||
MappingsProviderImpl getMappingsProvider();
|
||||
|
||||
void setMappingsProvider(MappingsProviderImpl mappingsProvider);
|
||||
|
||||
NamedMinecraftProvider<?> getNamedMinecraftProvider();
|
||||
|
||||
IntermediaryMinecraftProvider<?> getIntermediaryMinecraftProvider();
|
||||
|
||||
void setNamedMinecraftProvider(NamedMinecraftProvider<?> namedMinecraftProvider);
|
||||
|
||||
void setIntermediaryMinecraftProvider(IntermediaryMinecraftProvider<?> intermediaryMinecraftProvider);
|
||||
|
||||
default List<Path> getMinecraftJars(MappingsNamespace mappingsNamespace) {
|
||||
return switch (mappingsNamespace) {
|
||||
case NAMED -> getNamedMinecraftProvider().getMinecraftJars();
|
||||
case INTERMEDIARY -> getIntermediaryMinecraftProvider().getMinecraftJars();
|
||||
case OFFICIAL -> getMinecraftProvider().getMinecraftJars();
|
||||
};
|
||||
}
|
||||
|
||||
default MappingsProviderImpl getMappingsProvider() {
|
||||
return getDependencyManager().getProvider(isForge() ? FieldMigratedMappingsProvider.class : MappingsProviderImpl.class);
|
||||
}
|
||||
|
||||
default MinecraftMappedProvider getMinecraftMappedProvider() {
|
||||
return getMappingsProvider().mappedProvider;
|
||||
}
|
||||
|
||||
File getMixinMappings(SourceSet sourceSet);
|
||||
|
||||
FileCollection getAllMixinMappings();
|
||||
FileCollection getMinecraftJarsCollection(MappingsNamespace mappingsNamespace);
|
||||
|
||||
boolean isRootProject();
|
||||
|
||||
|
||||
@@ -28,7 +28,6 @@ import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.gradle.api.Action;
|
||||
import org.gradle.api.DomainObjectCollection;
|
||||
import org.gradle.api.NamedDomainObjectContainer;
|
||||
import org.gradle.api.artifacts.Dependency;
|
||||
import org.gradle.api.file.ConfigurableFileCollection;
|
||||
@@ -39,13 +38,14 @@ import org.gradle.api.provider.Provider;
|
||||
import org.gradle.api.publish.maven.MavenPublication;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import net.fabricmc.loom.api.decompilers.LoomDecompiler;
|
||||
import net.fabricmc.loom.api.decompilers.DecompilerOptions;
|
||||
import net.fabricmc.loom.api.decompilers.architectury.ArchitecturyLoomDecompiler;
|
||||
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.minecraft.MinecraftJarConfiguration;
|
||||
import net.fabricmc.loom.util.DeprecationHelper;
|
||||
import net.fabricmc.loom.util.ModPlatform;
|
||||
|
||||
@@ -64,11 +64,9 @@ public interface LoomGradleExtensionAPI {
|
||||
getShareRemapCaches().set(true);
|
||||
}
|
||||
|
||||
DomainObjectCollection<LoomDecompiler> getGameDecompilers();
|
||||
NamedDomainObjectContainer<DecompilerOptions> getDecompilerOptions();
|
||||
|
||||
default void addDecompiler(LoomDecompiler decompiler) {
|
||||
getGameDecompilers().add(decompiler);
|
||||
}
|
||||
void decompilers(Action<NamedDomainObjectContainer<DecompilerOptions>> action);
|
||||
|
||||
ListProperty<JarProcessor> getGameJarProcessors();
|
||||
|
||||
@@ -150,6 +148,19 @@ public interface LoomGradleExtensionAPI {
|
||||
*/
|
||||
Property<Boolean> getEnableInterfaceInjection();
|
||||
|
||||
@ApiStatus.Experimental
|
||||
Property<MinecraftJarConfiguration> getMinecraftJarConfiguration();
|
||||
|
||||
@ApiStatus.Experimental
|
||||
default void serverOnlyMinecraftJar() {
|
||||
getMinecraftJarConfiguration().set(MinecraftJarConfiguration.SERVER_ONLY);
|
||||
}
|
||||
|
||||
@ApiStatus.Experimental
|
||||
default void splitMinecraftJar() {
|
||||
getMinecraftJarConfiguration().set(MinecraftJarConfiguration.SPLIT);
|
||||
}
|
||||
|
||||
// ===================
|
||||
// Architectury Loom
|
||||
// ===================
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2022 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.decompilers;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import org.gradle.api.Named;
|
||||
import org.gradle.api.file.ConfigurableFileCollection;
|
||||
import org.gradle.api.provider.MapProperty;
|
||||
import org.gradle.api.provider.Property;
|
||||
|
||||
public abstract class DecompilerOptions implements Named {
|
||||
/**
|
||||
* Class name for to the {@link LoomDecompiler}.
|
||||
*/
|
||||
public abstract Property<String> getDecompilerClassName();
|
||||
|
||||
/**
|
||||
* Additional classpath entries for the decompiler jvm.
|
||||
*/
|
||||
public abstract ConfigurableFileCollection getClasspath();
|
||||
|
||||
/**
|
||||
* Additional options to be passed to the decompiler.
|
||||
*/
|
||||
public abstract MapProperty<String, String> getOptions();
|
||||
|
||||
/**
|
||||
* Memory used for forked JVM in megabytes.
|
||||
*/
|
||||
public abstract Property<Long> getMemory();
|
||||
|
||||
/**
|
||||
* Maximum number of threads the decompiler is allowed to use.
|
||||
*/
|
||||
public abstract Property<Integer> getMaxThreads();
|
||||
|
||||
public DecompilerOptions() {
|
||||
getDecompilerClassName().finalizeValueOnRead();
|
||||
getClasspath().finalizeValueOnRead();
|
||||
getOptions().finalizeValueOnRead();
|
||||
getMemory().convention(4096L).finalizeValueOnRead();
|
||||
getMaxThreads().convention(Runtime.getRuntime().availableProcessors()).finalizeValueOnRead();
|
||||
}
|
||||
|
||||
// Done to work around weird issues with the workers, possibly https://github.com/gradle/gradle/issues/13422
|
||||
public record Dto(String className, Map<String, String> options, int maxThreads) implements Serializable { }
|
||||
|
||||
public Dto toDto() {
|
||||
Preconditions.checkArgument(getDecompilerClassName().isPresent(), "No decompiler classname specified for decompiler: " + getName());
|
||||
return new Dto(
|
||||
getDecompilerClassName().get(),
|
||||
getOptions().get(),
|
||||
getMaxThreads().get()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -26,13 +26,7 @@ package net.fabricmc.loom.api.decompilers;
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.file.FileCollection;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public interface LoomDecompiler {
|
||||
String name();
|
||||
|
||||
/**
|
||||
* @param sourcesDestination Decompiled sources jar
|
||||
* @param linemapDestination A byproduct of decompilation that lines up the compiled jar's line numbers with the decompiled
|
||||
@@ -41,12 +35,4 @@ public interface LoomDecompiler {
|
||||
* @param metaData Additional information that may or may not be needed while decompiling
|
||||
*/
|
||||
void decompile(Path compiledJar, Path sourcesDestination, Path linemapDestination, DecompilationMetadata metaData);
|
||||
|
||||
/**
|
||||
* Add additional classpath entries to the decompiler classpath, can return a configuration.
|
||||
*/
|
||||
@Nullable
|
||||
default FileCollection getBootstrapClasspath(Project project) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,13 +25,14 @@
|
||||
package net.fabricmc.loom.api.mappings.layered;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
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;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftProvider;
|
||||
import net.fabricmc.mappingio.tree.MemoryMappingTree;
|
||||
|
||||
@ApiStatus.Experimental /* Very Experimental and not cleanly separated from the impl atm */
|
||||
public interface MappingContext {
|
||||
@@ -39,7 +40,7 @@ public interface MappingContext {
|
||||
|
||||
Path resolveMavenDependency(String mavenNotation);
|
||||
|
||||
MappingsProvider mappingsProvider();
|
||||
Supplier<MemoryMappingTree> intermediaryTree();
|
||||
|
||||
MinecraftProvider minecraftProvider();
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ public interface LayeredMappingSpecBuilder {
|
||||
LayeredMappingSpecBuilder addLayer(MappingsSpec<?> mappingSpec);
|
||||
|
||||
/**
|
||||
* Add a layer that uses the official mappings provided by Mojang with the default options.
|
||||
* Add a layer that uses the official mappings provided by Mojang with the default decompilerOptions.
|
||||
*/
|
||||
default LayeredMappingSpecBuilder officialMojangMappings() {
|
||||
return officialMojangMappings(builder -> { });
|
||||
|
||||
@@ -43,6 +43,7 @@ import org.gradle.api.tasks.SourceSet;
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.configuration.ide.idea.IdeaUtils;
|
||||
import net.fabricmc.loom.extension.MixinExtension;
|
||||
import net.fabricmc.loom.task.service.MixinMappingsService;
|
||||
import net.fabricmc.loom.util.Constants;
|
||||
|
||||
/**
|
||||
@@ -86,7 +87,7 @@ public abstract class AnnotationProcessorInvoker<T extends Task> {
|
||||
Path mappings = loom.isForge() ? loom.getMappingsProvider().mixinTinyMappingsWithSrg : loom.getMappingsProvider().tinyMappings;
|
||||
Map<String, String> args = new HashMap<>() {{
|
||||
put(Constants.MixinArguments.IN_MAP_FILE_NAMED_INTERMEDIARY, mappings.toFile().getCanonicalPath());
|
||||
put(Constants.MixinArguments.OUT_MAP_FILE_NAMED_INTERMEDIARY, loom.getMixinMappings(sourceSet).getCanonicalPath());
|
||||
put(Constants.MixinArguments.OUT_MAP_FILE_NAMED_INTERMEDIARY, MixinMappingsService.getMixinMappingFile(project, sourceSet).getCanonicalPath());
|
||||
put(Constants.MixinArguments.OUT_REFMAP_FILE, getRefmapDestination(task, refmapName));
|
||||
put(Constants.MixinArguments.DEFAULT_OBFUSCATION_ENV, "named:intermediary");
|
||||
}};
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
|
||||
package net.fabricmc.loom.configuration;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import org.gradle.api.NamedDomainObjectProvider;
|
||||
@@ -35,7 +34,6 @@ import org.gradle.api.plugins.JavaPluginConvention;
|
||||
import org.gradle.api.plugins.JavaPluginExtension;
|
||||
import org.gradle.api.tasks.AbstractCopyTask;
|
||||
import org.gradle.api.tasks.SourceSet;
|
||||
import org.gradle.api.tasks.TaskContainer;
|
||||
import org.gradle.api.tasks.compile.JavaCompile;
|
||||
import org.gradle.api.tasks.javadoc.Javadoc;
|
||||
|
||||
@@ -43,8 +41,10 @@ import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.build.mixin.JavaApInvoker;
|
||||
import net.fabricmc.loom.build.mixin.KaptApInvoker;
|
||||
import net.fabricmc.loom.build.mixin.ScalaApInvoker;
|
||||
import net.fabricmc.loom.configuration.providers.LaunchProvider;
|
||||
import net.fabricmc.loom.configuration.providers.MinecraftProviderImpl;
|
||||
import net.fabricmc.loom.configuration.accesswidener.AccessWidenerJarProcessor;
|
||||
import net.fabricmc.loom.configuration.accesswidener.TransitiveAccessWidenerJarProcessor;
|
||||
import net.fabricmc.loom.configuration.ifaceinject.InterfaceInjectionProcessor;
|
||||
import net.fabricmc.loom.configuration.processors.JarProcessorManager;
|
||||
import net.fabricmc.loom.configuration.providers.forge.FieldMigratedMappingsProvider;
|
||||
import net.fabricmc.loom.configuration.providers.forge.ForgeProvider;
|
||||
import net.fabricmc.loom.configuration.providers.forge.ForgeUniversalProvider;
|
||||
@@ -53,9 +53,11 @@ import net.fabricmc.loom.configuration.providers.forge.McpConfigProvider;
|
||||
import net.fabricmc.loom.configuration.providers.forge.PatchProvider;
|
||||
import net.fabricmc.loom.configuration.providers.forge.SrgProvider;
|
||||
import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftJarConfiguration;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftProvider;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.mapped.IntermediaryMinecraftProvider;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.mapped.NamedMinecraftProvider;
|
||||
import net.fabricmc.loom.extension.MixinExtension;
|
||||
import net.fabricmc.loom.task.GenerateSourcesTask;
|
||||
import net.fabricmc.loom.task.UnpickJarTask;
|
||||
import net.fabricmc.loom.util.Constants;
|
||||
|
||||
public final class CompileConfiguration {
|
||||
@@ -179,6 +181,11 @@ public final class CompileConfiguration {
|
||||
|
||||
extendsFrom(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME, Constants.Configurations.LOOM_DEVELOPMENT_DEPENDENCIES, project);
|
||||
extendsFrom(JavaPlugin.TEST_RUNTIME_CLASSPATH_CONFIGURATION_NAME, Constants.Configurations.LOOM_DEVELOPMENT_DEPENDENCIES, project);
|
||||
|
||||
// Add the dev time dependencies
|
||||
project.getDependencies().add(Constants.Configurations.LOOM_DEVELOPMENT_DEPENDENCIES, Constants.Dependencies.DEV_LAUNCH_INJECTOR + Constants.Dependencies.Versions.DEV_LAUNCH_INJECTOR);
|
||||
project.getDependencies().add(Constants.Configurations.LOOM_DEVELOPMENT_DEPENDENCIES, Constants.Dependencies.TERMINAL_CONSOLE_APPENDER + Constants.Dependencies.Versions.TERMINAL_CONSOLE_APPENDER);
|
||||
project.getDependencies().add(JavaPlugin.COMPILE_ONLY_CONFIGURATION_NAME, Constants.Dependencies.JETBRAINS_ANNOTATIONS + Constants.Dependencies.Versions.JETBRAINS_ANNOTATIONS);
|
||||
}
|
||||
|
||||
public static void configureCompile(Project p) {
|
||||
@@ -191,11 +198,15 @@ public final class CompileConfiguration {
|
||||
});
|
||||
|
||||
p.afterEvaluate(project -> {
|
||||
try {
|
||||
setupMinecraft(project);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Failed to setup minecraft", e);
|
||||
}
|
||||
|
||||
LoomDependencyManager dependencyManager = new LoomDependencyManager();
|
||||
extension.setDependencyManager(dependencyManager);
|
||||
|
||||
dependencyManager.addProvider(new MinecraftProviderImpl(project));
|
||||
|
||||
if (extension.isForge()) {
|
||||
dependencyManager.addProvider(new ForgeProvider(project));
|
||||
dependencyManager.addProvider(new ForgeUserdevProvider(project));
|
||||
@@ -211,9 +222,6 @@ public final class CompileConfiguration {
|
||||
dependencyManager.addProvider(new ForgeUniversalProvider(project));
|
||||
}
|
||||
|
||||
dependencyManager.addProvider(extension.isForge() ? new FieldMigratedMappingsProvider(project) : new MappingsProviderImpl(project));
|
||||
dependencyManager.addProvider(new LaunchProvider(project));
|
||||
|
||||
dependencyManager.handleDependencies(project);
|
||||
|
||||
extension.getRemapArchives().finalizeValue();
|
||||
@@ -246,6 +254,69 @@ public final class CompileConfiguration {
|
||||
}
|
||||
}
|
||||
|
||||
// This is not thread safe across projects synchronize it here just to be sure, might be possible to move this further down, but for now this will do.
|
||||
private static synchronized void setupMinecraft(Project project) throws Exception {
|
||||
final LoomGradleExtension extension = LoomGradleExtension.get(project);
|
||||
final MinecraftJarConfiguration jarConfiguration = extension.getMinecraftJarConfiguration().get();
|
||||
|
||||
// Provide the vanilla mc jars -- TODO share across projects.
|
||||
final MinecraftProvider minecraftProvider = jarConfiguration.getMinecraftProviderFunction().apply(project);
|
||||
extension.setMinecraftProvider(minecraftProvider);
|
||||
minecraftProvider.provide();
|
||||
|
||||
final DependencyInfo mappingsDep = DependencyInfo.create(project, Constants.Configurations.MAPPINGS);
|
||||
final MappingsProviderImpl mappingsProvider = MappingsProviderImpl.getInstance(project, mappingsDep, minecraftProvider);
|
||||
extension.setMappingsProvider(mappingsProvider);
|
||||
mappingsProvider.applyToProject(project, mappingsDep);
|
||||
|
||||
// Provide the remapped mc jars
|
||||
final IntermediaryMinecraftProvider<?> intermediaryMinecraftProvider = jarConfiguration.getIntermediaryMinecraftProviderBiFunction().apply(project, minecraftProvider);
|
||||
NamedMinecraftProvider<?> namedMinecraftProvider = jarConfiguration.getNamedMinecraftProviderBiFunction().apply(project, minecraftProvider);
|
||||
|
||||
final JarProcessorManager jarProcessorManager = createJarProcessorManager(project);
|
||||
|
||||
if (jarProcessorManager.active()) {
|
||||
// Wrap the named MC provider for one that will provide the processed jars
|
||||
namedMinecraftProvider = jarConfiguration.getProcessedNamedMinecraftProviderBiFunction().apply(namedMinecraftProvider, jarProcessorManager);
|
||||
}
|
||||
|
||||
extension.setIntermediaryMinecraftProvider(intermediaryMinecraftProvider);
|
||||
intermediaryMinecraftProvider.provide(true);
|
||||
|
||||
extension.setNamedMinecraftProvider(namedMinecraftProvider);
|
||||
namedMinecraftProvider.provide(true);
|
||||
}
|
||||
|
||||
private static JarProcessorManager createJarProcessorManager(Project project) {
|
||||
final LoomGradleExtension extension = LoomGradleExtension.get(project);
|
||||
|
||||
if (extension.getAccessWidenerPath().isPresent()) {
|
||||
extension.getGameJarProcessors().add(new AccessWidenerJarProcessor(project));
|
||||
}
|
||||
|
||||
if (extension.getEnableTransitiveAccessWideners().get()) {
|
||||
TransitiveAccessWidenerJarProcessor transitiveAccessWidenerJarProcessor = new TransitiveAccessWidenerJarProcessor(project);
|
||||
|
||||
if (!transitiveAccessWidenerJarProcessor.isEmpty()) {
|
||||
extension.getGameJarProcessors().add(transitiveAccessWidenerJarProcessor);
|
||||
}
|
||||
}
|
||||
|
||||
if (extension.getEnableInterfaceInjection().get()) {
|
||||
InterfaceInjectionProcessor jarProcessor = new InterfaceInjectionProcessor(project);
|
||||
|
||||
if (!jarProcessor.isEmpty()) {
|
||||
extension.getGameJarProcessors().add(jarProcessor);
|
||||
}
|
||||
}
|
||||
|
||||
JarProcessorManager processorManager = new JarProcessorManager(extension.getGameJarProcessors().get());
|
||||
extension.setJarProcessorManager(processorManager);
|
||||
processorManager.setupProcessors();
|
||||
|
||||
return processorManager;
|
||||
}
|
||||
|
||||
private static void setupMixinAp(Project project, MixinExtension mixin) {
|
||||
mixin.init();
|
||||
|
||||
@@ -270,39 +341,10 @@ public final class CompileConfiguration {
|
||||
}
|
||||
|
||||
private static void configureDecompileTasks(Project project) {
|
||||
final TaskContainer tasks = project.getTasks();
|
||||
final LoomGradleExtension extension = LoomGradleExtension.get(project);
|
||||
|
||||
MappingsProviderImpl mappingsProvider = extension.getMappingsProvider();
|
||||
|
||||
File mappedJar = mappingsProvider.mappedProvider.getMappedJar();
|
||||
|
||||
if (mappingsProvider.hasUnpickDefinitions()) {
|
||||
File outputJar = mappingsProvider.mappedProvider.getUnpickedJar();
|
||||
|
||||
tasks.register("unpickJar", UnpickJarTask.class, unpickJarTask -> {
|
||||
unpickJarTask.getUnpickDefinitions().set(mappingsProvider.getUnpickDefinitionsFile());
|
||||
unpickJarTask.getInputJar().set(mappingsProvider.mappedProvider.getMappedJar());
|
||||
unpickJarTask.getOutputJar().set(outputJar);
|
||||
});
|
||||
|
||||
mappedJar = outputJar;
|
||||
}
|
||||
|
||||
final File inputJar = mappedJar;
|
||||
|
||||
extension.getGameDecompilers().configureEach(decompiler -> {
|
||||
String taskName = "genSourcesWith" + decompiler.name();
|
||||
|
||||
// Set the input jar for the task after evaluation has occurred.
|
||||
tasks.named(taskName, GenerateSourcesTask.class).configure(task -> {
|
||||
task.getInputJar().set(inputJar);
|
||||
|
||||
if (mappingsProvider.hasUnpickDefinitions()) {
|
||||
task.dependsOn(tasks.named("unpickJar"));
|
||||
}
|
||||
});
|
||||
});
|
||||
extension.getMinecraftJarConfiguration().get().getDecompileConfigurationBiFunction()
|
||||
.apply(project, extension.getNamedMinecraftProvider()).afterEvaluation();
|
||||
}
|
||||
|
||||
private static void extendsFrom(String a, String b, Project project) {
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* 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.configuration;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.artifacts.Configuration;
|
||||
import org.gradle.api.artifacts.Dependency;
|
||||
import org.gradle.api.artifacts.DependencySet;
|
||||
import org.gradle.api.artifacts.ResolvedDependency;
|
||||
import org.gradle.api.artifacts.SelfResolvingDependency;
|
||||
|
||||
public class DependencyInfo {
|
||||
final Project project;
|
||||
final Dependency dependency;
|
||||
final Configuration sourceConfiguration;
|
||||
|
||||
private String resolvedVersion = null;
|
||||
|
||||
public static DependencyInfo create(Project project, String configuration) {
|
||||
return create(project, project.getConfigurations().getByName(configuration));
|
||||
}
|
||||
|
||||
public static DependencyInfo create(Project project, Configuration configuration) {
|
||||
DependencySet dependencies = configuration.getDependencies();
|
||||
|
||||
if (dependencies.isEmpty()) {
|
||||
throw new IllegalArgumentException(String.format("Configuration '%s' has no dependencies", configuration.getName()));
|
||||
}
|
||||
|
||||
if (dependencies.size() != 1) {
|
||||
throw new IllegalArgumentException(String.format("Configuration '%s' must only have 1 dependency", configuration.getName()));
|
||||
}
|
||||
|
||||
return create(project, dependencies.iterator().next(), configuration);
|
||||
}
|
||||
|
||||
public static DependencyInfo create(Project project, Dependency dependency, Configuration sourceConfiguration) {
|
||||
if (dependency instanceof SelfResolvingDependency selfResolvingDependency) {
|
||||
return new FileDependencyInfo(project, selfResolvingDependency, sourceConfiguration);
|
||||
} else {
|
||||
return new DependencyInfo(project, dependency, sourceConfiguration);
|
||||
}
|
||||
}
|
||||
|
||||
DependencyInfo(Project project, Dependency dependency, Configuration sourceConfiguration) {
|
||||
this.project = project;
|
||||
this.dependency = dependency;
|
||||
this.sourceConfiguration = sourceConfiguration;
|
||||
}
|
||||
|
||||
public Dependency getDependency() {
|
||||
return dependency;
|
||||
}
|
||||
|
||||
public String getResolvedVersion() {
|
||||
if (resolvedVersion != null) {
|
||||
return resolvedVersion;
|
||||
}
|
||||
|
||||
for (ResolvedDependency rd : sourceConfiguration.getResolvedConfiguration().getFirstLevelModuleDependencies()) {
|
||||
if (rd.getModuleGroup().equals(dependency.getGroup()) && rd.getModuleName().equals(dependency.getName())) {
|
||||
resolvedVersion = rd.getModuleVersion();
|
||||
return resolvedVersion;
|
||||
}
|
||||
}
|
||||
|
||||
resolvedVersion = dependency.getVersion();
|
||||
return resolvedVersion;
|
||||
}
|
||||
|
||||
public Configuration getSourceConfiguration() {
|
||||
return sourceConfiguration;
|
||||
}
|
||||
|
||||
public Set<File> resolve() {
|
||||
if (dependency instanceof SelfResolvingDependency selfResolvingDependency) {
|
||||
return selfResolvingDependency.resolve();
|
||||
}
|
||||
|
||||
return sourceConfiguration.files(dependency);
|
||||
}
|
||||
|
||||
public Optional<File> resolveFile() {
|
||||
Set<File> files = resolve();
|
||||
|
||||
if (files.isEmpty()) {
|
||||
return Optional.empty();
|
||||
} else if (files.size() > 1) {
|
||||
StringBuilder builder = new StringBuilder(this.toString());
|
||||
builder.append(" resolves to more than one file:");
|
||||
|
||||
for (File f : files) {
|
||||
builder.append("\n\t-").append(f.getAbsolutePath());
|
||||
}
|
||||
|
||||
throw new RuntimeException(builder.toString());
|
||||
} else {
|
||||
return files.stream().findFirst();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getDepString();
|
||||
}
|
||||
|
||||
public String getDepString() {
|
||||
return dependency.getGroup() + ":" + dependency.getName() + ":" + dependency.getVersion();
|
||||
}
|
||||
|
||||
public String getResolvedDepString() {
|
||||
return dependency.getGroup() + ":" + dependency.getName() + ":" + getResolvedVersion();
|
||||
}
|
||||
}
|
||||
@@ -1,294 +0,0 @@
|
||||
/*
|
||||
* 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.configuration;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonObject;
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
import org.gradle.api.InvalidUserDataException;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.artifacts.Configuration;
|
||||
import org.gradle.api.artifacts.Dependency;
|
||||
import org.gradle.api.artifacts.ResolvedDependency;
|
||||
import org.gradle.api.artifacts.SelfResolvingDependency;
|
||||
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.LoomGradlePlugin;
|
||||
import net.fabricmc.loom.configuration.providers.MinecraftProvider;
|
||||
import net.fabricmc.loom.extension.LoomFiles;
|
||||
import net.fabricmc.loom.util.ZipUtils;
|
||||
|
||||
public abstract class DependencyProvider {
|
||||
private LoomDependencyManager dependencyManager;
|
||||
private final Project project;
|
||||
private final LoomGradleExtension extension;
|
||||
|
||||
public DependencyProvider(Project project) {
|
||||
this.project = project;
|
||||
this.extension = LoomGradleExtension.get(project);
|
||||
}
|
||||
|
||||
public abstract void provide(DependencyInfo dependency, Consumer<Runnable> postPopulationScheduler) throws Exception;
|
||||
|
||||
public abstract String getTargetConfig();
|
||||
|
||||
public Dependency addDependency(Object object, String target) {
|
||||
if (object instanceof File) {
|
||||
object = project.files(object);
|
||||
}
|
||||
|
||||
return project.getDependencies().add(target, object);
|
||||
}
|
||||
|
||||
public void register(LoomDependencyManager dependencyManager) {
|
||||
this.dependencyManager = dependencyManager;
|
||||
}
|
||||
|
||||
public LoomDependencyManager getDependencyManager() {
|
||||
return dependencyManager;
|
||||
}
|
||||
|
||||
public Project getProject() {
|
||||
return project;
|
||||
}
|
||||
|
||||
public LoomGradleExtension getExtension() {
|
||||
return extension;
|
||||
}
|
||||
|
||||
public LoomFiles getDirectories() {
|
||||
return getExtension().getFiles();
|
||||
}
|
||||
|
||||
public MinecraftProvider getMinecraftProvider() {
|
||||
return getExtension().getMinecraftProvider();
|
||||
}
|
||||
|
||||
public boolean isRefreshDeps() {
|
||||
return LoomGradlePlugin.refreshDeps;
|
||||
}
|
||||
|
||||
public static class DependencyInfo {
|
||||
final Project project;
|
||||
final Dependency dependency;
|
||||
final Configuration sourceConfiguration;
|
||||
|
||||
private String resolvedVersion = null;
|
||||
|
||||
public static DependencyInfo create(Project project, Dependency dependency, Configuration sourceConfiguration) {
|
||||
if (dependency instanceof SelfResolvingDependency selfResolvingDependency) {
|
||||
return new FileDependencyInfo(project, selfResolvingDependency, sourceConfiguration);
|
||||
} else {
|
||||
return new DependencyInfo(project, dependency, sourceConfiguration);
|
||||
}
|
||||
}
|
||||
|
||||
private DependencyInfo(Project project, Dependency dependency, Configuration sourceConfiguration) {
|
||||
this.project = project;
|
||||
this.dependency = dependency;
|
||||
this.sourceConfiguration = sourceConfiguration;
|
||||
}
|
||||
|
||||
public Dependency getDependency() {
|
||||
return dependency;
|
||||
}
|
||||
|
||||
public String getResolvedVersion() {
|
||||
if (resolvedVersion != null) {
|
||||
return resolvedVersion;
|
||||
}
|
||||
|
||||
for (ResolvedDependency rd : sourceConfiguration.getResolvedConfiguration().getFirstLevelModuleDependencies()) {
|
||||
if (rd.getModuleGroup().equals(dependency.getGroup()) && rd.getModuleName().equals(dependency.getName())) {
|
||||
resolvedVersion = rd.getModuleVersion();
|
||||
return resolvedVersion;
|
||||
}
|
||||
}
|
||||
|
||||
resolvedVersion = dependency.getVersion();
|
||||
return resolvedVersion;
|
||||
}
|
||||
|
||||
public Configuration getSourceConfiguration() {
|
||||
return sourceConfiguration;
|
||||
}
|
||||
|
||||
public Set<File> resolve() {
|
||||
if (dependency instanceof SelfResolvingDependency selfResolvingDependency) {
|
||||
return selfResolvingDependency.resolve();
|
||||
}
|
||||
|
||||
return sourceConfiguration.files(dependency);
|
||||
}
|
||||
|
||||
public Optional<File> resolveFile() {
|
||||
Set<File> files = resolve();
|
||||
|
||||
if (files.isEmpty()) {
|
||||
return Optional.empty();
|
||||
} else if (files.size() > 1) {
|
||||
StringBuilder builder = new StringBuilder(this.toString());
|
||||
builder.append(" resolves to more than one file:");
|
||||
|
||||
for (File f : files) {
|
||||
builder.append("\n\t-").append(f.getAbsolutePath());
|
||||
}
|
||||
|
||||
throw new RuntimeException(builder.toString());
|
||||
} else {
|
||||
return files.stream().findFirst();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getDepString();
|
||||
}
|
||||
|
||||
public String getDepString() {
|
||||
return dependency.getGroup() + ":" + dependency.getName() + ":" + dependency.getVersion();
|
||||
}
|
||||
|
||||
public String getResolvedDepString() {
|
||||
return dependency.getGroup() + ":" + dependency.getName() + ":" + getResolvedVersion();
|
||||
}
|
||||
}
|
||||
|
||||
public static class FileDependencyInfo extends DependencyInfo {
|
||||
protected final Map<String, File> classifierToFile = new HashMap<>();
|
||||
protected final Set<File> resolvedFiles;
|
||||
protected final String group, name, version;
|
||||
|
||||
FileDependencyInfo(Project project, SelfResolvingDependency dependency, Configuration configuration) {
|
||||
super(project, dependency, configuration);
|
||||
|
||||
Set<File> files = dependency.resolve();
|
||||
this.resolvedFiles = files;
|
||||
switch (files.size()) {
|
||||
case 0 -> //Don't think Gradle would ever let you do this
|
||||
throw new IllegalStateException("Empty dependency for " + configuration.getName());
|
||||
case 1 -> //Single file dependency
|
||||
classifierToFile.put("", Iterables.getOnlyElement(files));
|
||||
default -> { //File collection, try work out the classifiers
|
||||
List<File> sortedFiles = files.stream().sorted(Comparator.comparing(File::getName, Comparator.comparingInt(String::length))).collect(Collectors.toList());
|
||||
//First element in sortedFiles is the one with the shortest name, we presume all the others are different classifier types of this
|
||||
File shortest = sortedFiles.remove(0);
|
||||
String shortestName = FilenameUtils.removeExtension(shortest.getName()); //name.jar -> name
|
||||
|
||||
for (File file : sortedFiles) {
|
||||
if (!file.getName().startsWith(shortestName)) {
|
||||
//If there is another file which doesn't start with the same name as the presumed classifier-less one we're out of our depth
|
||||
throw new IllegalArgumentException("Unable to resolve classifiers for " + this + " (failed to sort " + files + ')');
|
||||
}
|
||||
}
|
||||
|
||||
//We appear to be right, therefore this is the normal dependency file we want
|
||||
classifierToFile.put("", shortest);
|
||||
int start = shortestName.length();
|
||||
|
||||
for (File file : sortedFiles) {
|
||||
//Now we just have to work out what classifier type the other files are, this shouldn't even return an empty string
|
||||
String classifier = FilenameUtils.removeExtension(file.getName()).substring(start);
|
||||
|
||||
//The classifier could well be separated with a dash (thing name.jar and name-sources.jar), we don't want that leading dash
|
||||
if (classifierToFile.put(classifier.charAt(0) == '-' ? classifier.substring(1) : classifier, file) != null) {
|
||||
throw new InvalidUserDataException("Duplicate classifiers for " + this + " (\"" + file.getName().substring(start) + "\" in " + files + ')');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dependency.getGroup() != null && dependency.getVersion() != null) {
|
||||
group = dependency.getGroup();
|
||||
name = dependency.getName();
|
||||
version = dependency.getVersion();
|
||||
} else {
|
||||
group = "net.fabricmc.synthetic";
|
||||
File root = classifierToFile.get(""); //We've built the classifierToFile map, now to try find a name and version for our dependency
|
||||
byte[] modJson;
|
||||
|
||||
try {
|
||||
if ("jar".equals(FilenameUtils.getExtension(root.getName())) && (modJson = ZipUtils.unpackNullable(root.toPath(), "fabric.mod.json")) != null) {
|
||||
//It's a Fabric mod, see how much we can extract out
|
||||
JsonObject json = new Gson().fromJson(new String(modJson, StandardCharsets.UTF_8), JsonObject.class);
|
||||
|
||||
if (json == null || !json.has("id") || !json.has("version")) {
|
||||
throw new IllegalArgumentException("Invalid Fabric mod jar: " + root + " (malformed json: " + json + ')');
|
||||
}
|
||||
|
||||
if (json.has("name")) { //Go for the name field if it's got one
|
||||
name = json.get("name").getAsString();
|
||||
} else {
|
||||
name = json.get("id").getAsString();
|
||||
}
|
||||
|
||||
version = json.get("version").getAsString();
|
||||
} else {
|
||||
//Not a Fabric mod, just have to make something up
|
||||
name = FilenameUtils.removeExtension(root.getName());
|
||||
version = "1.0";
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException("Failed to read input file: " + root, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getResolvedVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDepString() {
|
||||
//Use our custom name and version with the dummy group rather than the null:unspecified:null it would otherwise return
|
||||
return group + ':' + name + ':' + version;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getResolvedDepString() {
|
||||
return getDepString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<File> resolve() {
|
||||
return this.resolvedFiles;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* 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.configuration;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonObject;
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
import org.gradle.api.InvalidUserDataException;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.artifacts.Configuration;
|
||||
import org.gradle.api.artifacts.SelfResolvingDependency;
|
||||
|
||||
import net.fabricmc.loom.util.ZipUtils;
|
||||
|
||||
public class FileDependencyInfo extends DependencyInfo {
|
||||
protected final Map<String, File> classifierToFile = new HashMap<>();
|
||||
protected final Set<File> resolvedFiles;
|
||||
protected final String group, name, version;
|
||||
|
||||
FileDependencyInfo(Project project, SelfResolvingDependency dependency, Configuration configuration) {
|
||||
super(project, dependency, configuration);
|
||||
|
||||
Set<File> files = dependency.resolve();
|
||||
this.resolvedFiles = files;
|
||||
switch (files.size()) {
|
||||
case 0 -> //Don't think Gradle would ever let you do this
|
||||
throw new IllegalStateException("Empty dependency?");
|
||||
case 1 -> //Single file dependency
|
||||
classifierToFile.put("", Iterables.getOnlyElement(files));
|
||||
default -> { //File collection, try work out the classifiers
|
||||
List<File> sortedFiles = files.stream().sorted(Comparator.comparing(File::getName, Comparator.comparingInt(String::length))).collect(Collectors.toList());
|
||||
//First element in sortedFiles is the one with the shortest name, we presume all the others are different classifier types of this
|
||||
File shortest = sortedFiles.remove(0);
|
||||
String shortestName = FilenameUtils.removeExtension(shortest.getName()); //name.jar -> name
|
||||
|
||||
for (File file : sortedFiles) {
|
||||
if (!file.getName().startsWith(shortestName)) {
|
||||
//If there is another file which doesn't start with the same name as the presumed classifier-less one we're out of our depth
|
||||
throw new IllegalArgumentException("Unable to resolve classifiers for " + this + " (failed to sort " + files + ')');
|
||||
}
|
||||
}
|
||||
|
||||
//We appear to be right, therefore this is the normal dependency file we want
|
||||
classifierToFile.put("", shortest);
|
||||
int start = shortestName.length();
|
||||
|
||||
for (File file : sortedFiles) {
|
||||
//Now we just have to work out what classifier type the other files are, this shouldn't even return an empty string
|
||||
String classifier = FilenameUtils.removeExtension(file.getName()).substring(start);
|
||||
|
||||
//The classifier could well be separated with a dash (thing name.jar and name-sources.jar), we don't want that leading dash
|
||||
if (classifierToFile.put(classifier.charAt(0) == '-' ? classifier.substring(1) : classifier, file) != null) {
|
||||
throw new InvalidUserDataException("Duplicate classifiers for " + this + " (\"" + file.getName().substring(start) + "\" in " + files + ')');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dependency.getGroup() != null && dependency.getVersion() != null) {
|
||||
group = dependency.getGroup();
|
||||
name = dependency.getName();
|
||||
version = dependency.getVersion();
|
||||
} else {
|
||||
group = "net.fabricmc.synthetic";
|
||||
File root = classifierToFile.get(""); //We've built the classifierToFile map, now to try find a name and version for our dependency
|
||||
byte[] modJson;
|
||||
|
||||
try {
|
||||
if ("jar".equals(FilenameUtils.getExtension(root.getName())) && (modJson = ZipUtils.unpackNullable(root.toPath(), "fabric.mod.json")) != null) {
|
||||
//It's a Fabric mod, see how much we can extract out
|
||||
JsonObject json = new Gson().fromJson(new String(modJson, StandardCharsets.UTF_8), JsonObject.class);
|
||||
|
||||
if (json == null || !json.has("id") || !json.has("version")) {
|
||||
throw new IllegalArgumentException("Invalid Fabric mod jar: " + root + " (malformed json: " + json + ')');
|
||||
}
|
||||
|
||||
if (json.has("name")) { //Go for the name field if it's got one
|
||||
name = json.get("name").getAsString();
|
||||
} else {
|
||||
name = json.get("id").getAsString();
|
||||
}
|
||||
|
||||
version = json.get("version").getAsString();
|
||||
} else {
|
||||
//Not a Fabric mod, just have to make something up
|
||||
name = FilenameUtils.removeExtension(root.getName());
|
||||
version = "1.0";
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException("Failed to read input file: " + root, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getResolvedVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDepString() {
|
||||
//Use our custom name and version with the dummy group rather than the null:unspecified:null it would otherwise return
|
||||
return group + ':' + name + ':' + version;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getResolvedDepString() {
|
||||
return getDepString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<File> resolve() {
|
||||
return this.resolvedFiles;
|
||||
}
|
||||
}
|
||||
@@ -29,15 +29,12 @@ import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.artifacts.Configuration;
|
||||
import org.gradle.api.artifacts.Dependency;
|
||||
import org.gradle.api.artifacts.DependencySet;
|
||||
import org.gradle.api.artifacts.ExternalModuleDependency;
|
||||
import org.gradle.api.artifacts.repositories.MavenArtifactRepository;
|
||||
|
||||
@@ -45,106 +42,17 @@ import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.LoomGradlePlugin;
|
||||
import net.fabricmc.loom.LoomRepositoryPlugin;
|
||||
import net.fabricmc.loom.build.ModCompileRemapper;
|
||||
import net.fabricmc.loom.configuration.DependencyProvider.DependencyInfo;
|
||||
import net.fabricmc.loom.configuration.ide.idea.IdeaUtils;
|
||||
import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl;
|
||||
import net.fabricmc.loom.util.Constants;
|
||||
import net.fabricmc.loom.util.SourceRemapper;
|
||||
import net.fabricmc.loom.util.ZipUtils;
|
||||
|
||||
public class LoomDependencyManager {
|
||||
private static class ProviderList {
|
||||
private final String key;
|
||||
private final List<DependencyProvider> providers = new ArrayList<>();
|
||||
|
||||
ProviderList(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
}
|
||||
|
||||
private final List<DependencyProvider> dependencyProviderList = new ArrayList<>();
|
||||
|
||||
public <T extends DependencyProvider> T addProvider(T provider) {
|
||||
if (dependencyProviderList.contains(provider)) {
|
||||
throw new RuntimeException("Provider is already registered");
|
||||
}
|
||||
|
||||
if (getProvider(provider.getClass()) != null) {
|
||||
throw new RuntimeException("Provider of this type is already registered");
|
||||
}
|
||||
|
||||
provider.register(this);
|
||||
dependencyProviderList.add(provider);
|
||||
return provider;
|
||||
}
|
||||
|
||||
public <T> T getProvider(Class<? extends T> clazz) {
|
||||
for (DependencyProvider provider : dependencyProviderList) {
|
||||
if (provider.getClass() == clazz) {
|
||||
return (T) provider;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void handleDependencies(Project project) {
|
||||
List<Runnable> afterTasks = new ArrayList<>();
|
||||
|
||||
MappingsProviderImpl mappingsProvider = null;
|
||||
|
||||
project.getLogger().info(":setting up loom dependencies");
|
||||
LoomGradleExtension extension = LoomGradleExtension.get(project);
|
||||
Map<String, ProviderList> providerListMap = new HashMap<>();
|
||||
List<ProviderList> targetProviders = new ArrayList<>();
|
||||
|
||||
for (DependencyProvider provider : dependencyProviderList) {
|
||||
providerListMap.computeIfAbsent(provider.getTargetConfig(), (k) -> {
|
||||
ProviderList list = new ProviderList(k);
|
||||
targetProviders.add(list);
|
||||
return list;
|
||||
}).providers.add(provider);
|
||||
|
||||
if (provider instanceof MappingsProviderImpl) {
|
||||
mappingsProvider = (MappingsProviderImpl) provider;
|
||||
}
|
||||
}
|
||||
|
||||
if (mappingsProvider == null) {
|
||||
throw new RuntimeException("Could not find MappingsProvider instance!");
|
||||
}
|
||||
|
||||
for (ProviderList list : targetProviders) {
|
||||
Configuration configuration = project.getConfigurations().getByName(list.key);
|
||||
DependencySet dependencies = configuration.getDependencies();
|
||||
|
||||
if (dependencies.isEmpty()) {
|
||||
throw new IllegalArgumentException(String.format("No '%s' dependency was specified!", list.key));
|
||||
}
|
||||
|
||||
if (dependencies.size() > 1) {
|
||||
throw new IllegalArgumentException(String.format("Only one '%s' dependency should be specified, but %d were!",
|
||||
list.key,
|
||||
dependencies.size())
|
||||
);
|
||||
}
|
||||
|
||||
for (Dependency dependency : dependencies) {
|
||||
for (DependencyProvider provider : list.providers) {
|
||||
DependencyProvider.DependencyInfo info = DependencyInfo.create(project, dependency, configuration);
|
||||
|
||||
try {
|
||||
provider.provide(info, afterTasks::add);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Failed to provide " + dependency.getGroup() + ":" + dependency.getName() + ":" + dependency.getVersion() + " : " + e.toString() + "\n\tEnsure minecraft is not open and try running with --refresh-dependencies. Use --stacktrace to see the full stacktrace.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SourceRemapper sourceRemapper = new SourceRemapper(project, true);
|
||||
String platformSuffix = extension.isForge() ? "_forge" : "";
|
||||
String mappingsIdentifier = mappingsProvider.mappingsIdentifier() + platformSuffix;
|
||||
|
||||
if (extension.getInstallerData() == null && !extension.isForge()) {
|
||||
//If we've not found the installer JSON we've probably skipped remapping Fabric loader, let's go looking
|
||||
@@ -168,15 +76,18 @@ public class LoomDependencyManager {
|
||||
}
|
||||
}
|
||||
|
||||
if (extension.getInstallerData() == null) {
|
||||
project.getLogger().warn("fabric-installer.json not found in classpath!");
|
||||
}
|
||||
}
|
||||
SourceRemapper sourceRemapper = new SourceRemapper(project, true);
|
||||
String platformSuffix = extension.isForge() ? "_forge" : "";
|
||||
String mappingsIdentifier = extension.getMappingsProvider().mappingsIdentifier() + platformSuffix;
|
||||
|
||||
ModCompileRemapper.remapDependencies(project, mappingsIdentifier, extension, sourceRemapper);
|
||||
|
||||
sourceRemapper.remapAll();
|
||||
|
||||
if (extension.getInstallerData() == null) {
|
||||
project.getLogger().warn("fabric-installer.json not found in classpath!");
|
||||
}
|
||||
|
||||
for (Runnable runnable : afterTasks) {
|
||||
runnable.run();
|
||||
}
|
||||
|
||||
@@ -30,7 +30,6 @@ import java.io.UncheckedIOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.NoSuchFileException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
|
||||
import com.google.common.hash.Hashing;
|
||||
import org.gradle.api.Project;
|
||||
@@ -39,6 +38,7 @@ import net.fabricmc.accesswidener.AccessWidener;
|
||||
import net.fabricmc.accesswidener.AccessWidenerReader;
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.configuration.processors.JarProcessor;
|
||||
import net.fabricmc.loom.util.Checksum;
|
||||
import net.fabricmc.loom.util.ZipUtils;
|
||||
|
||||
public class AccessWidenerJarProcessor implements JarProcessor {
|
||||
@@ -57,7 +57,7 @@ public class AccessWidenerJarProcessor implements JarProcessor {
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return "loom:access_widener";
|
||||
return "loom:access_widener:" + Checksum.toHex(inputHash);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -91,21 +91,4 @@ public class AccessWidenerJarProcessor implements JarProcessor {
|
||||
throw new UncheckedIOException("Failed to write aw jar hash", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInvalid(File file) {
|
||||
byte[] hash;
|
||||
|
||||
try {
|
||||
hash = ZipUtils.unpackNullable(file.toPath(), HASH_FILENAME);
|
||||
} catch (IOException e) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (hash == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return !Arrays.equals(inputHash, hash); // TODO how do we know if the current jar as the correct access applied? save the hash of the input?
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,7 +174,10 @@ public class TransitiveAccessWidenerJarProcessor implements JarProcessor {
|
||||
TinyRemapper tinyRemapper = TinyRemapperHelper.getTinyRemapper(project, "intermediary", "named");
|
||||
|
||||
tinyRemapper.readClassPath(TinyRemapperHelper.getMinecraftDependencies(project));
|
||||
tinyRemapper.readClassPath(extension.getMinecraftMappedProvider().getIntermediaryJar().toPath());
|
||||
|
||||
for (Path minecraftJar : extension.getMinecraftJars(MappingsNamespace.INTERMEDIARY)) {
|
||||
tinyRemapper.readClassPath(minecraftJar);
|
||||
}
|
||||
|
||||
return tinyRemapper;
|
||||
} catch (IOException e) {
|
||||
@@ -182,12 +185,6 @@ public class TransitiveAccessWidenerJarProcessor implements JarProcessor {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInvalid(File file) {
|
||||
// The hash is handled by getId()
|
||||
return false;
|
||||
}
|
||||
|
||||
private static class TransitiveDetectorVisitor implements AccessWidenerVisitor {
|
||||
private boolean transitive = false;
|
||||
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2022 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.decompile;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.tasks.TaskProvider;
|
||||
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.mapped.MappedMinecraftProvider;
|
||||
import net.fabricmc.loom.task.UnpickJarTask;
|
||||
|
||||
public abstract class DecompileConfiguration<T extends MappedMinecraftProvider> {
|
||||
protected final Project project;
|
||||
protected final T minecraftProvider;
|
||||
protected final LoomGradleExtension extension;
|
||||
protected final MappingsProviderImpl mappingsProvider;
|
||||
|
||||
public DecompileConfiguration(Project project, T minecraftProvider) {
|
||||
this.project = project;
|
||||
this.minecraftProvider = minecraftProvider;
|
||||
this.extension = LoomGradleExtension.get(project);
|
||||
this.mappingsProvider = extension.getMappingsProvider();
|
||||
}
|
||||
|
||||
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(mappingsProvider.getUnpickDefinitionsFile());
|
||||
unpickJarTask.getInputJar().set(inputJar);
|
||||
unpickJarTask.getOutputJar().set(outputJar);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2022 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.decompile;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
|
||||
import org.gradle.api.Project;
|
||||
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.mapped.MappedMinecraftProvider;
|
||||
import net.fabricmc.loom.task.GenerateSourcesTask;
|
||||
import net.fabricmc.loom.util.Constants;
|
||||
|
||||
public class SingleJarDecompileConfiguration extends DecompileConfiguration<MappedMinecraftProvider> {
|
||||
public SingleJarDecompileConfiguration(Project project, MappedMinecraftProvider minecraftProvider) {
|
||||
super(project, minecraftProvider);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void afterEvaluation() {
|
||||
List<Path> minecraftJars = minecraftProvider.getMinecraftJars();
|
||||
assert minecraftJars.size() == 1;
|
||||
|
||||
final File namedJar = minecraftJars.get(0).toFile();
|
||||
|
||||
File mappedJar = namedJar;
|
||||
|
||||
if (mappingsProvider.hasUnpickDefinitions()) {
|
||||
File outputJar = new File(extension.getMappingsProvider().mappingsWorkingDir().toFile(), "minecraft-unpicked.jar");
|
||||
createUnpickJarTask("unpickJar", namedJar, outputJar);
|
||||
|
||||
mappedJar = outputJar;
|
||||
}
|
||||
|
||||
final File inputJar = mappedJar;
|
||||
|
||||
LoomGradleExtension.get(project).getDecompilerOptions().forEach(options -> {
|
||||
final String decompilerName = options.getName().substring(0, 1).toUpperCase() + options.getName().substring(1);
|
||||
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.dependsOn(project.getTasks().named("validateAccessWidener"));
|
||||
task.setDescription("Decompile minecraft using %s.".formatted(decompilerName));
|
||||
task.setGroup(Constants.TaskGroup.FABRIC);
|
||||
|
||||
if (mappingsProvider.hasUnpickDefinitions()) {
|
||||
task.dependsOn(project.getTasks().named("unpickJar"));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
project.getTasks().register("genSources", task -> {
|
||||
task.setDescription("Decompile minecraft using the default decompiler.");
|
||||
task.setGroup(Constants.TaskGroup.FABRIC);
|
||||
|
||||
task.dependsOn(project.getTasks().named("genSourcesWithCfr"));
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* 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.decompile;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.gradle.api.Action;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.Task;
|
||||
import org.gradle.api.tasks.TaskProvider;
|
||||
|
||||
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> {
|
||||
public SplitDecompileConfiguration(Project project, MappedMinecraftProvider.Split minecraftProvider) {
|
||||
super(project, minecraftProvider);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterEvaluation() {
|
||||
File commonJarToDecompile = minecraftProvider.getCommonJar().toFile();
|
||||
File clientOnlyJarToDecompile = minecraftProvider.getClientOnlyJar().toFile();
|
||||
|
||||
TaskProvider<UnpickJarTask> unpickCommonJar = null;
|
||||
TaskProvider<UnpickJarTask> unpickClientOnlyJar = null;
|
||||
|
||||
if (mappingsProvider.hasUnpickDefinitions()) {
|
||||
commonJarToDecompile = new File(extension.getMappingsProvider().mappingsWorkingDir().toFile(), "minecraft-common-unpicked.jar");
|
||||
clientOnlyJarToDecompile = new File(extension.getMappingsProvider().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 TaskProvider<Task> commonDecompileTask = createDecompileTasks("Common", task -> {
|
||||
task.getInputJar().set(commonJar);
|
||||
task.getRuntimeJar().set(minecraftProvider.getCommonJar().toFile());
|
||||
|
||||
if (unpickCommonJarTask != null) {
|
||||
task.dependsOn(unpickCommonJarTask);
|
||||
}
|
||||
});
|
||||
|
||||
final TaskProvider<Task> clientOnlyDecompileTask = createDecompileTasks("ClientOnly", task -> {
|
||||
task.getInputJar().set(clientOnlyJar);
|
||||
task.getRuntimeJar().set(minecraftProvider.getClientOnlyJar().toFile());
|
||||
|
||||
if (unpickCommonJarTask != null) {
|
||||
task.dependsOn(unpickClientOnlyJarTask);
|
||||
}
|
||||
|
||||
// Don't allow them to run at the same time.
|
||||
task.mustRunAfter(commonDecompileTask);
|
||||
});
|
||||
|
||||
project.getTasks().register("genSources", task -> {
|
||||
task.setDescription("Decompile minecraft using the default decompiler.");
|
||||
task.setGroup(Constants.TaskGroup.FABRIC);
|
||||
|
||||
task.dependsOn(commonDecompileTask);
|
||||
task.dependsOn(clientOnlyDecompileTask);
|
||||
});
|
||||
}
|
||||
|
||||
private TaskProvider<Task> createDecompileTasks(String name, Action<GenerateSourcesTask> configureAction) {
|
||||
extension.getDecompilerOptions().forEach(options -> {
|
||||
final String decompilerName = options.getName().substring(0, 1).toUpperCase() + options.getName().substring(1);
|
||||
final String taskName = "gen%sSourcesWith%s".formatted(name, decompilerName);
|
||||
|
||||
project.getTasks().register(taskName, GenerateSourcesTask.class, options).configure(task -> {
|
||||
configureAction.execute(task);
|
||||
task.dependsOn(project.getTasks().named("validateAccessWidener"));
|
||||
task.setDescription("Decompile minecraft using %s.".formatted(decompilerName));
|
||||
task.setGroup(Constants.TaskGroup.FABRIC);
|
||||
});
|
||||
});
|
||||
|
||||
return project.getTasks().register("gen%sSources".formatted(name), task -> {
|
||||
task.setDescription("Decompile minecraft (%s) using the default decompiler.".formatted(name));
|
||||
task.setGroup(Constants.TaskGroup.FABRIC);
|
||||
|
||||
task.dependsOn(project.getTasks().named("gen%sSourcesWithCfr".formatted(name)));
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -30,10 +30,12 @@ import org.gradle.api.Project;
|
||||
import org.gradle.api.tasks.TaskProvider;
|
||||
import org.gradle.execution.taskgraph.TaskExecutionGraphInternal;
|
||||
|
||||
import net.fabricmc.loom.task.LoomTasks;
|
||||
|
||||
public class IdeaConfiguration {
|
||||
public static void setup(Project project) {
|
||||
TaskProvider<IdeaSyncTask> ideaSyncTask = project.getTasks().register("ideaSyncTask", IdeaSyncTask.class, ideaSyncTask1 -> {
|
||||
ideaSyncTask1.dependsOn(project.getTasks().named("downloadAssets"));
|
||||
TaskProvider<IdeaSyncTask> ideaSyncTask = project.getTasks().register("ideaSyncTask", IdeaSyncTask.class, task -> {
|
||||
task.dependsOn(LoomTasks.getIDELaunchConfigureTaskName(project));
|
||||
});
|
||||
|
||||
if (!IdeaUtils.isIdeaSync()) {
|
||||
|
||||
@@ -29,7 +29,6 @@ import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
@@ -38,6 +37,7 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.hash.Hasher;
|
||||
import com.google.common.hash.Hashing;
|
||||
import com.google.gson.Gson;
|
||||
@@ -52,8 +52,10 @@ import org.objectweb.asm.ClassWriter;
|
||||
import org.objectweb.asm.commons.Remapper;
|
||||
|
||||
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.Checksum;
|
||||
import net.fabricmc.loom.util.Constants;
|
||||
import net.fabricmc.loom.util.Pair;
|
||||
import net.fabricmc.loom.util.TinyRemapperHelper;
|
||||
@@ -82,6 +84,12 @@ public class InterfaceInjectionProcessor implements JarProcessor {
|
||||
return injectedInterfaces.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
Preconditions.checkArgument(!isEmpty());
|
||||
return "loom:interface_injection:" + Checksum.toHex(inputHash);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setup() {
|
||||
}
|
||||
@@ -147,23 +155,6 @@ public class InterfaceInjectionProcessor implements JarProcessor {
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInvalid(File file) {
|
||||
byte[] hash;
|
||||
|
||||
try {
|
||||
hash = ZipUtils.unpackNullable(file.toPath(), HASH_FILENAME);
|
||||
} catch (IOException e) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (hash == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return !Arrays.equals(inputHash, hash);
|
||||
}
|
||||
|
||||
private List<InjectedInterface> getInjectedInterfaces() {
|
||||
List<InjectedInterface> result = new ArrayList<>();
|
||||
|
||||
@@ -272,7 +263,10 @@ public class InterfaceInjectionProcessor implements JarProcessor {
|
||||
try {
|
||||
TinyRemapper tinyRemapper = TinyRemapperHelper.getTinyRemapper(project, "intermediary", "named");
|
||||
tinyRemapper.readClassPath(TinyRemapperHelper.getMinecraftDependencies(project));
|
||||
tinyRemapper.readClassPath(extension.getMinecraftMappedProvider().getIntermediaryJar().toPath());
|
||||
|
||||
for (Path minecraftJar : extension.getMinecraftJars(MappingsNamespace.INTERMEDIARY)) {
|
||||
tinyRemapper.readClassPath(minecraftJar);
|
||||
}
|
||||
|
||||
return tinyRemapper;
|
||||
} catch (IOException e) {
|
||||
|
||||
@@ -58,7 +58,7 @@ 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.kotlin.remapping.KotlinMetadataTinyRemapperExtension;
|
||||
import net.fabricmc.loom.util.Constants;
|
||||
import net.fabricmc.loom.util.FileSystemUtil;
|
||||
import net.fabricmc.loom.util.LoggerFilter;
|
||||
@@ -149,12 +149,11 @@ public class ModProcessor {
|
||||
|
||||
private void remapJars(List<ModDependencyInfo> remapList) throws IOException {
|
||||
final LoomGradleExtension extension = LoomGradleExtension.get(project);
|
||||
final MinecraftMappedProvider mappedProvider = extension.getMinecraftMappedProvider();
|
||||
final MappingsProviderImpl mappingsProvider = extension.getMappingsProvider();
|
||||
final boolean useKotlinExtension = project.getPluginManager().hasPlugin("org.jetbrains.kotlin.jvm");
|
||||
String fromM = extension.isForge() ? MappingsNamespace.SRG.toString() : MappingsNamespace.INTERMEDIARY.toString();
|
||||
String toM = MappingsNamespace.NAMED.toString();
|
||||
|
||||
Path intermediaryJar = extension.isForge() ? mappedProvider.getSrgJar().toPath() : mappedProvider.getIntermediaryJar().toPath();
|
||||
Path[] mcDeps = project.getConfigurations().getByName(Constants.Configurations.LOADER_DEPENDENCIES).getFiles()
|
||||
.stream().map(File::toPath).toArray(Path[]::new);
|
||||
|
||||
@@ -163,12 +162,21 @@ public class ModProcessor {
|
||||
|
||||
MemoryMappingTree mappings = (fromM.equals("srg") || toM.equals("srg")) && extension.isForge() ? mappingsProvider.getMappingsWithSrg() : mappingsProvider.getMappings();
|
||||
LoggerFilter.replaceSystemOut();
|
||||
final TinyRemapper remapper = TinyRemapper.newRemapper()
|
||||
TinyRemapper.Builder builder = TinyRemapper.newRemapper()
|
||||
.logger(project.getLogger()::lifecycle)
|
||||
.logUnknownInvokeDynamic(false)
|
||||
.withMappings(TinyRemapperHelper.create(mappings, fromM, toM, false))
|
||||
.renameInvalidLocals(false)
|
||||
.build();
|
||||
.renameInvalidLocals(false);
|
||||
|
||||
if (useKotlinExtension) {
|
||||
builder.extension(KotlinMetadataTinyRemapperExtension.INSTANCE);
|
||||
}
|
||||
|
||||
final TinyRemapper remapper = builder.build();
|
||||
|
||||
for (Path minecraftJar : extension.getMinecraftJars(MappingsNamespace.INTERMEDIARY)) {
|
||||
remapper.readClassPathAsync(minecraftJar);
|
||||
}
|
||||
|
||||
remapper.readClassPathAsync(intermediaryJar);
|
||||
|
||||
|
||||
@@ -33,11 +33,9 @@ public interface JarProcessor {
|
||||
* <p>If the jar processor implementation class supports creating multiple jar processors with different effects,
|
||||
* the needed configuration should also be included in this ID. Example: {@code path.to.MyJarProcessor#someOption}.
|
||||
*
|
||||
* @return the ID of this jar processor
|
||||
* @return the unique ID of this jar processor
|
||||
*/
|
||||
default String getId() {
|
||||
return getClass().getName();
|
||||
}
|
||||
String getId();
|
||||
|
||||
void setup();
|
||||
|
||||
@@ -45,9 +43,4 @@ public interface JarProcessor {
|
||||
* Currently this is a destructive process that replaces the existing jar.
|
||||
*/
|
||||
void process(File file);
|
||||
|
||||
/**
|
||||
* Return true to make all jar processors run again, return false to use the existing results of jar processing.
|
||||
*/
|
||||
boolean isInvalid(File file);
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ public class JarProcessorManager {
|
||||
throw new UncheckedIOException("Could not check jar manifest of " + file, e);
|
||||
}
|
||||
|
||||
return jarProcessors.stream().anyMatch(jarProcessor -> jarProcessor.isInvalid(file));
|
||||
return false;
|
||||
}
|
||||
|
||||
private String getJarProcessorHash() {
|
||||
|
||||
@@ -1,98 +0,0 @@
|
||||
/*
|
||||
* 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.processors;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.gradle.api.Project;
|
||||
|
||||
import net.fabricmc.loom.configuration.providers.MinecraftProviderImpl;
|
||||
import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftMappedProvider;
|
||||
import net.fabricmc.loom.util.Constants;
|
||||
|
||||
public class MinecraftProcessedProvider extends MinecraftMappedProvider {
|
||||
public final String projectMappedClassifier;
|
||||
|
||||
private File projectMappedJar;
|
||||
|
||||
private final JarProcessorManager jarProcessorManager;
|
||||
|
||||
public MinecraftProcessedProvider(Project project, JarProcessorManager jarProcessorManager) {
|
||||
super(project);
|
||||
this.jarProcessorManager = jarProcessorManager;
|
||||
this.projectMappedClassifier = "project-" + project.getPath().replace(':', '@')
|
||||
+ "-mapped";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addDependencies(DependencyInfo dependency, Consumer<Runnable> postPopulationScheduler) {
|
||||
boolean isForgeAtDirty = getExtension().isForge() && getExtension().getMappingsProvider().patchedProvider.isAtDirty();
|
||||
|
||||
if (jarProcessorManager.isInvalid(projectMappedJar) || isRefreshDeps() || isForgeAtDirty) {
|
||||
getProject().getLogger().info(":processing mapped jar");
|
||||
invalidateJar();
|
||||
|
||||
try {
|
||||
FileUtils.copyFile(super.getMappedJar(), projectMappedJar);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Failed to copy source jar", e);
|
||||
}
|
||||
|
||||
jarProcessorManager.process(projectMappedJar);
|
||||
}
|
||||
|
||||
getProject().getDependencies().add(Constants.Configurations.MINECRAFT_NAMED,
|
||||
getProject().getDependencies().module("net.minecraft:" + minecraftProvider.getJarPrefix() + "minecraft-" + projectMappedClassifier + ":" + getMinecraftProvider().minecraftVersion() + "/" + getExtension().getMappingsProvider().mappingsIdentifier()));
|
||||
}
|
||||
|
||||
private void invalidateJar() {
|
||||
if (projectMappedJar.exists()) {
|
||||
getProject().getLogger().warn("Invalidating project jar");
|
||||
|
||||
try {
|
||||
FileUtils.forceDelete(projectMappedJar);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Failed to invalidate jar, try stopping gradle daemon or closing the game", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initFiles(MinecraftProviderImpl minecraftProvider, MappingsProviderImpl mappingsProvider) {
|
||||
super.initFiles(minecraftProvider, mappingsProvider);
|
||||
|
||||
projectMappedJar = new File(getDirectories().getRootProjectPersistentCache(), getMinecraftProvider().minecraftVersion() + "/"
|
||||
+ getExtension().getMappingsProvider().mappingsIdentifier() + "/" + minecraftProvider.getJarPrefix() + "minecraft-" + projectMappedClassifier + ".jar");
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getMappedJar() {
|
||||
return projectMappedJar;
|
||||
}
|
||||
}
|
||||
@@ -1,238 +0,0 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2019-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;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.StringJoiner;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.logging.configuration.ConsoleOutput;
|
||||
import org.gradle.api.plugins.JavaPlugin;
|
||||
|
||||
import net.fabricmc.loom.configuration.DependencyProvider;
|
||||
import net.fabricmc.loom.configuration.RemappedConfigurationEntry;
|
||||
import net.fabricmc.loom.configuration.launch.LaunchProviderSettings;
|
||||
import net.fabricmc.loom.util.Constants;
|
||||
import net.fabricmc.loom.util.PropertyUtil;
|
||||
|
||||
public class LaunchProvider extends DependencyProvider {
|
||||
public LaunchProvider(Project project) {
|
||||
super(project);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void provide(DependencyInfo dependency, Consumer<Runnable> postPopulationScheduler) throws IOException {
|
||||
final String nativesPath = getExtension().getFiles().getNativesDirectory(getProject()).getAbsolutePath();
|
||||
|
||||
final LaunchConfig launchConfig = new LaunchConfig()
|
||||
.property("fabric.development", "true")
|
||||
.property("fabric.remapClasspathFile", getRemapClasspathFile().getAbsolutePath())
|
||||
.property("log4j.configurationFile", getAllLog4JConfigFiles())
|
||||
.property("log4j2.formatMsgNoLookups", "true")
|
||||
|
||||
.property("client", "java.library.path", nativesPath)
|
||||
.property("client", "org.lwjgl.librarypath", nativesPath);
|
||||
|
||||
if (!getExtension().isForge()) {
|
||||
launchConfig
|
||||
.argument("client", "--assetIndex")
|
||||
.argument("client", getExtension().getMinecraftProvider().getVersionInfo().assetIndex().fabricId(getExtension().getMinecraftProvider().minecraftVersion()))
|
||||
.argument("client", "--assetsDir")
|
||||
.argument("client", new File(getDirectories().getUserCache(), "assets").getAbsolutePath());
|
||||
}
|
||||
|
||||
if (getExtension().isForge()) {
|
||||
launchConfig
|
||||
// Should match YarnNamingService.PATH_TO_MAPPINGS in forge-runtime
|
||||
.property("fabric.yarnWithSrg.path", getExtension().getMappingsProvider().tinyMappingsWithSrg.toAbsolutePath().toString())
|
||||
|
||||
.argument("data", "--all")
|
||||
.argument("data", "--mod")
|
||||
.argument("data", String.join(",", getExtension().getForge().getDataGenMods()))
|
||||
.argument("data", "--output")
|
||||
.argument("data", getProject().file("src/generated/resources").getAbsolutePath())
|
||||
|
||||
.property("mixin.env.remapRefMap", "true");
|
||||
|
||||
if (PropertyUtil.getAndFinalize(getExtension().getForge().getUseCustomMixin())) {
|
||||
launchConfig.property("mixin.forgeloom.inject.mappings.srg-named", getExtension().getMappingsProvider().mixinTinyMappingsWithSrg.toAbsolutePath().toString());
|
||||
} else {
|
||||
launchConfig.property("net.minecraftforge.gradle.GradleStart.srg.srg-mcp", getExtension().getMappingsProvider().srgToNamedSrg.toAbsolutePath().toString());
|
||||
}
|
||||
|
||||
Set<String> mixinConfigs = PropertyUtil.getAndFinalize(getExtension().getForge().getMixinConfigs());
|
||||
|
||||
if (!mixinConfigs.isEmpty()) {
|
||||
for (String config : mixinConfigs) {
|
||||
launchConfig.argument("-mixin.config");
|
||||
launchConfig.argument(config);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
addDependency(Constants.Dependencies.DEV_LAUNCH_INJECTOR + Constants.Dependencies.Versions.DEV_LAUNCH_INJECTOR, Constants.Configurations.LOOM_DEVELOPMENT_DEPENDENCIES);
|
||||
addDependency(Constants.Dependencies.TERMINAL_CONSOLE_APPENDER + Constants.Dependencies.Versions.TERMINAL_CONSOLE_APPENDER, Constants.Configurations.LOOM_DEVELOPMENT_DEPENDENCIES);
|
||||
addDependency(Constants.Dependencies.JETBRAINS_ANNOTATIONS + Constants.Dependencies.Versions.JETBRAINS_ANNOTATIONS, JavaPlugin.COMPILE_ONLY_CONFIGURATION_NAME);
|
||||
|
||||
if (getExtension().isForge()) {
|
||||
addDependency(Constants.Dependencies.FORGE_RUNTIME + Constants.Dependencies.Versions.FORGE_RUNTIME, Constants.Configurations.FORGE_EXTRA);
|
||||
addDependency(Constants.Dependencies.JAVAX_ANNOTATIONS + Constants.Dependencies.Versions.JAVAX_ANNOTATIONS, JavaPlugin.COMPILE_ONLY_CONFIGURATION_NAME);
|
||||
}
|
||||
|
||||
for (LaunchProviderSettings settings : getExtension().getLaunchConfigs()) {
|
||||
settings.evaluateNow();
|
||||
|
||||
for (String argument : settings.getArguments()) {
|
||||
launchConfig.argument(settings.getName(), argument);
|
||||
}
|
||||
|
||||
for (Map.Entry<String, String> property : settings.getProperties()) {
|
||||
launchConfig.property(settings.getName(), property.getKey(), property.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
final boolean plainConsole = getProject().getGradle().getStartParameter().getConsoleOutput() == ConsoleOutput.Plain;
|
||||
final boolean ansiSupportedIDE = new File(getProject().getRootDir(), ".vscode").exists()
|
||||
|| new File(getProject().getRootDir(), ".idea").exists()
|
||||
|| (Arrays.stream(getProject().getRootDir().listFiles()).anyMatch(file -> file.getName().endsWith(".iws")));
|
||||
|
||||
//Enable ansi by default for idea and vscode when gradle is not ran with plain console.
|
||||
if (ansiSupportedIDE && !plainConsole) {
|
||||
launchConfig.property("fabric.log.disableAnsi", "false");
|
||||
}
|
||||
|
||||
writeLog4jConfig();
|
||||
FileUtils.writeStringToFile(getDirectories().getDevLauncherConfig(), launchConfig.asString(), StandardCharsets.UTF_8);
|
||||
|
||||
postPopulationScheduler.accept(this::writeRemapClassPath);
|
||||
}
|
||||
|
||||
private File getLog4jConfigFile() {
|
||||
return getDirectories().getDefaultLog4jConfigFile();
|
||||
}
|
||||
|
||||
private String getAllLog4JConfigFiles() {
|
||||
return getExtension().getLog4jConfigs().getFiles().stream()
|
||||
.map(File::getAbsolutePath)
|
||||
.collect(Collectors.joining(","));
|
||||
}
|
||||
|
||||
private File getRemapClasspathFile() {
|
||||
return new File(getDirectories().getDevLauncherConfig().getParentFile(), "remapClasspath.txt");
|
||||
}
|
||||
|
||||
private void writeLog4jConfig() {
|
||||
try (InputStream is = LaunchProvider.class.getClassLoader().getResourceAsStream("log4j2.fabric.xml")) {
|
||||
Files.deleteIfExists(getLog4jConfigFile().toPath());
|
||||
Files.copy(is, getLog4jConfigFile().toPath());
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Failed to generate log4j config", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeRemapClassPath() {
|
||||
List<String> inputConfigurations = new ArrayList<>();
|
||||
inputConfigurations.add(Constants.Configurations.LOADER_DEPENDENCIES);
|
||||
inputConfigurations.addAll(Constants.MOD_COMPILE_ENTRIES.stream().map(RemappedConfigurationEntry::sourceConfiguration).collect(Collectors.toList()));
|
||||
|
||||
List<File> remapClasspath = new ArrayList<>();
|
||||
|
||||
for (String inputConfiguration : inputConfigurations) {
|
||||
remapClasspath.addAll(getProject().getConfigurations().getByName(inputConfiguration).getFiles());
|
||||
}
|
||||
|
||||
remapClasspath.add(getExtension().getMinecraftMappedProvider().getIntermediaryJar());
|
||||
|
||||
if (getExtension().isForgeAndNotOfficial()) {
|
||||
remapClasspath.add(getExtension().getMinecraftMappedProvider().getForgeIntermediaryJar());
|
||||
}
|
||||
|
||||
String str = remapClasspath.stream()
|
||||
.map(File::getAbsolutePath)
|
||||
.collect(Collectors.joining(File.pathSeparator));
|
||||
|
||||
try {
|
||||
Files.writeString(getRemapClasspathFile().toPath(), str);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Failed to generate remap classpath", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTargetConfig() {
|
||||
return Constants.Configurations.MINECRAFT_NAMED;
|
||||
}
|
||||
|
||||
public static class LaunchConfig {
|
||||
private final Map<String, List<String>> values = new HashMap<>();
|
||||
|
||||
public LaunchConfig property(String key, String value) {
|
||||
return property("common", key, value);
|
||||
}
|
||||
|
||||
public LaunchConfig property(String side, String key, String value) {
|
||||
values.computeIfAbsent(side + "Properties", (s -> new ArrayList<>()))
|
||||
.add(String.format("%s=%s", key, value));
|
||||
return this;
|
||||
}
|
||||
|
||||
public LaunchConfig argument(String value) {
|
||||
return argument("common", value);
|
||||
}
|
||||
|
||||
public LaunchConfig argument(String side, String value) {
|
||||
values.computeIfAbsent(side + "Args", (s -> new ArrayList<>()))
|
||||
.add(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public String asString() {
|
||||
StringJoiner stringJoiner = new StringJoiner("\n");
|
||||
|
||||
for (Map.Entry<String, List<String>> entry : values.entrySet()) {
|
||||
stringJoiner.add(entry.getKey());
|
||||
|
||||
for (String s : entry.getValue()) {
|
||||
stringJoiner.add("\t" + s);
|
||||
}
|
||||
}
|
||||
|
||||
return stringJoiner.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,7 @@ package net.fabricmc.loom.configuration.providers.mappings;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Path;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.artifacts.Configuration;
|
||||
@@ -35,7 +36,8 @@ 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;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftProvider;
|
||||
import net.fabricmc.mappingio.tree.MemoryMappingTree;
|
||||
|
||||
public class GradleMappingContext implements MappingContext {
|
||||
private final Project project;
|
||||
@@ -62,8 +64,8 @@ public class GradleMappingContext implements MappingContext {
|
||||
}
|
||||
|
||||
@Override
|
||||
public MappingsProvider mappingsProvider() {
|
||||
return extension.getMappingsProvider();
|
||||
public Supplier<MemoryMappingTree> intermediaryTree() {
|
||||
return () -> IntermediaryService.getInstance(project, minecraftProvider()).getMemoryMappingTree();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2022 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.File;
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collections;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import com.google.common.base.Suppliers;
|
||||
import com.google.common.net.UrlEscapers;
|
||||
import org.gradle.api.Project;
|
||||
import org.jetbrains.annotations.VisibleForTesting;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.LoomGradlePlugin;
|
||||
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftProvider;
|
||||
import net.fabricmc.loom.util.DownloadUtil;
|
||||
import net.fabricmc.loom.util.service.SharedService;
|
||||
import net.fabricmc.loom.util.service.SharedServiceManager;
|
||||
import net.fabricmc.mappingio.adapter.MappingNsCompleter;
|
||||
import net.fabricmc.mappingio.format.Tiny2Reader;
|
||||
import net.fabricmc.mappingio.tree.MemoryMappingTree;
|
||||
|
||||
public final class IntermediaryService implements SharedService {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(IntermediaryService.class);
|
||||
|
||||
private final Path intermediaryTiny;
|
||||
private final Supplier<MemoryMappingTree> memoryMappingTree = Suppliers.memoize(this::createMemoryMappingTree);
|
||||
|
||||
private IntermediaryService(Path intermediaryTiny) {
|
||||
this.intermediaryTiny = intermediaryTiny;
|
||||
}
|
||||
|
||||
public static synchronized IntermediaryService getInstance(Project project, MinecraftProvider minecraftProvider) {
|
||||
final LoomGradleExtension extension = LoomGradleExtension.get(project);
|
||||
final String encodedMinecraftVersion = UrlEscapers.urlFragmentEscaper().escape(minecraftProvider.minecraftVersion());
|
||||
final String intermediaryArtifactUrl = extension.getIntermediaryUrl(encodedMinecraftVersion);
|
||||
|
||||
return SharedServiceManager.get(project).getOrCreateService("IntermediaryService:" + intermediaryArtifactUrl,
|
||||
() -> create(intermediaryArtifactUrl, minecraftProvider));
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public static IntermediaryService create(String intermediaryUrl, MinecraftProvider minecraftProvider) {
|
||||
final Path intermediaryTiny = minecraftProvider.file("intermediary-v2.tiny").toPath();
|
||||
|
||||
if (!Files.exists(intermediaryTiny) || LoomGradlePlugin.refreshDeps) {
|
||||
// Download and extract intermediary
|
||||
File intermediaryJar = minecraftProvider.file("intermediary-v2.jar");
|
||||
|
||||
try {
|
||||
DownloadUtil.downloadIfChanged(new URL(intermediaryUrl), intermediaryJar, LOGGER);
|
||||
MappingsProviderImpl.extractMappings(intermediaryJar.toPath(), intermediaryTiny);
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException("Failed to download and extract intermediary", e);
|
||||
}
|
||||
}
|
||||
|
||||
return new IntermediaryService(intermediaryTiny);
|
||||
}
|
||||
|
||||
private MemoryMappingTree createMemoryMappingTree() {
|
||||
final MemoryMappingTree tree = new MemoryMappingTree();
|
||||
|
||||
try {
|
||||
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);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException("Failed to read intermediary mappings", e);
|
||||
}
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
||||
public MemoryMappingTree getMemoryMappingTree() {
|
||||
return memoryMappingTree.get();
|
||||
}
|
||||
|
||||
public Path getIntermediaryTiny() {
|
||||
return Objects.requireNonNull(intermediaryTiny, "Intermediary mappings have not been setup");
|
||||
}
|
||||
}
|
||||
@@ -29,146 +29,134 @@ import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.FileSystem;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.NoSuchFileException;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import com.google.common.base.Stopwatch;
|
||||
import com.google.common.net.UrlEscapers;
|
||||
import com.google.common.base.Suppliers;
|
||||
import com.google.gson.JsonObject;
|
||||
import org.apache.tools.ant.util.StringUtils;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.artifacts.Configuration;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
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.ifaceinject.InterfaceInjectionProcessor;
|
||||
import net.fabricmc.loom.configuration.processors.JarProcessorManager;
|
||||
import net.fabricmc.loom.configuration.processors.MinecraftProcessedProvider;
|
||||
import net.fabricmc.loom.configuration.providers.MinecraftProviderImpl;
|
||||
import net.fabricmc.loom.configuration.providers.forge.MinecraftPatchedProvider;
|
||||
import net.fabricmc.loom.configuration.providers.forge.SrgProvider;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftMappedProvider;
|
||||
import net.fabricmc.loom.configuration.DependencyInfo;
|
||||
import net.fabricmc.loom.configuration.providers.mappings.tiny.MappingsMerger;
|
||||
import net.fabricmc.loom.configuration.providers.mappings.tiny.TinyJarInfo;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MergedMinecraftProvider;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftProvider;
|
||||
import net.fabricmc.loom.util.Constants;
|
||||
import net.fabricmc.loom.util.DeletingFileVisitor;
|
||||
import net.fabricmc.loom.util.DownloadUtil;
|
||||
import net.fabricmc.loom.util.ZipUtils;
|
||||
import net.fabricmc.loom.util.srg.MCPReader;
|
||||
import net.fabricmc.loom.util.srg.SrgMerger;
|
||||
import net.fabricmc.loom.util.srg.SrgNamedWriter;
|
||||
import net.fabricmc.loom.util.service.SharedService;
|
||||
import net.fabricmc.loom.util.service.SharedServiceManager;
|
||||
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.MappingTree;
|
||||
import net.fabricmc.mappingio.tree.MemoryMappingTree;
|
||||
import net.fabricmc.stitch.Command;
|
||||
import net.fabricmc.stitch.commands.CommandProposeFieldNames;
|
||||
import net.fabricmc.stitch.commands.tinyv2.TinyFile;
|
||||
import net.fabricmc.stitch.commands.tinyv2.TinyV2Writer;
|
||||
|
||||
public class MappingsProviderImpl extends DependencyProvider implements MappingsProvider {
|
||||
public MinecraftMappedProvider mappedProvider;
|
||||
public MinecraftPatchedProvider patchedProvider;
|
||||
public class MappingsProviderImpl implements MappingsProvider, SharedService {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(MappingsProviderImpl.class);
|
||||
|
||||
public String mappingsIdentifier;
|
||||
private Supplier<MemoryMappingTree> mappingTree;
|
||||
public final String mappingsIdentifier;
|
||||
|
||||
private Path mappingsWorkingDir;
|
||||
private Path intermediaryTiny;
|
||||
private boolean hasRefreshed = false;
|
||||
private final Path mappingsWorkingDir;
|
||||
// The mappings that gradle gives us
|
||||
private Path baseTinyMappings;
|
||||
private final Path baseTinyMappings;
|
||||
// The mappings we use in practice
|
||||
public Path tinyMappings;
|
||||
public Path tinyMappingsJar;
|
||||
public Path tinyMappingsWithSrg;
|
||||
public Path mixinTinyMappingsWithSrg; // FORGE: The mixin mappings have srg names in intermediary.
|
||||
public Path srgToNamedSrg; // FORGE: srg to named in srg file format
|
||||
private Path unpickDefinitions;
|
||||
public final Path tinyMappings;
|
||||
public final Path tinyMappingsJar;
|
||||
private final Path unpickDefinitions;
|
||||
|
||||
private boolean hasUnpickDefinitions;
|
||||
private UnpickMetadata unpickMetadata;
|
||||
private MemoryMappingTree mappingTree;
|
||||
private MemoryMappingTree mappingTreeWithSrg;
|
||||
private Map<String, String> signatureFixes;
|
||||
|
||||
public MappingsProviderImpl(Project project) {
|
||||
super(project);
|
||||
private final Supplier<IntermediaryService> intermediaryService;
|
||||
|
||||
private MappingsProviderImpl(String mappingsIdentifier, Path mappingsWorkingDir, Supplier<IntermediaryService> intermediaryService) {
|
||||
this.mappingsIdentifier = mappingsIdentifier;
|
||||
|
||||
this.mappingsWorkingDir = mappingsWorkingDir;
|
||||
this.baseTinyMappings = mappingsWorkingDir.resolve("mappings-base.tiny");
|
||||
this.tinyMappings = mappingsWorkingDir.resolve("mappings.tiny");
|
||||
this.tinyMappingsJar = mappingsWorkingDir.resolve("mappings.jar");
|
||||
this.unpickDefinitions = mappingsWorkingDir.resolve("mappings.unpick");
|
||||
|
||||
this.intermediaryService = intermediaryService;
|
||||
}
|
||||
|
||||
public static synchronized MappingsProviderImpl getInstance(Project project, DependencyInfo dependency, MinecraftProvider minecraftProvider) {
|
||||
return SharedServiceManager.get(project).getOrCreateService("MappingsProvider:%s:%s".formatted(dependency.getDepString(), minecraftProvider.minecraftVersion()), () -> {
|
||||
Supplier<IntermediaryService> intermediaryService = Suppliers.memoize(() -> IntermediaryService.getInstance(project, minecraftProvider));
|
||||
return create(dependency, minecraftProvider, intermediaryService);
|
||||
});
|
||||
}
|
||||
|
||||
public MemoryMappingTree getMappings() throws IOException {
|
||||
return Objects.requireNonNull(mappingTree, "Cannot get mappings before they have been read");
|
||||
return Objects.requireNonNull(mappingTree, "Cannot get mappings before they have been read").get();
|
||||
}
|
||||
|
||||
public MemoryMappingTree getMappingsWithSrg() throws IOException {
|
||||
return Objects.requireNonNull(mappingTreeWithSrg, "Cannot get mappings before they have been read");
|
||||
private static MappingsProviderImpl create(DependencyInfo dependency, MinecraftProvider minecraftProvider, Supplier<IntermediaryService> intermediaryService) {
|
||||
final String version = dependency.getResolvedVersion();
|
||||
final Path inputJar = dependency.resolveFile().orElseThrow(() -> new RuntimeException("Could not resolve mappings: " + dependency)).toPath();
|
||||
final String mappingsName = StringUtils.removeSuffix(dependency.getDependency().getGroup() + "." + dependency.getDependency().getName(), "-unmerged");
|
||||
|
||||
final TinyJarInfo jarInfo = TinyJarInfo.get(inputJar);
|
||||
jarInfo.minecraftVersionId().ifPresent(id -> {
|
||||
if (!minecraftProvider.minecraftVersion().equals(id)) {
|
||||
LOGGER.warn("The mappings (%s) were not build for minecraft version (%s) produce with caution.".formatted(dependency.getDepString(), minecraftProvider.minecraftVersion()));
|
||||
}
|
||||
});
|
||||
|
||||
final String mappingsIdentifier = createMappingsIdentifier(mappingsName, version, getMappingsClassifier(dependency, jarInfo.v2()), minecraftProvider.minecraftVersion());
|
||||
final Path workingDir = minecraftProvider.dir(mappingsIdentifier).toPath();
|
||||
|
||||
var mappingProvider = new MappingsProviderImpl(mappingsIdentifier, workingDir, intermediaryService);
|
||||
|
||||
try {
|
||||
mappingProvider.setup(minecraftProvider, inputJar);
|
||||
} catch (IOException e) {
|
||||
cleanWorkingDirectory(workingDir);
|
||||
throw new UncheckedIOException("Failed to setup mappings: " + dependency.getDepString(), e);
|
||||
}
|
||||
|
||||
return mappingProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void provide(DependencyInfo dependency, Consumer<Runnable> postPopulationScheduler) throws Exception {
|
||||
MinecraftProviderImpl minecraftProvider = getDependencyManager().getProvider(MinecraftProviderImpl.class);
|
||||
|
||||
getProject().getLogger().info(":setting up mappings (" + dependency.getDependency().getName() + " " + dependency.getResolvedVersion() + ")");
|
||||
|
||||
String version = dependency.getResolvedVersion();
|
||||
File mappingsJar = dependency.resolveFile().orElseThrow(() -> new RuntimeException("Could not find yarn mappings: " + dependency));
|
||||
|
||||
String mappingsName = StringUtils.removeSuffix(dependency.getDependency().getGroup() + "." + dependency.getDependency().getName(), "-unmerged");
|
||||
boolean isV2 = isV2(dependency, mappingsJar);
|
||||
this.mappingsIdentifier = createMappingsIdentifier(mappingsName, version, getMappingsClassifier(dependency, isV2));
|
||||
|
||||
initFiles();
|
||||
private void setup(MinecraftProvider minecraftProvider, Path inputJar) throws IOException {
|
||||
if (isRefreshDeps()) {
|
||||
cleanWorkingDirectory(mappingsWorkingDir);
|
||||
}
|
||||
|
||||
if (Files.notExists(tinyMappings) || isRefreshDeps()) {
|
||||
storeMappings(getProject(), minecraftProvider, mappingsJar.toPath(), postPopulationScheduler);
|
||||
storeMappings(minecraftProvider, inputJar);
|
||||
} else {
|
||||
try (FileSystem fileSystem = FileSystems.newFileSystem(mappingsJar.toPath(), (ClassLoader) null)) {
|
||||
try (FileSystem fileSystem = FileSystems.newFileSystem(inputJar, (ClassLoader) null)) {
|
||||
extractExtras(fileSystem);
|
||||
}
|
||||
}
|
||||
|
||||
if (getExtension().isForge()) {
|
||||
patchedProvider = new MinecraftPatchedProvider(getProject());
|
||||
patchedProvider.provide(dependency, postPopulationScheduler);
|
||||
}
|
||||
|
||||
mappingTree = readMappings(tinyMappings);
|
||||
manipulateMappings(mappingsJar.toPath());
|
||||
|
||||
if (getExtension().shouldGenerateSrgTiny()) {
|
||||
if (Files.notExists(tinyMappingsWithSrg) || isRefreshDeps()) {
|
||||
// Merge tiny mappings with srg
|
||||
SrgMerger.mergeSrg(getProject().getLogger(), getExtension().getMappingsProvider()::getMojmapSrgFileIfPossible, getRawSrgFile(), tinyMappings, tinyMappingsWithSrg, true);
|
||||
}
|
||||
|
||||
mappingTreeWithSrg = readMappings(tinyMappingsWithSrg);
|
||||
}
|
||||
|
||||
if (Files.notExists(tinyMappingsJar) || isRefreshDeps()) {
|
||||
Files.deleteIfExists(tinyMappingsJar);
|
||||
ZipUtils.add(tinyMappingsJar, "mappings/mappings.tiny", Files.readAllBytes(tinyMappings));
|
||||
}
|
||||
|
||||
mappingTree = Suppliers.memoize(this::readMappings);
|
||||
}
|
||||
|
||||
public void applyToProject(Project project, DependencyInfo dependency) {
|
||||
if (hasUnpickDefinitions()) {
|
||||
String notation = String.format("%s:%s:%s:constants",
|
||||
dependency.getDependency().getGroup(),
|
||||
@@ -176,95 +164,14 @@ public class MappingsProviderImpl extends DependencyProvider implements Mappings
|
||||
dependency.getDependency().getVersion()
|
||||
);
|
||||
|
||||
getProject().getDependencies().add(Constants.Configurations.MAPPING_CONSTANTS, notation);
|
||||
populateUnpickClasspath();
|
||||
project.getDependencies().add(Constants.Configurations.MAPPING_CONSTANTS, notation);
|
||||
populateUnpickClasspath(project);
|
||||
}
|
||||
|
||||
if (getExtension().isForge()) {
|
||||
if (!getExtension().shouldGenerateSrgTiny()) {
|
||||
throw new IllegalStateException("We have to generate srg tiny in a forge environment!");
|
||||
}
|
||||
|
||||
if (Files.notExists(mixinTinyMappingsWithSrg) || isRefreshDeps()) {
|
||||
List<String> lines = new ArrayList<>(Files.readAllLines(tinyMappingsWithSrg));
|
||||
lines.set(0, lines.get(0).replace("intermediary", "yraidemretni").replace("srg", "intermediary"));
|
||||
Files.deleteIfExists(mixinTinyMappingsWithSrg);
|
||||
Files.write(mixinTinyMappingsWithSrg, lines);
|
||||
}
|
||||
|
||||
if (Files.notExists(srgToNamedSrg) || isRefreshDeps()) {
|
||||
SrgNamedWriter.writeTo(getProject().getLogger(), srgToNamedSrg, getMappingsWithSrg(), "srg", "named");
|
||||
}
|
||||
}
|
||||
|
||||
addDependency(getProject().getDependencies().module("loom.resolved:mappings:" + getMinecraftProvider().minecraftVersion() + "/" + getExtension().getMappingsProvider().mappingsIdentifier()), Constants.Configurations.MAPPINGS_FINAL);
|
||||
|
||||
LoomGradleExtension extension = getExtension();
|
||||
|
||||
if (extension.getAccessWidenerPath().isPresent()) {
|
||||
extension.getGameJarProcessors().add(new AccessWidenerJarProcessor(getProject()));
|
||||
}
|
||||
|
||||
if (extension.getEnableTransitiveAccessWideners().get()) {
|
||||
TransitiveAccessWidenerJarProcessor transitiveAccessWidenerJarProcessor = new TransitiveAccessWidenerJarProcessor(getProject());
|
||||
|
||||
if (!transitiveAccessWidenerJarProcessor.isEmpty()) {
|
||||
extension.getGameJarProcessors().add(transitiveAccessWidenerJarProcessor);
|
||||
}
|
||||
}
|
||||
|
||||
if (extension.getEnableInterfaceInjection().get()) {
|
||||
InterfaceInjectionProcessor jarProcessor = new InterfaceInjectionProcessor(getProject());
|
||||
|
||||
if (!jarProcessor.isEmpty()) {
|
||||
extension.getGameJarProcessors().add(jarProcessor);
|
||||
}
|
||||
}
|
||||
|
||||
extension.getAccessWidenerPath().finalizeValue();
|
||||
extension.getGameJarProcessors().finalizeValue();
|
||||
JarProcessorManager processorManager = new JarProcessorManager(extension.getGameJarProcessors().get());
|
||||
extension.setJarProcessorManager(processorManager);
|
||||
processorManager.setupProcessors();
|
||||
|
||||
if (extension.isForge()) {
|
||||
patchedProvider.finishProvide();
|
||||
}
|
||||
|
||||
if (processorManager.active() || (extension.isForge() && patchedProvider.usesProjectCache())) {
|
||||
mappedProvider = new MinecraftProcessedProvider(getProject(), processorManager);
|
||||
getProject().getLogger().info("Using project based jar storage");
|
||||
} else {
|
||||
mappedProvider = new MinecraftMappedProvider(getProject());
|
||||
}
|
||||
|
||||
mappedProvider.initFiles(minecraftProvider, this);
|
||||
mappedProvider.provide(dependency, postPopulationScheduler);
|
||||
project.getDependencies().add(Constants.Configurations.MAPPINGS_FINAL, project.files(tinyMappingsJar.toFile()));
|
||||
}
|
||||
|
||||
protected Path getRawSrgFile() throws IOException {
|
||||
LoomGradleExtension extension = getExtension();
|
||||
|
||||
if (extension.getSrgProvider().isTsrgV2()) {
|
||||
return extension.getSrgProvider().getMergedMojangTrimmed();
|
||||
}
|
||||
|
||||
return extension.getSrgProvider().getSrg();
|
||||
}
|
||||
|
||||
public Path getMojmapSrgFileIfPossible() {
|
||||
try {
|
||||
LoomGradleExtension extension = getExtension();
|
||||
return SrgProvider.getMojmapTsrg2(getProject(), extension);
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void manipulateMappings(Path mappingsJar) throws IOException {
|
||||
}
|
||||
|
||||
private String getMappingsClassifier(DependencyInfo dependency, boolean isV2) {
|
||||
private static String getMappingsClassifier(DependencyInfo dependency, boolean isV2) {
|
||||
String[] depStringSplit = dependency.getDepString().split(":");
|
||||
|
||||
if (depStringSplit.length >= 4) {
|
||||
@@ -274,122 +181,46 @@ public class MappingsProviderImpl extends DependencyProvider implements Mappings
|
||||
return isV2 ? "-v2" : "";
|
||||
}
|
||||
|
||||
private boolean isV2(DependencyInfo dependency, File mappingsJar) throws IOException {
|
||||
String minecraftVersion = getMinecraftProvider().minecraftVersion();
|
||||
private void storeMappings(MinecraftProvider minecraftProvider, Path inputJar) throws IOException {
|
||||
LOGGER.info(":extracting " + inputJar.getFileName());
|
||||
|
||||
// Only do this for official yarn, there isn't really a way we can get the mc version for all mappings
|
||||
if (dependency.getDependency().getGroup() != null && dependency.getDependency().getGroup().equals("net.fabricmc") && dependency.getDependency().getName().equals("yarn") && dependency.getDependency().getVersion() != null) {
|
||||
String yarnVersion = dependency.getDependency().getVersion();
|
||||
char separator = yarnVersion.contains("+build.") ? '+' : yarnVersion.contains("-") ? '-' : '.';
|
||||
String yarnMinecraftVersion = yarnVersion.substring(0, yarnVersion.lastIndexOf(separator));
|
||||
|
||||
if (!yarnMinecraftVersion.equalsIgnoreCase(minecraftVersion)) {
|
||||
getProject().getLogger().warn("Minecraft Version ({}) does not match yarn's minecraft version ({})", minecraftVersion, yarnMinecraftVersion);
|
||||
}
|
||||
|
||||
// We can save reading the zip file + header by checking the file name
|
||||
return mappingsJar.getName().endsWith("-v2.jar") || mappingsJar.getName().endsWith("-mergedv2.jar");
|
||||
} else {
|
||||
return doesJarContainV2Mappings(mappingsJar.toPath());
|
||||
}
|
||||
}
|
||||
|
||||
private void storeMappings(Project project, MinecraftProviderImpl minecraftProvider, Path yarnJar, Consumer<Runnable> postPopulationScheduler)
|
||||
throws IOException {
|
||||
project.getLogger().info(":extracting " + yarnJar.getFileName());
|
||||
|
||||
if (isMCP(yarnJar)) {
|
||||
try {
|
||||
readAndMergeMCP(yarnJar, postPopulationScheduler);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
try (FileSystem fileSystem = FileSystems.newFileSystem(yarnJar, (ClassLoader) null)) {
|
||||
try (FileSystem fileSystem = FileSystems.newFileSystem(inputJar, (ClassLoader) null)) {
|
||||
extractMappings(fileSystem, baseTinyMappings);
|
||||
extractExtras(fileSystem);
|
||||
}
|
||||
|
||||
if (areMappingsMergedV2(baseTinyMappings)) {
|
||||
// Architectury Loom Patch
|
||||
// If a merged tiny v2 mappings file is provided
|
||||
// Skip merging, should save a lot of time
|
||||
Files.copy(baseTinyMappings, tinyMappings, StandardCopyOption.REPLACE_EXISTING);
|
||||
} else if (areMappingsV2(baseTinyMappings)) {
|
||||
if (areMappingsV2(baseTinyMappings)) {
|
||||
// These are unmerged v2 mappings
|
||||
mergeAndSaveMappings(project, baseTinyMappings, tinyMappings);
|
||||
MappingsMerger.mergeAndSaveMappings(baseTinyMappings, tinyMappings, intermediaryService.get());
|
||||
} else {
|
||||
// These are merged v1 mappings
|
||||
Files.deleteIfExists(tinyMappings);
|
||||
project.getLogger().lifecycle(":populating field names");
|
||||
suggestFieldNames(minecraftProvider, baseTinyMappings, tinyMappings);
|
||||
}
|
||||
}
|
||||
|
||||
private static MemoryMappingTree readMappings(Path file) throws IOException {
|
||||
MemoryMappingTree mappingTree = new MemoryMappingTree();
|
||||
MappingReader.read(file, mappingTree);
|
||||
return mappingTree;
|
||||
}
|
||||
|
||||
private void readAndMergeMCP(Path mcpJar, Consumer<Runnable> postPopulationScheduler) throws Exception {
|
||||
Path intermediaryTinyPath = getIntermediaryTiny();
|
||||
SrgProvider provider = getExtension().getSrgProvider();
|
||||
|
||||
if (provider == null) {
|
||||
if (!getExtension().shouldGenerateSrgTiny()) {
|
||||
Configuration srg = getProject().getConfigurations().maybeCreate(Constants.Configurations.SRG);
|
||||
srg.setTransitive(false);
|
||||
if (minecraftProvider instanceof MergedMinecraftProvider mergedMinecraftProvider) {
|
||||
// These are merged v1 mappings
|
||||
Files.deleteIfExists(tinyMappings);
|
||||
LOGGER.info(":populating field names");
|
||||
suggestFieldNames(mergedMinecraftProvider, baseTinyMappings, tinyMappings);
|
||||
} else {
|
||||
throw new UnsupportedOperationException("V1 mappings only support merged minecraft");
|
||||
}
|
||||
|
||||
provider = new SrgProvider(getProject());
|
||||
getProject().getDependencies().add(provider.getTargetConfig(), "de.oceanlabs.mcp:mcp_config:" + getMinecraftProvider().minecraftVersion());
|
||||
Configuration configuration = getProject().getConfigurations().getByName(provider.getTargetConfig());
|
||||
provider.provide(DependencyInfo.create(getProject(), configuration.getDependencies().iterator().next(), configuration), postPopulationScheduler);
|
||||
}
|
||||
|
||||
Path srgPath = getRawSrgFile();
|
||||
TinyFile file = new MCPReader(intermediaryTinyPath, srgPath).read(mcpJar);
|
||||
TinyV2Writer.write(file, tinyMappings);
|
||||
}
|
||||
|
||||
private boolean isMCP(Path path) throws IOException {
|
||||
try (FileSystem fs = FileSystems.newFileSystem(path, (ClassLoader) null)) {
|
||||
return Files.exists(fs.getPath("fields.csv")) && Files.exists(fs.getPath("methods.csv"));
|
||||
private MemoryMappingTree readMappings() {
|
||||
try {
|
||||
MemoryMappingTree mappingTree = new MemoryMappingTree();
|
||||
MappingReader.read(tinyMappings, mappingTree);
|
||||
return mappingTree;
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException("Failed to read mappings", e);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean areMappingsV2(Path path) throws IOException {
|
||||
try (BufferedReader reader = Files.newBufferedReader(path)) {
|
||||
return MappingReader.detectFormat(reader) == MappingFormat.TINY_2;
|
||||
} catch (NoSuchFileException e) {
|
||||
// TODO: just check the mappings version when Parser supports V1 in readMetadata()
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean areMappingsMergedV2(Path path) throws IOException {
|
||||
try (BufferedReader reader = Files.newBufferedReader(path)) {
|
||||
return MappingReader.detectFormat(reader) == MappingFormat.TINY_2 && MappingReader.getNamespaces(reader).containsAll(Arrays.asList("named", "intermediary", "official"));
|
||||
} catch (NoSuchFileException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
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"))) {
|
||||
return MappingReader.detectFormat(reader) == MappingFormat.TINY_2;
|
||||
}
|
||||
} catch (NoSuchFileException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static void extractMappings(Path jar, Path extractTo) throws IOException {
|
||||
public static void extractMappings(Path jar, Path extractTo) throws IOException {
|
||||
try (FileSystem unmergedIntermediaryFs = FileSystems.newFileSystem(jar, (ClassLoader) null)) {
|
||||
extractMappings(unmergedIntermediaryFs, extractTo);
|
||||
}
|
||||
@@ -444,9 +275,9 @@ public class MappingsProviderImpl extends DependencyProvider implements Mappings
|
||||
);
|
||||
}
|
||||
|
||||
private void populateUnpickClasspath() {
|
||||
private void populateUnpickClasspath(Project project) {
|
||||
String unpickCliName = "unpick-cli";
|
||||
getProject().getDependencies().add(Constants.Configurations.UNPICK_CLASSPATH,
|
||||
project.getDependencies().add(Constants.Configurations.UNPICK_CLASSPATH,
|
||||
String.format("%s:%s:%s", unpickMetadata.unpickGroup, unpickCliName, unpickMetadata.unpickVersion)
|
||||
);
|
||||
|
||||
@@ -459,83 +290,17 @@ public class MappingsProviderImpl extends DependencyProvider implements Mappings
|
||||
};
|
||||
|
||||
for (String asm : asmDeps) {
|
||||
getProject().getDependencies().add(Constants.Configurations.UNPICK_CLASSPATH,
|
||||
project.getDependencies().add(Constants.Configurations.UNPICK_CLASSPATH,
|
||||
asm.formatted(Opcodes.class.getPackage().getImplementationVersion())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private void mergeAndSaveMappings(Project project, Path from, Path out) throws IOException {
|
||||
Stopwatch stopwatch = Stopwatch.createStarted();
|
||||
project.getLogger().info(":merging mappings");
|
||||
|
||||
MemoryMappingTree tree = new MemoryMappingTree();
|
||||
MappingSourceNsSwitch sourceNsSwitch = new MappingSourceNsSwitch(tree, MappingsNamespace.OFFICIAL.toString());
|
||||
readIntermediaryTree().accept(sourceNsSwitch);
|
||||
|
||||
try (BufferedReader reader = Files.newBufferedReader(from, StandardCharsets.UTF_8)) {
|
||||
Tiny2Reader.read(reader, tree);
|
||||
}
|
||||
|
||||
inheritMappedNamesOfEnclosingClasses(tree);
|
||||
|
||||
try (Tiny2Writer writer = new Tiny2Writer(Files.newBufferedWriter(out, StandardCharsets.UTF_8), false)) {
|
||||
tree.accept(writer);
|
||||
}
|
||||
|
||||
project.getLogger().info(":merged mappings in " + stopwatch.stop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches the mapping tree for inner classes with no mapped name, whose enclosing classes have mapped names.
|
||||
* Currently, Yarn does not export mappings for these inner classes.
|
||||
*/
|
||||
private void inheritMappedNamesOfEnclosingClasses(MemoryMappingTree tree) {
|
||||
int intermediaryIdx = tree.getNamespaceId("intermediary");
|
||||
int namedIdx = tree.getNamespaceId("named");
|
||||
|
||||
// The tree does not have an index by intermediary names by default
|
||||
tree.setIndexByDstNames(true);
|
||||
|
||||
for (MappingTree.ClassMapping classEntry : tree.getClasses()) {
|
||||
String intermediaryName = classEntry.getDstName(intermediaryIdx);
|
||||
String namedName = classEntry.getDstName(namedIdx);
|
||||
|
||||
if (intermediaryName.equals(namedName) && intermediaryName.contains("$")) {
|
||||
String[] path = intermediaryName.split(Pattern.quote("$"));
|
||||
int parts = path.length;
|
||||
|
||||
for (int i = parts - 2; i >= 0; i--) {
|
||||
String currentPath = String.join("$", Arrays.copyOfRange(path, 0, i + 1));
|
||||
String namedParentClass = tree.mapClassName(currentPath, intermediaryIdx, namedIdx);
|
||||
|
||||
if (!namedParentClass.equals(currentPath)) {
|
||||
classEntry.setDstName(namedParentClass
|
||||
+ "$" + String.join("$", Arrays.copyOfRange(path, i + 1, path.length)),
|
||||
namedIdx);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private MemoryMappingTree readIntermediaryTree() throws IOException {
|
||||
MemoryMappingTree tree = new MemoryMappingTree();
|
||||
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);
|
||||
}
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
||||
private void suggestFieldNames(MinecraftProviderImpl minecraftProvider, Path oldMappings, Path newMappings) {
|
||||
private void suggestFieldNames(MergedMinecraftProvider minecraftProvider, Path oldMappings, Path newMappings) {
|
||||
Command command = new CommandProposeFieldNames();
|
||||
runCommand(command, minecraftProvider.getMergedJar().getAbsolutePath(),
|
||||
oldMappings.toAbsolutePath().toString(),
|
||||
newMappings.toAbsolutePath().toString());
|
||||
runCommand(command, minecraftProvider.getMergedJar().toFile().getAbsolutePath(),
|
||||
oldMappings.toAbsolutePath().toString(),
|
||||
newMappings.toAbsolutePath().toString());
|
||||
}
|
||||
|
||||
private void runCommand(Command command, String... args) {
|
||||
@@ -546,22 +311,7 @@ public class MappingsProviderImpl extends DependencyProvider implements Mappings
|
||||
}
|
||||
}
|
||||
|
||||
private void initFiles() {
|
||||
mappingsWorkingDir = getMinecraftProvider().dir(mappingsIdentifier).toPath();
|
||||
baseTinyMappings = mappingsWorkingDir.resolve("mappings-base.tiny");
|
||||
tinyMappings = mappingsWorkingDir.resolve("mappings.tiny");
|
||||
tinyMappingsJar = mappingsWorkingDir.resolve("mappings.jar");
|
||||
unpickDefinitions = mappingsWorkingDir.resolve("mappings.unpick");
|
||||
tinyMappingsWithSrg = mappingsWorkingDir.resolve("mappings-srg.tiny");
|
||||
mixinTinyMappingsWithSrg = mappingsWorkingDir.resolve("mappings-mixin-srg.tiny");
|
||||
srgToNamedSrg = mappingsWorkingDir.resolve("mappings-srg-named.srg");
|
||||
|
||||
if (isRefreshDeps()) {
|
||||
cleanFiles();
|
||||
}
|
||||
}
|
||||
|
||||
public void cleanFiles() {
|
||||
private static void cleanWorkingDirectory(Path mappingsWorkingDir) {
|
||||
try {
|
||||
if (Files.exists(mappingsWorkingDir)) {
|
||||
Files.walkFileTree(mappingsWorkingDir, new DeletingFileVisitor());
|
||||
@@ -573,39 +323,20 @@ public class MappingsProviderImpl extends DependencyProvider implements Mappings
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTargetConfig() {
|
||||
return Constants.Configurations.MAPPINGS;
|
||||
}
|
||||
|
||||
public Path getIntermediaryTiny() throws IOException {
|
||||
if (intermediaryTiny == null) {
|
||||
intermediaryTiny = getMinecraftProvider().file("intermediary-v2.tiny").toPath();
|
||||
|
||||
if (!Files.exists(intermediaryTiny) || (isRefreshDeps() && !hasRefreshed)) {
|
||||
hasRefreshed = true;
|
||||
|
||||
// Download and extract intermediary
|
||||
String encodedMinecraftVersion = UrlEscapers.urlFragmentEscaper().escape(getMinecraftProvider().minecraftVersion());
|
||||
String intermediaryArtifactUrl = getExtension().getIntermediaryUrl(encodedMinecraftVersion);
|
||||
File intermediaryJar = getMinecraftProvider().file("intermediary-v2.jar");
|
||||
DownloadUtil.downloadIfChanged(new URL(intermediaryArtifactUrl), intermediaryJar, getProject().getLogger());
|
||||
extractMappings(intermediaryJar.toPath(), intermediaryTiny);
|
||||
}
|
||||
}
|
||||
|
||||
return intermediaryTiny;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path mappingsWorkingDir() {
|
||||
return mappingsWorkingDir;
|
||||
}
|
||||
|
||||
protected String createMappingsIdentifier(String mappingsName, String version, String classifier) {
|
||||
@Override
|
||||
public File intermediaryTinyFile() {
|
||||
return intermediaryService.get().getIntermediaryTiny().toFile();
|
||||
}
|
||||
|
||||
private static String createMappingsIdentifier(String mappingsName, String version, String classifier, String minecraftVersion) {
|
||||
// mappingsName . mcVersion . version classifier
|
||||
// Example: net.fabricmc.yarn . 1_16_5 . 1.16.5+build.5 -v2
|
||||
return mappingsName + "." + getMinecraftProvider().minecraftVersion().replace(' ', '_').replace('.', '_').replace('-', '_') + "." + version + classifier;
|
||||
return mappingsName + "." + minecraftVersion.replace(' ', '_').replace('.', '_').replace('-', '_') + "." + version + classifier;
|
||||
}
|
||||
|
||||
public String mappingsIdentifier() {
|
||||
@@ -625,19 +356,19 @@ public class MappingsProviderImpl extends DependencyProvider implements Mappings
|
||||
return signatureFixes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public File intermediaryTinyFile() {
|
||||
try {
|
||||
return getIntermediaryTiny().toFile();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Failed to get intermediary", e);
|
||||
}
|
||||
}
|
||||
|
||||
public String getBuildServiceName(String name, String from, String to) {
|
||||
return "%s:%s:%s>%S".formatted(name, mappingsIdentifier(), from, to);
|
||||
}
|
||||
|
||||
public record UnpickMetadata(String unpickGroup, String unpickVersion) {
|
||||
}
|
||||
|
||||
protected static boolean isRefreshDeps() {
|
||||
return LoomGradlePlugin.refreshDeps;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
mappingTree = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,11 +24,7 @@
|
||||
|
||||
package net.fabricmc.loom.configuration.providers.mappings.intermediary;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.util.Collections;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@@ -36,9 +32,9 @@ 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;
|
||||
import net.fabricmc.mappingio.tree.MemoryMappingTree;
|
||||
|
||||
public record IntermediaryMappingLayer(Supplier<File> tinyFile) implements MappingLayer {
|
||||
public record IntermediaryMappingLayer(Supplier<MemoryMappingTree> memoryMappingTree) implements MappingLayer {
|
||||
@Override
|
||||
public MappingsNamespace getSourceNamespace() {
|
||||
return MappingsNamespace.OFFICIAL;
|
||||
@@ -49,8 +45,6 @@ public record IntermediaryMappingLayer(Supplier<File> tinyFile) implements Mappi
|
||||
// Populate named with intermediary and add Add a "named" namespace
|
||||
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);
|
||||
}
|
||||
memoryMappingTree.get().accept(nsCompleter);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,6 @@ import net.fabricmc.loom.api.mappings.layered.spec.MappingsSpec;
|
||||
public record IntermediaryMappingsSpec() implements MappingsSpec<IntermediaryMappingLayer> {
|
||||
@Override
|
||||
public IntermediaryMappingLayer createLayer(MappingContext context) {
|
||||
return new IntermediaryMappingLayer(context.mappingsProvider()::intermediaryTinyFile);
|
||||
return new IntermediaryMappingLayer(context.intermediaryTree());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2022 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.tiny;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import com.google.common.base.Stopwatch;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
|
||||
import net.fabricmc.loom.configuration.providers.mappings.IntermediaryService;
|
||||
import net.fabricmc.mappingio.adapter.MappingNsCompleter;
|
||||
import net.fabricmc.mappingio.adapter.MappingSourceNsSwitch;
|
||||
import net.fabricmc.mappingio.format.Tiny2Reader;
|
||||
import net.fabricmc.mappingio.format.Tiny2Writer;
|
||||
import net.fabricmc.mappingio.tree.MappingTree;
|
||||
import net.fabricmc.mappingio.tree.MemoryMappingTree;
|
||||
|
||||
public final class MappingsMerger {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(MappingsMerger.class);
|
||||
|
||||
public static void mergeAndSaveMappings(Path from, Path out, IntermediaryService intermediaryService) throws IOException {
|
||||
Stopwatch stopwatch = Stopwatch.createStarted();
|
||||
LOGGER.info(":merging mappings");
|
||||
|
||||
MemoryMappingTree intermediaryTree = new MemoryMappingTree();
|
||||
intermediaryService.getMemoryMappingTree().accept(new MappingSourceNsSwitch(intermediaryTree, MappingsNamespace.INTERMEDIARY.toString()));
|
||||
|
||||
try (BufferedReader reader = Files.newBufferedReader(from, StandardCharsets.UTF_8)) {
|
||||
Tiny2Reader.read(reader, intermediaryTree);
|
||||
}
|
||||
|
||||
MemoryMappingTree officialTree = new MemoryMappingTree();
|
||||
MappingNsCompleter nsCompleter = new MappingNsCompleter(officialTree, Map.of(MappingsNamespace.OFFICIAL.toString(), MappingsNamespace.INTERMEDIARY.toString()));
|
||||
MappingSourceNsSwitch nsSwitch = new MappingSourceNsSwitch(nsCompleter, MappingsNamespace.OFFICIAL.toString());
|
||||
intermediaryTree.accept(nsSwitch);
|
||||
|
||||
inheritMappedNamesOfEnclosingClasses(officialTree);
|
||||
|
||||
try (Tiny2Writer writer = new Tiny2Writer(Files.newBufferedWriter(out, StandardCharsets.UTF_8), false)) {
|
||||
officialTree.accept(writer);
|
||||
}
|
||||
|
||||
LOGGER.info(":merged mappings in " + stopwatch.stop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches the mapping tree for inner classes with no mapped name, whose enclosing classes have mapped names.
|
||||
* Currently, Yarn does not export mappings for these inner classes.
|
||||
*/
|
||||
private static void inheritMappedNamesOfEnclosingClasses(MemoryMappingTree tree) {
|
||||
int intermediaryIdx = tree.getNamespaceId("intermediary");
|
||||
int namedIdx = tree.getNamespaceId("named");
|
||||
|
||||
// The tree does not have an index by intermediary names by default
|
||||
tree.setIndexByDstNames(true);
|
||||
|
||||
for (MappingTree.ClassMapping classEntry : tree.getClasses()) {
|
||||
String intermediaryName = classEntry.getDstName(intermediaryIdx);
|
||||
String namedName = classEntry.getDstName(namedIdx);
|
||||
|
||||
if (intermediaryName.equals(namedName) && intermediaryName.contains("$")) {
|
||||
String[] path = intermediaryName.split(Pattern.quote("$"));
|
||||
int parts = path.length;
|
||||
|
||||
for (int i = parts - 2; i >= 0; i--) {
|
||||
String currentPath = String.join("$", Arrays.copyOfRange(path, 0, i + 1));
|
||||
String namedParentClass = tree.mapClassName(currentPath, intermediaryIdx, namedIdx);
|
||||
|
||||
if (!namedParentClass.equals(currentPath)) {
|
||||
classEntry.setDstName(namedParentClass
|
||||
+ "$" + String.join("$", Arrays.copyOfRange(path, i + 1, path.length)),
|
||||
namedIdx);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2022 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.tiny;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.nio.file.FileSystem;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Optional;
|
||||
|
||||
import net.fabricmc.mappingio.MappingReader;
|
||||
import net.fabricmc.mappingio.format.MappingFormat;
|
||||
|
||||
public record TinyJarInfo(boolean v2, Optional<String> minecraftVersionId) {
|
||||
public static TinyJarInfo get(Path jar) {
|
||||
try {
|
||||
return new TinyJarInfo(doesJarContainV2Mappings(jar), Optional.empty());
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException("Failed to read tiny jar info", e);
|
||||
}
|
||||
}
|
||||
|
||||
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"))) {
|
||||
return MappingReader.detectFormat(reader) == MappingFormat.TINY_2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* 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.minecraft;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.gradle.api.Project;
|
||||
|
||||
import net.fabricmc.loom.util.HashedDownloadUtil;
|
||||
import net.fabricmc.stitch.merge.JarMerger;
|
||||
|
||||
public final class MergedMinecraftProvider extends MinecraftProvider {
|
||||
private Path minecraftMergedJar;
|
||||
|
||||
public MergedMinecraftProvider(Project project) {
|
||||
super(project);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initFiles() {
|
||||
super.initFiles();
|
||||
minecraftMergedJar = path("minecraft-merged.jar");
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Path> getMinecraftJars() {
|
||||
return List.of(minecraftMergedJar);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void provide() throws Exception {
|
||||
super.provide();
|
||||
|
||||
if (!Files.exists(minecraftMergedJar) || isRefreshDeps()) {
|
||||
try {
|
||||
mergeJars();
|
||||
} catch (Throwable e) {
|
||||
HashedDownloadUtil.delete(getMinecraftClientJar());
|
||||
HashedDownloadUtil.delete(getMinecraftServerJar());
|
||||
Files.deleteIfExists(minecraftMergedJar);
|
||||
|
||||
getProject().getLogger().error("Could not merge JARs! Deleting source JARs - please re-run the command and move on.", e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void mergeJars() throws IOException {
|
||||
getLogger().info(":merging jars");
|
||||
|
||||
File jarToMerge = getMinecraftServerJar();
|
||||
|
||||
if (getServerBundleMetadata() != null) {
|
||||
extractBundledServerJar();
|
||||
jarToMerge = getMinecraftExtractedServerJar();
|
||||
}
|
||||
|
||||
Objects.requireNonNull(jarToMerge, "Cannot merge null input jar?");
|
||||
|
||||
try (JarMerger jarMerger = new JarMerger(getMinecraftClientJar(), jarToMerge, minecraftMergedJar.toFile())) {
|
||||
jarMerger.enableSyntheticParamsOffset();
|
||||
jarMerger.merge();
|
||||
}
|
||||
}
|
||||
|
||||
public Path getMergedJar() {
|
||||
return minecraftMergedJar;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2022 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.minecraft;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.gradle.api.Project;
|
||||
|
||||
import net.fabricmc.loom.configuration.decompile.DecompileConfiguration;
|
||||
import net.fabricmc.loom.configuration.decompile.SingleJarDecompileConfiguration;
|
||||
import net.fabricmc.loom.configuration.decompile.SplitDecompileConfiguration;
|
||||
import net.fabricmc.loom.configuration.processors.JarProcessorManager;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.mapped.IntermediaryMinecraftProvider;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.mapped.MappedMinecraftProvider;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.mapped.NamedMinecraftProvider;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.mapped.ProcessedNamedMinecraftProvider;
|
||||
|
||||
public enum MinecraftJarConfiguration {
|
||||
MERGED(
|
||||
MergedMinecraftProvider::new,
|
||||
IntermediaryMinecraftProvider.MergedImpl::new,
|
||||
NamedMinecraftProvider.MergedImpl::new,
|
||||
ProcessedNamedMinecraftProvider.MergedImpl::new,
|
||||
SingleJarDecompileConfiguration::new,
|
||||
List.of("client", "server")
|
||||
),
|
||||
SERVER_ONLY(
|
||||
ServerOnlyMinecraftProvider::new,
|
||||
IntermediaryMinecraftProvider.ServerOnlyImpl::new,
|
||||
NamedMinecraftProvider.ServerOnlyImpl::new,
|
||||
ProcessedNamedMinecraftProvider.ServerOnlyImpl::new,
|
||||
SingleJarDecompileConfiguration::new,
|
||||
List.of("server")
|
||||
),
|
||||
SPLIT(
|
||||
SplitMinecraftProvider::new,
|
||||
IntermediaryMinecraftProvider.SplitImpl::new,
|
||||
NamedMinecraftProvider.SplitImpl::new,
|
||||
ProcessedNamedMinecraftProvider.SplitImpl::new,
|
||||
SplitDecompileConfiguration::new,
|
||||
List.of("client", "server")
|
||||
);
|
||||
|
||||
private final Function<Project, MinecraftProvider> minecraftProviderFunction;
|
||||
private final BiFunction<Project, MinecraftProvider, IntermediaryMinecraftProvider<?>> intermediaryMinecraftProviderBiFunction;
|
||||
private final BiFunction<Project, MinecraftProvider, NamedMinecraftProvider<?>> namedMinecraftProviderBiFunction;
|
||||
private final BiFunction<NamedMinecraftProvider<?>, JarProcessorManager, ProcessedNamedMinecraftProvider<?, ?>> processedNamedMinecraftProviderBiFunction;
|
||||
private final BiFunction<Project, MappedMinecraftProvider, DecompileConfiguration<?>> decompileConfigurationBiFunction;
|
||||
private final List<String> supportedEnvironments;
|
||||
|
||||
@SuppressWarnings("unchecked") // Just a bit of a generic mess :)
|
||||
<M extends MinecraftProvider, P extends NamedMinecraftProvider<M>, Q extends MappedMinecraftProvider> MinecraftJarConfiguration(
|
||||
Function<Project, M> minecraftProviderFunction,
|
||||
BiFunction<Project, M, IntermediaryMinecraftProvider<M>> intermediaryMinecraftProviderBiFunction,
|
||||
BiFunction<Project, M, P> namedMinecraftProviderBiFunction,
|
||||
BiFunction<P, JarProcessorManager, ProcessedNamedMinecraftProvider<M, P>> processedNamedMinecraftProviderBiFunction,
|
||||
BiFunction<Project, Q, DecompileConfiguration<?>> decompileConfigurationBiFunction,
|
||||
List<String> supportedEnvironments
|
||||
) {
|
||||
this.minecraftProviderFunction = (Function<Project, MinecraftProvider>) minecraftProviderFunction;
|
||||
this.intermediaryMinecraftProviderBiFunction = (BiFunction<Project, MinecraftProvider, IntermediaryMinecraftProvider<?>>) (Object) intermediaryMinecraftProviderBiFunction;
|
||||
this.namedMinecraftProviderBiFunction = (BiFunction<Project, MinecraftProvider, NamedMinecraftProvider<?>>) namedMinecraftProviderBiFunction;
|
||||
this.processedNamedMinecraftProviderBiFunction = (BiFunction<NamedMinecraftProvider<?>, JarProcessorManager, ProcessedNamedMinecraftProvider<?, ?>>) (Object) processedNamedMinecraftProviderBiFunction;
|
||||
this.decompileConfigurationBiFunction = (BiFunction<Project, MappedMinecraftProvider, DecompileConfiguration<?>>) decompileConfigurationBiFunction;
|
||||
this.supportedEnvironments = supportedEnvironments;
|
||||
}
|
||||
|
||||
public Function<Project, MinecraftProvider> getMinecraftProviderFunction() {
|
||||
return minecraftProviderFunction;
|
||||
}
|
||||
|
||||
public BiFunction<Project, MinecraftProvider, IntermediaryMinecraftProvider<?>> getIntermediaryMinecraftProviderBiFunction() {
|
||||
return intermediaryMinecraftProviderBiFunction;
|
||||
}
|
||||
|
||||
public BiFunction<Project, MinecraftProvider, NamedMinecraftProvider<?>> getNamedMinecraftProviderBiFunction() {
|
||||
return namedMinecraftProviderBiFunction;
|
||||
}
|
||||
|
||||
public BiFunction<NamedMinecraftProvider<?>, JarProcessorManager, ProcessedNamedMinecraftProvider<?, ?>> getProcessedNamedMinecraftProviderBiFunction() {
|
||||
return processedNamedMinecraftProviderBiFunction;
|
||||
}
|
||||
|
||||
public BiFunction<Project, MappedMinecraftProvider, DecompileConfiguration<?>> getDecompileConfigurationBiFunction() {
|
||||
return decompileConfigurationBiFunction;
|
||||
}
|
||||
|
||||
public List<String> getSupportedEnvironments() {
|
||||
return supportedEnvironments;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
* 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.minecraft;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.jar.Attributes;
|
||||
import java.util.jar.Manifest;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
import net.fabricmc.loom.util.FileSystemUtil;
|
||||
|
||||
public class MinecraftJarSplitter implements AutoCloseable {
|
||||
private final Path clientInputJar;
|
||||
private final Path serverInputJar;
|
||||
|
||||
private EntryData entryData;
|
||||
private Set<String> sharedEntries = new HashSet<>();
|
||||
private Set<String> forcedClientEntries = new HashSet<>();
|
||||
|
||||
public MinecraftJarSplitter(Path clientInputJar, Path serverInputJar) {
|
||||
this.clientInputJar = Objects.requireNonNull(clientInputJar);
|
||||
this.serverInputJar = Objects.requireNonNull(serverInputJar);
|
||||
}
|
||||
|
||||
public void split(Path clientOnlyOutputJar, Path commonOutputJar) throws IOException {
|
||||
Objects.requireNonNull(clientOnlyOutputJar);
|
||||
Objects.requireNonNull(commonOutputJar);
|
||||
|
||||
if (entryData == null) {
|
||||
entryData = new EntryData(getJarEntries(clientInputJar), getJarEntries(serverInputJar));
|
||||
}
|
||||
|
||||
// Not something we expect, will require 3 jars, server, client and common.
|
||||
assert entryData.serverOnlyEntries.isEmpty();
|
||||
|
||||
copyEntriesToJar(entryData.commonEntries, serverInputJar, commonOutputJar);
|
||||
copyEntriesToJar(entryData.clientOnlyEntries, clientInputJar, clientOnlyOutputJar);
|
||||
}
|
||||
|
||||
public void sharedEntry(String path) {
|
||||
this.sharedEntries.add(path);
|
||||
}
|
||||
|
||||
public void forcedClientEntry(String path) {
|
||||
this.forcedClientEntries.add(path);
|
||||
}
|
||||
|
||||
private Set<String> getJarEntries(Path input) throws IOException {
|
||||
Set<String> entries = Sets.newHashSet();
|
||||
|
||||
try (FileSystemUtil.Delegate fs = FileSystemUtil.getJarFileSystem(input);
|
||||
Stream<Path> walk = Files.walk(fs.get().getPath("/"))) {
|
||||
Iterator<Path> iterator = walk.iterator();
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
Path fsPath = iterator.next();
|
||||
|
||||
if (!Files.isRegularFile(fsPath)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String entryPath = fs.get().getPath("/").relativize(fsPath).toString();
|
||||
|
||||
if (entryPath.startsWith("META-INF/")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
entries.add(entryPath);
|
||||
}
|
||||
}
|
||||
|
||||
return entries;
|
||||
}
|
||||
|
||||
private void copyEntriesToJar(Set<String> entries, Path inputJar, Path outputJar) throws IOException {
|
||||
Files.deleteIfExists(outputJar);
|
||||
|
||||
try (FileSystemUtil.Delegate inputFs = FileSystemUtil.getJarFileSystem(inputJar);
|
||||
FileSystemUtil.Delegate outputFs = FileSystemUtil.getJarFileSystem(outputJar, true)) {
|
||||
for (String entry : entries) {
|
||||
Path inputPath = inputFs.get().getPath(entry);
|
||||
Path outputPath = outputFs.get().getPath(entry);
|
||||
|
||||
assert Files.isRegularFile(inputPath);
|
||||
|
||||
Path outputPathParent = outputPath.getParent();
|
||||
|
||||
if (outputPathParent != null) {
|
||||
Files.createDirectories(outputPathParent);
|
||||
}
|
||||
|
||||
Files.copy(inputPath, outputPath, StandardCopyOption.COPY_ATTRIBUTES);
|
||||
}
|
||||
|
||||
writeManifest(outputFs);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeManifest(FileSystemUtil.Delegate outputFs) throws IOException {
|
||||
final Manifest manifest = new Manifest();
|
||||
manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0");
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
manifest.write(out);
|
||||
Files.createDirectories(outputFs.get().getPath("META-INF"));
|
||||
Files.write(outputFs.get().getPath("META-INF/MANIFEST.MF"), out.toByteArray());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws Exception {
|
||||
}
|
||||
|
||||
private final class EntryData {
|
||||
private final Set<String> clientEntries;
|
||||
private final Set<String> serverEntries;
|
||||
private final Set<String> commonEntries;
|
||||
private final Set<String> clientOnlyEntries;
|
||||
private final Set<String> serverOnlyEntries;
|
||||
|
||||
private EntryData(Set<String> clientEntries, Set<String> serverEntries) {
|
||||
this.clientEntries = clientEntries;
|
||||
this.serverEntries = serverEntries;
|
||||
|
||||
this.commonEntries = Sets.newHashSet(clientEntries);
|
||||
this.commonEntries.retainAll(serverEntries);
|
||||
this.commonEntries.addAll(sharedEntries);
|
||||
this.commonEntries.removeAll(forcedClientEntries);
|
||||
|
||||
this.clientOnlyEntries = Sets.newHashSet(clientEntries);
|
||||
this.clientOnlyEntries.removeAll(serverEntries);
|
||||
this.clientOnlyEntries.addAll(sharedEntries);
|
||||
this.clientOnlyEntries.addAll(forcedClientEntries);
|
||||
|
||||
this.serverOnlyEntries = Sets.newHashSet(serverEntries);
|
||||
this.serverOnlyEntries.removeAll(clientEntries);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -30,16 +30,17 @@ import java.util.regex.Pattern;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.artifacts.ExternalModuleDependency;
|
||||
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.configuration.providers.BundleMetadata;
|
||||
import net.fabricmc.loom.configuration.providers.MinecraftProviderImpl;
|
||||
import net.fabricmc.loom.util.Constants;
|
||||
|
||||
public class MinecraftLibraryProvider {
|
||||
private static final Pattern NATIVES_PATTERN = Pattern.compile("^(?<group>.*)/(.*?)/(?<version>.*)/((?<name>.*?)-([0-9].*?)-)(?<classifier>.*).jar$");
|
||||
|
||||
public void provide(MinecraftProviderImpl minecraftProvider, Project project) {
|
||||
MinecraftVersionMeta versionInfo = minecraftProvider.getVersionInfo();
|
||||
BundleMetadata serverBundleMetadata = minecraftProvider.getServerBundleMetadata();
|
||||
public void provide(MinecraftProvider minecraftProvider, Project project) {
|
||||
final MinecraftJarConfiguration jarConfiguration = LoomGradleExtension.get(project).getMinecraftJarConfiguration().get();
|
||||
final MinecraftVersionMeta versionInfo = minecraftProvider.getVersionInfo();
|
||||
final BundleMetadata serverBundleMetadata = minecraftProvider.getServerBundleMetadata();
|
||||
|
||||
final boolean overrideLWJGL = LWJGLVersionOverride.overrideByDefault() || LWJGLVersionOverride.forceOverride(project) || Boolean.getBoolean("loom.test.lwjgloverride");
|
||||
|
||||
@@ -55,7 +56,7 @@ public class MinecraftLibraryProvider {
|
||||
if (library.isValidForOS() && !library.hasNatives() && library.artifact() != null) {
|
||||
if (serverBundleMetadata != null && isLibraryInBundle(serverBundleMetadata, library)) {
|
||||
project.getDependencies().add(Constants.Configurations.MINECRAFT_SERVER_DEPENDENCIES, library.name());
|
||||
} else {
|
||||
} else if (jarConfiguration.getSupportedEnvironments().contains("client")) {
|
||||
// Client only library, or legacy version
|
||||
project.getDependencies().add(Constants.Configurations.MINECRAFT_DEPENDENCIES, library.name());
|
||||
}
|
||||
|
||||
@@ -1,389 +0,0 @@
|
||||
/*
|
||||
* 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.configuration.providers.minecraft;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import com.google.common.base.Stopwatch;
|
||||
import dev.architectury.tinyremapper.IMappingProvider;
|
||||
import dev.architectury.tinyremapper.InputTag;
|
||||
import dev.architectury.tinyremapper.NonClassCopyMode;
|
||||
import dev.architectury.tinyremapper.OutputConsumerPath;
|
||||
import dev.architectury.tinyremapper.TinyRemapper;
|
||||
import org.apache.commons.lang3.mutable.Mutable;
|
||||
import org.apache.commons.lang3.tuple.Triple;
|
||||
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;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.tr.OutputRemappingHandler;
|
||||
import net.fabricmc.loom.configuration.sources.ForgeSourcesRemapper;
|
||||
import net.fabricmc.loom.util.Constants;
|
||||
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.TinyRemapperHelper;
|
||||
import net.fabricmc.loom.util.srg.AtRemapper;
|
||||
import net.fabricmc.loom.util.srg.CoreModClassRemapper;
|
||||
import net.fabricmc.loom.util.srg.InnerClassRemapper;
|
||||
import net.fabricmc.mappingio.tree.MemoryMappingTree;
|
||||
|
||||
public class MinecraftMappedProvider extends DependencyProvider {
|
||||
private File inputJar;
|
||||
private File inputForgeJar;
|
||||
private File minecraftMappedJar;
|
||||
private File minecraftIntermediaryJar;
|
||||
private File minecraftSrgJar;
|
||||
private File forgeMappedJar;
|
||||
private File forgeIntermediaryJar;
|
||||
private File forgeSrgJar;
|
||||
|
||||
protected MinecraftProviderImpl minecraftProvider;
|
||||
|
||||
public MinecraftMappedProvider(Project project) {
|
||||
super(project);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void provide(DependencyInfo dependency, Consumer<Runnable> postPopulationScheduler) throws Exception {
|
||||
if (Files.notExists(getExtension().getMappingsProvider().tinyMappings)) {
|
||||
throw new RuntimeException("mappings file not found");
|
||||
}
|
||||
|
||||
if (!inputJar.exists()) {
|
||||
throw new RuntimeException("input merged jar not found");
|
||||
}
|
||||
|
||||
boolean isForgeAtDirty = getExtension().isForge() && getExtension().getMappingsProvider().patchedProvider.isAtDirty();
|
||||
boolean needToRemap = false;
|
||||
|
||||
if (!minecraftMappedJar.exists() || !getIntermediaryJar().exists() || (getExtension().isForge() && !getSrgJar().exists()) || isRefreshDeps() || isForgeAtDirty) {
|
||||
needToRemap = true;
|
||||
}
|
||||
|
||||
if (getExtension().isForgeAndNotOfficial() && (!getForgeMappedJar().exists() || !getForgeIntermediaryJar().exists() || !getForgeSrgJar().exists() || isRefreshDeps() || isForgeAtDirty)) {
|
||||
needToRemap = true;
|
||||
}
|
||||
|
||||
if (needToRemap) {
|
||||
if (minecraftMappedJar.exists()) {
|
||||
minecraftMappedJar.delete();
|
||||
}
|
||||
|
||||
minecraftMappedJar.getParentFile().mkdirs();
|
||||
|
||||
if (minecraftIntermediaryJar.exists()) {
|
||||
minecraftIntermediaryJar.delete();
|
||||
}
|
||||
|
||||
if (getExtension().isForge() && minecraftSrgJar.exists()) {
|
||||
minecraftSrgJar.delete();
|
||||
}
|
||||
|
||||
if (getExtension().isForgeAndNotOfficial()) {
|
||||
if (getForgeMappedJar().exists()) {
|
||||
getForgeMappedJar().delete();
|
||||
}
|
||||
|
||||
getForgeMappedJar().getParentFile().mkdirs();
|
||||
getForgeIntermediaryJar().delete();
|
||||
getForgeSrgJar().delete();
|
||||
}
|
||||
|
||||
try {
|
||||
TinyRemapper[] remapperArray = new TinyRemapper[] {null};
|
||||
mapMinecraftJar(remapperArray);
|
||||
remapperArray[0].finish();
|
||||
} catch (Throwable t) {
|
||||
// Cleanup some some things that may be in a bad state now
|
||||
DownloadUtil.delete(minecraftMappedJar);
|
||||
DownloadUtil.delete(minecraftIntermediaryJar);
|
||||
getExtension().getMinecraftProvider().deleteFiles();
|
||||
|
||||
if (getExtension().isForge()) {
|
||||
DownloadUtil.delete(minecraftSrgJar);
|
||||
DownloadUtil.delete(forgeMappedJar);
|
||||
DownloadUtil.delete(forgeSrgJar);
|
||||
DownloadUtil.delete(forgeIntermediaryJar);
|
||||
}
|
||||
|
||||
getExtension().getMappingsProvider().cleanFiles();
|
||||
throw new RuntimeException("Failed to remap minecraft", t);
|
||||
}
|
||||
}
|
||||
|
||||
if (!minecraftMappedJar.exists()) {
|
||||
throw new RuntimeException("mapped jar not found");
|
||||
}
|
||||
|
||||
addDependencies(dependency, postPopulationScheduler);
|
||||
|
||||
if (getExtension().isForgeAndNotOfficial()) {
|
||||
getProject().getDependencies().add(Constants.Configurations.FORGE_NAMED,
|
||||
getProject().getDependencies().module("net.minecraftforge-loom:forge-mapped:" + getMinecraftProvider().minecraftVersion() + "/" + getExtension().getMappingsProvider().mappingsIdentifier() + "/forge"));
|
||||
}
|
||||
|
||||
if (getExtension().isForge()) {
|
||||
getProject().afterEvaluate(project -> {
|
||||
if (!OperatingSystem.isCIBuild()) {
|
||||
try {
|
||||
ForgeSourcesRemapper.addBaseForgeSources(project, getExtension().isForgeAndOfficial());
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private byte[][] inputBytes(Path input) throws IOException {
|
||||
List<byte[]> inputByteList = new ArrayList<>();
|
||||
|
||||
try (FileSystemUtil.Delegate inputFs = FileSystemUtil.getJarFileSystem(input, false)) {
|
||||
ThreadingUtils.TaskCompleter taskCompleter = ThreadingUtils.taskCompleter();
|
||||
|
||||
for (Path path : (Iterable<? extends Path>) Files.walk(inputFs.get().getPath("/"))::iterator) {
|
||||
if (Files.isRegularFile(path)) {
|
||||
if (path.getFileName().toString().endsWith(".class")) {
|
||||
taskCompleter.add(() -> {
|
||||
byte[] bytes = Files.readAllBytes(path);
|
||||
|
||||
synchronized (inputByteList) {
|
||||
inputByteList.add(bytes);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
taskCompleter.complete();
|
||||
}
|
||||
|
||||
return inputByteList.toArray(new byte[0][0]);
|
||||
}
|
||||
|
||||
private void assetsOut(Path input, @Nullable Path assetsOut) throws IOException {
|
||||
if (assetsOut != null) {
|
||||
try (OutputConsumerPath tmpAssetsPath = new OutputConsumerPath.Builder(assetsOut).assumeArchive(true).build()) {
|
||||
if (getExtension().isForge()) {
|
||||
tmpAssetsPath.addNonClassFiles(input, NonClassCopyMode.FIX_META_INF, null);
|
||||
} else {
|
||||
tmpAssetsPath.addNonClassFiles(input);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void mapMinecraftJar(TinyRemapper[] remapperArray) throws Exception {
|
||||
Path input = inputJar.toPath();
|
||||
Path inputForge = inputForgeJar == null ? null : inputForgeJar.toPath();
|
||||
Path outputMapped = minecraftMappedJar.toPath();
|
||||
Path outputIntermediary = minecraftIntermediaryJar.toPath();
|
||||
Path outputSrg = minecraftSrgJar == null ? null : minecraftSrgJar.toPath();
|
||||
|
||||
Path forgeOutputMapped = forgeMappedJar == null ? null : forgeMappedJar.toPath();
|
||||
Path forgeOutputIntermediary = forgeIntermediaryJar == null ? null : forgeIntermediaryJar.toPath();
|
||||
Path forgeOutputSrg = forgeSrgJar == null ? null : forgeSrgJar.toPath();
|
||||
|
||||
Path vanillaAssets = Files.createTempFile("assets", null);
|
||||
Files.deleteIfExists(vanillaAssets);
|
||||
vanillaAssets.toFile().deleteOnExit();
|
||||
Path forgeAssets = Files.createTempFile("assets", null);
|
||||
Files.deleteIfExists(forgeAssets);
|
||||
forgeAssets.toFile().deleteOnExit();
|
||||
|
||||
Info vanilla = new Info(vanillaAssets, input, outputMapped, outputIntermediary, outputSrg);
|
||||
Info forge = getExtension().isForgeAndNotOfficial() ? new Info(forgeAssets, inputForge, forgeOutputMapped, forgeOutputIntermediary, forgeOutputSrg) : null;
|
||||
|
||||
Triple<TinyRemapper, Mutable<MemoryMappingTree>, List<TinyRemapper.ApplyVisitorProvider>> pair = TinyRemapperHelper.getTinyRemapper(getProject(), true, builder -> { });
|
||||
TinyRemapper remapper = remapperArray[0] = pair.getLeft();
|
||||
|
||||
assetsOut(input, vanillaAssets);
|
||||
|
||||
if (getExtension().isForgeAndNotOfficial()) {
|
||||
assetsOut(inputForge, forgeAssets);
|
||||
}
|
||||
|
||||
remap(remapper, pair.getMiddle(), pair.getRight(), vanilla, forge, MappingsNamespace.OFFICIAL.toString());
|
||||
}
|
||||
|
||||
public static class Info {
|
||||
Path assets;
|
||||
Path input;
|
||||
Path outputMapped;
|
||||
Path outputIntermediary;
|
||||
Path outputSrg;
|
||||
|
||||
public Info(Path assets, Path input, Path outputMapped, Path outputIntermediary, Path outputSrg) {
|
||||
this.assets = assets;
|
||||
this.input = input;
|
||||
this.outputMapped = outputMapped;
|
||||
this.outputIntermediary = outputIntermediary;
|
||||
this.outputSrg = outputSrg;
|
||||
}
|
||||
}
|
||||
|
||||
public void remap(TinyRemapper remapper, Mutable<MemoryMappingTree> mappings, List<TinyRemapper.ApplyVisitorProvider> postApply, 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(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();
|
||||
getProject().getLogger().lifecycle(":remapping minecraft (TinyRemapper, " + fromM + " -> " + toM + ")");
|
||||
|
||||
remapper.readInputs(vanillaTag, vanilla.input);
|
||||
|
||||
if (forge != null) {
|
||||
remapper.readInputs(forgeTag, forge.input);
|
||||
}
|
||||
|
||||
remapper.replaceMappings(getMappings(classNames, fromM, toM, mappings));
|
||||
if (!MappingsNamespace.INTERMEDIARY.toString().equals(toM)) mappings.setValue(null);
|
||||
postApply.clear();
|
||||
|
||||
postApply.add(new SignatureFixerApplyVisitor(SignatureFixerApplyVisitor.getRemappedSignatures(MappingsNamespace.INTERMEDIARY.toString().equals(toM), getExtension().getMappingsProvider(), getProject(), toM)));
|
||||
|
||||
OutputRemappingHandler.remap(remapper, vanilla.assets, output, null, vanillaTag);
|
||||
|
||||
if (forge != null) {
|
||||
OutputRemappingHandler.remap(remapper, forge.assets, outputForge, null, forgeTag);
|
||||
}
|
||||
|
||||
getProject().getLogger().lifecycle(":remapped minecraft (TinyRemapper, " + fromM + " -> " + toM + ") in " + stopwatch);
|
||||
remapper.removeInput();
|
||||
mappings.setValue(null);
|
||||
|
||||
if (getExtension().isForge() && !"srg".equals(toM)) {
|
||||
getProject().getLogger().info(":running minecraft finalising tasks");
|
||||
|
||||
MemoryMappingTree yarnWithSrg = getExtension().getMappingsProvider().getMappingsWithSrg();
|
||||
AtRemapper.remap(getProject().getLogger(), output, yarnWithSrg);
|
||||
CoreModClassRemapper.remapJar(output, yarnWithSrg, getProject().getLogger());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Set<IMappingProvider> getMappings(@Nullable Set<String> fromClassNames, String fromM, String toM, Mutable<MemoryMappingTree> mappings) throws IOException {
|
||||
Set<IMappingProvider> providers = new HashSet<>();
|
||||
mappings.setValue(getExtension().isForge() ? getExtension().getMappingsProvider().getMappingsWithSrg() : getExtension().getMappingsProvider().getMappings());
|
||||
providers.add(TinyRemapperHelper.create(mappings.getValue(), fromM, toM, true));
|
||||
|
||||
if (getExtension().isForge()) {
|
||||
if (fromClassNames != null) {
|
||||
providers.add(InnerClassRemapper.of(fromClassNames, getExtension().getMappingsProvider().getMappingsWithSrg(), fromM, toM));
|
||||
}
|
||||
} else {
|
||||
providers.add(out -> TinyRemapperHelper.JSR_TO_JETBRAINS.forEach(out::acceptClass));
|
||||
}
|
||||
|
||||
return providers;
|
||||
}
|
||||
|
||||
protected void addDependencies(DependencyInfo dependency, Consumer<Runnable> postPopulationScheduler) {
|
||||
getProject().getDependencies().add(Constants.Configurations.MINECRAFT_NAMED,
|
||||
getProject().getDependencies().module("net.minecraft:" + minecraftProvider.getJarPrefix() + "minecraft-mapped:" + getMinecraftProvider().minecraftVersion() + "/" + getExtension().getMappingsProvider().mappingsIdentifier()));
|
||||
}
|
||||
|
||||
public void initFiles(MinecraftProviderImpl minecraftProvider, MappingsProviderImpl mappingsProvider) {
|
||||
this.minecraftProvider = minecraftProvider;
|
||||
minecraftIntermediaryJar = new File(getExtension().getMappingsProvider().mappingsWorkingDir().toFile(), "minecraft-intermediary.jar");
|
||||
minecraftSrgJar = !getExtension().isForge() ? null : new File(getExtension().getMappingsProvider().mappingsWorkingDir().toFile(), "minecraft-srg.jar");
|
||||
minecraftMappedJar = new File(getExtension().getMappingsProvider().mappingsWorkingDir().toFile(), minecraftProvider.getJarPrefix() + "minecraft-mapped.jar");
|
||||
inputJar = getExtension().isForge() ? mappingsProvider.patchedProvider.getMergedJar() : minecraftProvider.getMergedJar();
|
||||
|
||||
if (getExtension().isForgeAndNotOfficial()) {
|
||||
inputForgeJar = mappingsProvider.patchedProvider.getForgeMergedJar();
|
||||
forgeIntermediaryJar = new File(getExtension().getMappingsProvider().mappingsWorkingDir().toFile(), "forge/forge-intermediary.jar");
|
||||
forgeSrgJar = new File(getExtension().getMappingsProvider().mappingsWorkingDir().toFile(), "forge/forge-srg.jar");
|
||||
forgeMappedJar = new File(getExtension().getMappingsProvider().mappingsWorkingDir().toFile(), "forge/forge-mapped.jar");
|
||||
} else {
|
||||
inputForgeJar = null;
|
||||
forgeIntermediaryJar = null;
|
||||
forgeSrgJar = null;
|
||||
forgeMappedJar = null;
|
||||
}
|
||||
}
|
||||
|
||||
protected File getJarDirectory(File parentDirectory, String type) {
|
||||
return new File(parentDirectory, getJarVersionString(type));
|
||||
}
|
||||
|
||||
protected String getJarVersionString(String type) {
|
||||
return String.format("%s-%s%s", type, getExtension().getMappingsProvider().mappingsIdentifier(), minecraftProvider.getJarPrefix());
|
||||
}
|
||||
|
||||
public File getIntermediaryJar() {
|
||||
return minecraftIntermediaryJar;
|
||||
}
|
||||
|
||||
public File getSrgJar() {
|
||||
return minecraftSrgJar;
|
||||
}
|
||||
|
||||
public File getMappedJar() {
|
||||
return minecraftMappedJar;
|
||||
}
|
||||
|
||||
public final File getBaseMappedJar() {
|
||||
return minecraftMappedJar;
|
||||
}
|
||||
|
||||
public File getForgeIntermediaryJar() {
|
||||
return forgeIntermediaryJar;
|
||||
}
|
||||
|
||||
public File getForgeSrgJar() {
|
||||
return forgeSrgJar;
|
||||
}
|
||||
|
||||
public File getForgeMappedJar() {
|
||||
return forgeMappedJar;
|
||||
}
|
||||
|
||||
public File getUnpickedJar() {
|
||||
return new File(getExtension().getMappingsProvider().mappingsWorkingDir().toFile(), "minecraft-unpicked.jar");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTargetConfig() {
|
||||
return Constants.Configurations.MINECRAFT_NAMED;
|
||||
}
|
||||
}
|
||||
@@ -22,35 +22,34 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.fabricmc.loom.configuration.providers;
|
||||
package net.fabricmc.loom.configuration.providers.minecraft;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import com.google.common.base.Stopwatch;
|
||||
import com.google.common.io.Files;
|
||||
import org.gradle.api.GradleException;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.logging.Logger;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.LoomGradlePlugin;
|
||||
import net.fabricmc.loom.configuration.DependencyProvider;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.ManifestVersion;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftLibraryProvider;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftVersionMeta;
|
||||
import net.fabricmc.loom.configuration.DependencyInfo;
|
||||
import net.fabricmc.loom.configuration.providers.BundleMetadata;
|
||||
import net.fabricmc.loom.util.Constants;
|
||||
import net.fabricmc.loom.util.DownloadUtil;
|
||||
import net.fabricmc.loom.util.HashedDownloadUtil;
|
||||
import net.fabricmc.loom.util.MirrorUtil;
|
||||
import net.fabricmc.stitch.merge.JarMerger;
|
||||
|
||||
public class MinecraftProviderImpl extends DependencyProvider implements MinecraftProvider {
|
||||
public abstract class MinecraftProvider {
|
||||
private String minecraftVersion;
|
||||
|
||||
private MinecraftVersionMeta versionInfo;
|
||||
@@ -58,30 +57,26 @@ public class MinecraftProviderImpl extends DependencyProvider implements Minecra
|
||||
|
||||
private File workingDir;
|
||||
private File minecraftJson;
|
||||
public File minecraftClientJar;
|
||||
private File minecraftClientJar;
|
||||
// Note this will be the boostrap jar starting with 21w39a
|
||||
public File minecraftServerJar;
|
||||
private File minecraftServerJar;
|
||||
// The extracted server jar from the boostrap, only exists in >=21w39a
|
||||
public File minecraftExtractedServerJar;
|
||||
private File minecraftExtractedServerJar;
|
||||
@Nullable
|
||||
public BundleMetadata serverBundleMetadata;
|
||||
private File minecraftMergedJar;
|
||||
private BundleMetadata serverBundleMetadata;
|
||||
private File versionManifestJson;
|
||||
private File experimentalVersionsJson;
|
||||
private String jarPrefix = "";
|
||||
|
||||
public MinecraftProviderImpl(Project project) {
|
||||
super(project);
|
||||
private final Project project;
|
||||
|
||||
public MinecraftProvider(Project project) {
|
||||
this.project = project;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void provide(DependencyInfo dependency, Consumer<Runnable> postPopulationScheduler) throws Exception {
|
||||
public void provide() throws Exception {
|
||||
final DependencyInfo dependency = DependencyInfo.create(getProject(), Constants.Configurations.MINECRAFT);
|
||||
minecraftVersion = dependency.getDependency().getVersion();
|
||||
|
||||
if (getExtension().shouldGenerateSrgTiny() && !getExtension().isForge()) {
|
||||
addDependency("de.oceanlabs.mcp:mcp_config:" + minecraftVersion, Constants.Configurations.SRG);
|
||||
}
|
||||
|
||||
boolean offline = getProject().getGradle().getStartParameter().isOffline();
|
||||
|
||||
initFiles();
|
||||
@@ -95,9 +90,6 @@ public class MinecraftProviderImpl extends DependencyProvider implements Minecra
|
||||
if (offline) {
|
||||
if (minecraftClientJar.exists() && minecraftServerJar.exists()) {
|
||||
getProject().getLogger().debug("Found client and server jars, presuming up-to-date");
|
||||
} else if (minecraftMergedJar.exists()) {
|
||||
//Strictly we don't need the split jars if the merged one exists, let's try go on
|
||||
getProject().getLogger().warn("Missing game jar but merged jar present, things might end badly");
|
||||
} else {
|
||||
throw new GradleException("Missing jar(s); Client: " + minecraftClientJar.exists() + ", Server: " + minecraftServerJar.exists());
|
||||
}
|
||||
@@ -109,39 +101,17 @@ public class MinecraftProviderImpl extends DependencyProvider implements Minecra
|
||||
|
||||
libraryProvider = new MinecraftLibraryProvider();
|
||||
libraryProvider.provide(this, getProject());
|
||||
|
||||
if (!minecraftMergedJar.exists() || isRefreshDeps()) {
|
||||
try {
|
||||
mergeJars(getProject().getLogger());
|
||||
} catch (Throwable e) {
|
||||
HashedDownloadUtil.delete(minecraftClientJar);
|
||||
HashedDownloadUtil.delete(minecraftServerJar);
|
||||
minecraftMergedJar.delete();
|
||||
|
||||
getProject().getLogger().error("Could not merge JARs! Deleting source JARs - please re-run the command and move on.", e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void initFiles() {
|
||||
workingDir = new File(getDirectories().getUserCache(), minecraftVersion);
|
||||
protected void initFiles() {
|
||||
workingDir = new File(getExtension().getFiles().getUserCache(), minecraftVersion);
|
||||
workingDir.mkdirs();
|
||||
minecraftJson = file("minecraft-info.json");
|
||||
minecraftClientJar = file("minecraft-client.jar");
|
||||
minecraftServerJar = file("minecraft-server.jar");
|
||||
minecraftExtractedServerJar = file("minecraft-extracted_server.jar");
|
||||
minecraftMergedJar = file("minecraft-merged.jar");
|
||||
versionManifestJson = new File(getDirectories().getUserCache(), "version_manifest.json");
|
||||
experimentalVersionsJson = new File(getDirectories().getUserCache(), "experimental_version_manifest.json");
|
||||
}
|
||||
|
||||
public void deleteFiles() {
|
||||
DownloadUtil.delete(minecraftClientJar);
|
||||
DownloadUtil.delete(minecraftServerJar);
|
||||
DownloadUtil.delete(minecraftMergedJar);
|
||||
DownloadUtil.delete(versionManifestJson);
|
||||
DownloadUtil.delete(experimentalVersionsJson);
|
||||
versionManifestJson = new File(getExtension().getFiles().getUserCache(), "version_manifest.json");
|
||||
experimentalVersionsJson = new File(getExtension().getFiles().getUserCache(), "experimental_version_manifest.json");
|
||||
}
|
||||
|
||||
private void downloadMcJson(boolean offline) throws IOException {
|
||||
@@ -268,58 +238,55 @@ public class MinecraftProviderImpl extends DependencyProvider implements Minecra
|
||||
HashedDownloadUtil.downloadIfInvalid(new URL(server.url()), minecraftServerJar, server.sha1(), logger, false);
|
||||
}
|
||||
|
||||
private void mergeJars(Logger logger) throws IOException {
|
||||
logger.info(":merging jars");
|
||||
Stopwatch stopwatch = Stopwatch.createStarted();
|
||||
protected final void extractBundledServerJar() throws IOException {
|
||||
Objects.requireNonNull(getServerBundleMetadata(), "Cannot bundled mc jar from none bundled server jar");
|
||||
|
||||
File jarToMerge = minecraftServerJar;
|
||||
getLogger().info(":Extracting server jar from bootstrap");
|
||||
|
||||
if (serverBundleMetadata != null) {
|
||||
logger.info(":Extracting server jar from bootstrap");
|
||||
|
||||
if (serverBundleMetadata.versions().size() != 1) {
|
||||
throw new UnsupportedOperationException("Expected only 1 version in META-INF/versions.list, but got %d".formatted(serverBundleMetadata.versions().size()));
|
||||
}
|
||||
|
||||
serverBundleMetadata.versions().get(0).unpackEntry(minecraftServerJar.toPath(), minecraftExtractedServerJar.toPath());
|
||||
jarToMerge = minecraftExtractedServerJar;
|
||||
if (getServerBundleMetadata().versions().size() != 1) {
|
||||
throw new UnsupportedOperationException("Expected only 1 version in META-INF/versions.list, but got %d".formatted(getServerBundleMetadata().versions().size()));
|
||||
}
|
||||
|
||||
try (JarMerger jarMerger = new JarMerger(minecraftClientJar, jarToMerge, minecraftMergedJar)) {
|
||||
jarMerger.enableSyntheticParamsOffset();
|
||||
jarMerger.merge();
|
||||
}
|
||||
|
||||
logger.info(":merged jars in " + stopwatch);
|
||||
getServerBundleMetadata().versions().get(0).unpackEntry(minecraftServerJar.toPath(), getMinecraftExtractedServerJar().toPath());
|
||||
}
|
||||
|
||||
public File getMergedJar() {
|
||||
return minecraftMergedJar;
|
||||
}
|
||||
|
||||
@Override
|
||||
public File workingDir() {
|
||||
return workingDir;
|
||||
}
|
||||
|
||||
@Override
|
||||
public File dir(String path) {
|
||||
File dir = file(path);
|
||||
dir.mkdirs();
|
||||
return dir;
|
||||
}
|
||||
|
||||
@Override
|
||||
public File file(String path) {
|
||||
return new File(workingDir(), path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path path(String path) {
|
||||
return file(path).toPath();
|
||||
}
|
||||
|
||||
public File getMinecraftClientJar() {
|
||||
return minecraftClientJar;
|
||||
}
|
||||
|
||||
// May be null on older versions
|
||||
@Nullable
|
||||
public File getMinecraftExtractedServerJar() {
|
||||
return minecraftExtractedServerJar;
|
||||
}
|
||||
|
||||
// This may be the server bundler jar on newer versions prob not what you want.
|
||||
public File getMinecraftServerJar() {
|
||||
return minecraftServerJar;
|
||||
}
|
||||
|
||||
public String minecraftVersion() {
|
||||
return minecraftVersion;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MinecraftVersionMeta getVersionInfo() {
|
||||
return versionInfo;
|
||||
}
|
||||
@@ -328,15 +295,6 @@ public class MinecraftProviderImpl extends DependencyProvider implements Minecra
|
||||
return libraryProvider;
|
||||
}
|
||||
|
||||
public String getJarPrefix() {
|
||||
return jarPrefix;
|
||||
}
|
||||
|
||||
public void setJarPrefix(String jarSuffix) {
|
||||
this.jarPrefix = jarSuffix;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTargetConfig() {
|
||||
return Constants.Configurations.MINECRAFT;
|
||||
}
|
||||
@@ -345,4 +303,22 @@ public class MinecraftProviderImpl extends DependencyProvider implements Minecra
|
||||
public BundleMetadata getServerBundleMetadata() {
|
||||
return serverBundleMetadata;
|
||||
}
|
||||
|
||||
protected Logger getLogger() {
|
||||
return getProject().getLogger();
|
||||
}
|
||||
|
||||
public abstract List<Path> getMinecraftJars();
|
||||
|
||||
protected Project getProject() {
|
||||
return project;
|
||||
}
|
||||
|
||||
protected LoomGradleExtension getExtension() {
|
||||
return LoomGradleExtension.get(getProject());
|
||||
}
|
||||
|
||||
protected boolean isRefreshDeps() {
|
||||
return LoomGradlePlugin.refreshDeps;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2022 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.minecraft;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
|
||||
import org.gradle.api.Project;
|
||||
|
||||
import net.fabricmc.loom.configuration.providers.BundleMetadata;
|
||||
import net.fabricmc.tinyremapper.NonClassCopyMode;
|
||||
import net.fabricmc.tinyremapper.OutputConsumerPath;
|
||||
import net.fabricmc.tinyremapper.TinyRemapper;
|
||||
|
||||
public final class ServerOnlyMinecraftProvider extends MinecraftProvider {
|
||||
private Path minecraftServerOnlyJar;
|
||||
|
||||
public ServerOnlyMinecraftProvider(Project project) {
|
||||
super(project);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initFiles() {
|
||||
super.initFiles();
|
||||
|
||||
minecraftServerOnlyJar = path("minecraft-server-only.jar");
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Path> getMinecraftJars() {
|
||||
return List.of(minecraftServerOnlyJar);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void provide() throws Exception {
|
||||
super.provide();
|
||||
|
||||
boolean requiresRefresh = isRefreshDeps() || Files.notExists(minecraftServerOnlyJar);
|
||||
|
||||
if (!requiresRefresh) {
|
||||
return;
|
||||
}
|
||||
|
||||
BundleMetadata serverBundleMetadata = getServerBundleMetadata();
|
||||
|
||||
if (serverBundleMetadata == null) {
|
||||
throw new UnsupportedOperationException("Only Minecraft versions using a bundled server jar support server only configuration, please use a merged jar setup for this version of minecraft");
|
||||
}
|
||||
|
||||
extractBundledServerJar();
|
||||
final Path serverJar = getMinecraftExtractedServerJar().toPath();
|
||||
|
||||
TinyRemapper remapper = null;
|
||||
|
||||
try {
|
||||
remapper = TinyRemapper.newRemapper().build();
|
||||
|
||||
Files.deleteIfExists(minecraftServerOnlyJar);
|
||||
|
||||
// Pass through tiny remapper to fix the meta-inf
|
||||
try (OutputConsumerPath outputConsumer = new OutputConsumerPath.Builder(minecraftServerOnlyJar).build()) {
|
||||
outputConsumer.addNonClassFiles(serverJar, NonClassCopyMode.FIX_META_INF, remapper);
|
||||
remapper.readInputs(serverJar);
|
||||
remapper.apply(outputConsumer);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Files.deleteIfExists(minecraftServerOnlyJar);
|
||||
throw new RuntimeException("Failed to process server only jar", e);
|
||||
} finally {
|
||||
if (remapper != null) {
|
||||
remapper.finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Path getMinecraftServerOnlyJar() {
|
||||
return minecraftServerOnlyJar;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* 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.minecraft;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
|
||||
import org.gradle.api.Project;
|
||||
|
||||
import net.fabricmc.loom.configuration.providers.BundleMetadata;
|
||||
|
||||
public final class SplitMinecraftProvider extends MinecraftProvider {
|
||||
private Path minecraftClientOnlyJar;
|
||||
private Path minecraftCommonJar;
|
||||
|
||||
public SplitMinecraftProvider(Project project) {
|
||||
super(project);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initFiles() {
|
||||
super.initFiles();
|
||||
|
||||
minecraftClientOnlyJar = path("minecraft-client-only.jar");
|
||||
minecraftCommonJar = path("minecraft-common.jar");
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Path> getMinecraftJars() {
|
||||
return List.of(minecraftClientOnlyJar, minecraftCommonJar);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void provide() throws Exception {
|
||||
super.provide();
|
||||
|
||||
boolean requiresRefresh = isRefreshDeps() || Files.notExists(minecraftClientOnlyJar) || Files.notExists(minecraftCommonJar);
|
||||
|
||||
if (!requiresRefresh) {
|
||||
return;
|
||||
}
|
||||
|
||||
BundleMetadata serverBundleMetadata = getServerBundleMetadata();
|
||||
|
||||
if (serverBundleMetadata == null) {
|
||||
throw new UnsupportedOperationException("Only Minecraft versions using a bundled server jar can be split, please use a merged jar setup for this version of minecraft");
|
||||
}
|
||||
|
||||
extractBundledServerJar();
|
||||
|
||||
final Path clientJar = getMinecraftClientJar().toPath();
|
||||
final Path serverJar = getMinecraftExtractedServerJar().toPath();
|
||||
|
||||
try (MinecraftJarSplitter jarSplitter = new MinecraftJarSplitter(clientJar, serverJar)) {
|
||||
// Required for loader to compute the version info also useful to have in both jars.
|
||||
jarSplitter.sharedEntry("version.json");
|
||||
jarSplitter.forcedClientEntry("assets/.mcassetsroot");
|
||||
|
||||
jarSplitter.split(minecraftClientOnlyJar, minecraftCommonJar);
|
||||
} catch (Exception e) {
|
||||
Files.deleteIfExists(minecraftClientOnlyJar);
|
||||
Files.deleteIfExists(minecraftCommonJar);
|
||||
|
||||
throw new RuntimeException("Failed to split minecraft", e);
|
||||
}
|
||||
}
|
||||
|
||||
public Path getMinecraftClientOnlyJar() {
|
||||
return minecraftClientOnlyJar;
|
||||
}
|
||||
|
||||
public Path getMinecraftCommonJar() {
|
||||
return minecraftCommonJar;
|
||||
}
|
||||
}
|
||||
@@ -43,13 +43,13 @@ import org.gradle.api.Project;
|
||||
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.LoomGradlePlugin;
|
||||
import net.fabricmc.loom.configuration.providers.MinecraftProviderImpl;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftProvider;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftVersionMeta;
|
||||
import net.fabricmc.loom.util.MirrorUtil;
|
||||
import net.fabricmc.loom.util.HashedDownloadUtil;
|
||||
|
||||
public class MinecraftAssetsProvider {
|
||||
public static void provide(MinecraftProviderImpl minecraftProvider, Project project) throws IOException {
|
||||
public static void provide(MinecraftProvider minecraftProvider, Project project) throws IOException {
|
||||
LoomGradleExtension extension = LoomGradleExtension.get(project);
|
||||
boolean offline = project.getGradle().getStartParameter().isOffline();
|
||||
|
||||
|
||||
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
* 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.minecraft.mapped;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
import org.gradle.api.Project;
|
||||
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.LoomGradlePlugin;
|
||||
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
|
||||
import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftProvider;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.SignatureFixerApplyVisitor;
|
||||
import net.fabricmc.loom.util.TinyRemapperHelper;
|
||||
import net.fabricmc.tinyremapper.OutputConsumerPath;
|
||||
import net.fabricmc.tinyremapper.TinyRemapper;
|
||||
|
||||
public abstract class AbstractMappedMinecraftProvider<M extends MinecraftProvider> implements MappedMinecraftProvider.ProviderImpl {
|
||||
protected final M minecraftProvider;
|
||||
private final Project project;
|
||||
protected final LoomGradleExtension extension;
|
||||
|
||||
public AbstractMappedMinecraftProvider(Project project, M minecraftProvider) {
|
||||
this.project = project;
|
||||
this.minecraftProvider = minecraftProvider;
|
||||
this.extension = LoomGradleExtension.get(project);
|
||||
}
|
||||
|
||||
public abstract MappingsNamespace getTargetNamespace();
|
||||
|
||||
public abstract List<RemappedJars> getRemappedJars();
|
||||
|
||||
protected void applyDependencies(BiConsumer<String, String> consumer) {
|
||||
// Override if needed
|
||||
}
|
||||
|
||||
public void provide(boolean applyDependencies) throws Exception {
|
||||
final List<RemappedJars> remappedJars = getRemappedJars();
|
||||
assert !remappedJars.isEmpty();
|
||||
|
||||
if (!areOutputsValid(remappedJars) || LoomGradlePlugin.refreshDeps) {
|
||||
try {
|
||||
remapInputs(remappedJars);
|
||||
} catch (Throwable t) {
|
||||
cleanOutputs(remappedJars);
|
||||
|
||||
throw new RuntimeException("Failed to remap minecraft", t);
|
||||
}
|
||||
}
|
||||
|
||||
if (applyDependencies) {
|
||||
applyDependencies((configuration, name) -> getProject().getDependencies().add(configuration, getDependencyNotation(name)));
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract Path getDirectory();
|
||||
|
||||
@Override
|
||||
public Path getJar(String name) {
|
||||
return getDirectory().resolve(getName(name) + ".jar");
|
||||
}
|
||||
|
||||
protected String getName(String name) {
|
||||
return "minecraft-%s-%s".formatted(name, getTargetNamespace().toString());
|
||||
}
|
||||
|
||||
protected String getDependencyNotation(String name) {
|
||||
return "net.minecraft:%s:%s/%s".formatted(getName(name), extension.getMinecraftProvider().minecraftVersion(), extension.getMappingsProvider().mappingsIdentifier());
|
||||
}
|
||||
|
||||
private boolean areOutputsValid(List<RemappedJars> remappedJars) {
|
||||
for (RemappedJars remappedJar : remappedJars) {
|
||||
if (!Files.exists(remappedJar.outputJar())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void remapInputs(List<RemappedJars> remappedJars) throws IOException {
|
||||
cleanOutputs(remappedJars);
|
||||
|
||||
for (RemappedJars remappedJar : remappedJars) {
|
||||
remapJar(remappedJar);
|
||||
}
|
||||
}
|
||||
|
||||
private void remapJar(RemappedJars remappedJars) throws IOException {
|
||||
final MappingsProviderImpl mappingsProvider = extension.getMappingsProvider();
|
||||
final String fromM = remappedJars.sourceNamespace().toString();
|
||||
final String toM = getTargetNamespace().toString();
|
||||
|
||||
Files.deleteIfExists(remappedJars.outputJar());
|
||||
|
||||
final Map<String, String> remappedSignatures = SignatureFixerApplyVisitor.getRemappedSignatures(getTargetNamespace() == MappingsNamespace.INTERMEDIARY, mappingsProvider, project, toM);
|
||||
TinyRemapper remapper = TinyRemapperHelper.getTinyRemapper(project, fromM, toM, true, (builder) -> {
|
||||
builder.extraPostApplyVisitor(new SignatureFixerApplyVisitor(remappedSignatures));
|
||||
configureRemapper(remappedJars, builder);
|
||||
});
|
||||
|
||||
try (OutputConsumerPath outputConsumer = new OutputConsumerPath.Builder(remappedJars.outputJar()).build()) {
|
||||
outputConsumer.addNonClassFiles(remappedJars.inputJar());
|
||||
remapper.readClassPath(TinyRemapperHelper.getMinecraftDependencies(project));
|
||||
|
||||
for (Path path : remappedJars.remapClasspath()) {
|
||||
remapper.readClassPath(path);
|
||||
}
|
||||
|
||||
remapper.readInputs(remappedJars.inputJar());
|
||||
remapper.apply(outputConsumer);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Failed to remap JAR " + remappedJars.inputJar() + " with mappings from " + mappingsProvider.tinyMappings, e);
|
||||
} finally {
|
||||
remapper.finish();
|
||||
}
|
||||
}
|
||||
|
||||
protected void configureRemapper(RemappedJars remappedJars, TinyRemapper.Builder tinyRemapperBuilder) {
|
||||
}
|
||||
|
||||
private void cleanOutputs(List<RemappedJars> remappedJars) throws IOException {
|
||||
for (RemappedJars remappedJar : remappedJars) {
|
||||
Files.deleteIfExists(remappedJar.outputJar());
|
||||
}
|
||||
}
|
||||
|
||||
public Project getProject() {
|
||||
return project;
|
||||
}
|
||||
|
||||
public M getMinecraftProvider() {
|
||||
return minecraftProvider;
|
||||
}
|
||||
|
||||
public record RemappedJars(Path inputJar, Path outputJar, MappingsNamespace sourceNamespace, Path... remapClasspath) {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* 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.minecraft.mapped;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
|
||||
import org.gradle.api.Project;
|
||||
|
||||
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MergedMinecraftProvider;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftProvider;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.ServerOnlyMinecraftProvider;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.SplitMinecraftProvider;
|
||||
import net.fabricmc.loom.util.SidedClassVisitor;
|
||||
import net.fabricmc.tinyremapper.TinyRemapper;
|
||||
|
||||
public abstract sealed class IntermediaryMinecraftProvider<M extends MinecraftProvider> extends AbstractMappedMinecraftProvider<M> permits IntermediaryMinecraftProvider.MergedImpl, IntermediaryMinecraftProvider.ServerOnlyImpl, IntermediaryMinecraftProvider.SplitImpl {
|
||||
public IntermediaryMinecraftProvider(Project project, M minecraftProvider) {
|
||||
super(project, minecraftProvider);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Path getDirectory() {
|
||||
return extension.getMinecraftProvider().workingDir().toPath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final MappingsNamespace getTargetNamespace() {
|
||||
return MappingsNamespace.INTERMEDIARY;
|
||||
}
|
||||
|
||||
public static final class MergedImpl extends IntermediaryMinecraftProvider<MergedMinecraftProvider> implements Merged {
|
||||
public MergedImpl(Project project, MergedMinecraftProvider minecraftProvider) {
|
||||
super(project, minecraftProvider);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<RemappedJars> getRemappedJars() {
|
||||
return List.of(
|
||||
new RemappedJars(minecraftProvider.getMergedJar(), getMergedJar(), MappingsNamespace.OFFICIAL)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public static final class SplitImpl extends IntermediaryMinecraftProvider<SplitMinecraftProvider> implements Split {
|
||||
public SplitImpl(Project project, SplitMinecraftProvider minecraftProvider) {
|
||||
super(project, minecraftProvider);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<RemappedJars> getRemappedJars() {
|
||||
return List.of(
|
||||
new RemappedJars(minecraftProvider.getMinecraftCommonJar(), getCommonJar(), MappingsNamespace.OFFICIAL),
|
||||
new RemappedJars(minecraftProvider.getMinecraftClientOnlyJar(), getClientOnlyJar(), MappingsNamespace.OFFICIAL, minecraftProvider.getMinecraftCommonJar())
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configureRemapper(RemappedJars remappedJars, TinyRemapper.Builder tinyRemapperBuilder) {
|
||||
if (remappedJars.outputJar().equals(getClientOnlyJar())) {
|
||||
tinyRemapperBuilder.extraPostApplyVisitor(SidedClassVisitor.CLIENT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static final class ServerOnlyImpl extends IntermediaryMinecraftProvider<ServerOnlyMinecraftProvider> implements ServerOnly {
|
||||
public ServerOnlyImpl(Project project, ServerOnlyMinecraftProvider minecraftProvider) {
|
||||
super(project, minecraftProvider);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<RemappedJars> getRemappedJars() {
|
||||
return List.of(
|
||||
new RemappedJars(minecraftProvider.getMinecraftServerOnlyJar(), getServerOnlyJar(), MappingsNamespace.OFFICIAL)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* 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.minecraft.mapped;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
|
||||
public interface MappedMinecraftProvider {
|
||||
List<Path> getMinecraftJars();
|
||||
|
||||
interface ProviderImpl extends MappedMinecraftProvider {
|
||||
Path getJar(String name);
|
||||
}
|
||||
|
||||
interface Merged extends ProviderImpl {
|
||||
String MERGED = "merged";
|
||||
|
||||
default Path getMergedJar() {
|
||||
return getJar(MERGED);
|
||||
}
|
||||
|
||||
@Override
|
||||
default List<Path> getMinecraftJars() {
|
||||
return List.of(getMergedJar());
|
||||
}
|
||||
}
|
||||
|
||||
interface Split extends ProviderImpl {
|
||||
String COMMON = "common";
|
||||
String CLIENT_ONLY = "clientOnly";
|
||||
|
||||
default Path getCommonJar() {
|
||||
return getJar(COMMON);
|
||||
}
|
||||
|
||||
default Path getClientOnlyJar() {
|
||||
return getJar(CLIENT_ONLY);
|
||||
}
|
||||
|
||||
@Override
|
||||
default List<Path> getMinecraftJars() {
|
||||
return List.of(getCommonJar(), getClientOnlyJar());
|
||||
}
|
||||
}
|
||||
|
||||
interface ServerOnly extends ProviderImpl {
|
||||
String SERVER_ONLY = "serverOnly";
|
||||
|
||||
default Path getServerOnlyJar() {
|
||||
return getJar(SERVER_ONLY);
|
||||
}
|
||||
|
||||
@Override
|
||||
default List<Path> getMinecraftJars() {
|
||||
return List.of(getServerOnlyJar());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* 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.minecraft.mapped;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
import org.gradle.api.Project;
|
||||
|
||||
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MergedMinecraftProvider;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftProvider;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.ServerOnlyMinecraftProvider;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.SplitMinecraftProvider;
|
||||
import net.fabricmc.loom.util.Constants;
|
||||
import net.fabricmc.loom.util.SidedClassVisitor;
|
||||
import net.fabricmc.tinyremapper.TinyRemapper;
|
||||
|
||||
public abstract class NamedMinecraftProvider<M extends MinecraftProvider> extends AbstractMappedMinecraftProvider<M> {
|
||||
public NamedMinecraftProvider(Project project, M minecraftProvider) {
|
||||
super(project, minecraftProvider);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Path getDirectory() {
|
||||
return extension.getMappingsProvider().mappingsWorkingDir();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final MappingsNamespace getTargetNamespace() {
|
||||
return MappingsNamespace.NAMED;
|
||||
}
|
||||
|
||||
public static final class MergedImpl extends NamedMinecraftProvider<MergedMinecraftProvider> implements Merged {
|
||||
public MergedImpl(Project project, MergedMinecraftProvider minecraftProvider) {
|
||||
super(project, minecraftProvider);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<RemappedJars> getRemappedJars() {
|
||||
return List.of(
|
||||
new RemappedJars(minecraftProvider.getMergedJar(), getMergedJar(), MappingsNamespace.OFFICIAL)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void applyDependencies(BiConsumer<String, String> consumer) {
|
||||
consumer.accept(Constants.Configurations.MINECRAFT_NAMED, MERGED);
|
||||
}
|
||||
}
|
||||
|
||||
public static final class SplitImpl extends NamedMinecraftProvider<SplitMinecraftProvider> implements Split {
|
||||
public SplitImpl(Project project, SplitMinecraftProvider minecraftProvider) {
|
||||
super(project, minecraftProvider);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<RemappedJars> getRemappedJars() {
|
||||
return List.of(
|
||||
new RemappedJars(minecraftProvider.getMinecraftCommonJar(), getCommonJar(), MappingsNamespace.OFFICIAL),
|
||||
new RemappedJars(minecraftProvider.getMinecraftClientOnlyJar(), getClientOnlyJar(), MappingsNamespace.OFFICIAL, minecraftProvider.getMinecraftCommonJar())
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configureRemapper(RemappedJars remappedJars, TinyRemapper.Builder tinyRemapperBuilder) {
|
||||
if (remappedJars.outputJar().equals(getClientOnlyJar())) {
|
||||
tinyRemapperBuilder.extraPostApplyVisitor(SidedClassVisitor.CLIENT);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void applyDependencies(BiConsumer<String, String> consumer) {
|
||||
consumer.accept(Constants.Configurations.MINECRAFT_NAMED, COMMON);
|
||||
consumer.accept(Constants.Configurations.MINECRAFT_NAMED, CLIENT_ONLY);
|
||||
}
|
||||
}
|
||||
|
||||
public static final class ServerOnlyImpl extends NamedMinecraftProvider<ServerOnlyMinecraftProvider> implements ServerOnly {
|
||||
public ServerOnlyImpl(Project project, ServerOnlyMinecraftProvider minecraftProvider) {
|
||||
super(project, minecraftProvider);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<RemappedJars> getRemappedJars() {
|
||||
return List.of(
|
||||
new RemappedJars(minecraftProvider.getMinecraftServerOnlyJar(), getServerOnlyJar(), MappingsNamespace.OFFICIAL)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void applyDependencies(BiConsumer<String, String> consumer) {
|
||||
consumer.accept(Constants.Configurations.MINECRAFT_NAMED, SERVER_ONLY);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
* 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.minecraft.mapped;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.util.List;
|
||||
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.LoomGradlePlugin;
|
||||
import net.fabricmc.loom.configuration.processors.JarProcessorManager;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MergedMinecraftProvider;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftProvider;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.ServerOnlyMinecraftProvider;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.SplitMinecraftProvider;
|
||||
|
||||
public abstract class ProcessedNamedMinecraftProvider<M extends MinecraftProvider, P extends NamedMinecraftProvider<M>> extends NamedMinecraftProvider<M> {
|
||||
private final P parentMinecraftProvider;
|
||||
private final JarProcessorManager jarProcessorManager;
|
||||
private final String projectMappedName;
|
||||
private final Path projectMappedDir;
|
||||
|
||||
public ProcessedNamedMinecraftProvider(P parentMinecraftProvide, JarProcessorManager jarProcessorManager) {
|
||||
super(parentMinecraftProvide.getProject(), parentMinecraftProvide.getMinecraftProvider());
|
||||
this.parentMinecraftProvider = parentMinecraftProvide;
|
||||
this.jarProcessorManager = jarProcessorManager;
|
||||
|
||||
this.projectMappedName = "minecraft-project-%s-".formatted(getProject().getPath().replace(':', '@'));
|
||||
|
||||
final LoomGradleExtension extension = LoomGradleExtension.get(getProject());
|
||||
this.projectMappedDir = extension.getFiles().getRootProjectPersistentCache().toPath()
|
||||
.resolve(getMinecraftProvider().minecraftVersion())
|
||||
.resolve(extension.getMappingsProvider().mappingsIdentifier());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void provide(boolean applyDependencies) throws Exception {
|
||||
parentMinecraftProvider.provide(false);
|
||||
|
||||
final List<Path> inputJars = parentMinecraftProvider.getMinecraftJars();
|
||||
boolean requiresProcessing = LoomGradlePlugin.refreshDeps || inputJars.stream()
|
||||
.map(this::getProcessedPath)
|
||||
.map(Path::toFile)
|
||||
.anyMatch(jarProcessorManager::isInvalid);
|
||||
|
||||
if (requiresProcessing) {
|
||||
try {
|
||||
Files.createDirectories(projectMappedDir);
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException("Failed to create project mapped dir", e);
|
||||
}
|
||||
|
||||
for (Path inputJar : inputJars) {
|
||||
final Path outputJar = getProcessedPath(inputJar);
|
||||
deleteSimilarJars(outputJar);
|
||||
|
||||
Files.copy(inputJar, outputJar, StandardCopyOption.REPLACE_EXISTING);
|
||||
jarProcessorManager.process(outputJar.toFile());
|
||||
}
|
||||
}
|
||||
|
||||
if (applyDependencies) {
|
||||
parentMinecraftProvider.applyDependencies((configuration, name) -> getProject().getDependencies().add(configuration, getDependencyNotation(name)));
|
||||
}
|
||||
}
|
||||
|
||||
private void deleteSimilarJars(Path jar) throws IOException {
|
||||
Files.deleteIfExists(jar);
|
||||
|
||||
for (Path path : Files.list(jar.getParent()).filter(Files::isRegularFile)
|
||||
.filter(path -> path.getFileName().startsWith(jar.getFileName().toString().replace(".jar", ""))).toList()) {
|
||||
Files.deleteIfExists(path);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getName(String name) {
|
||||
return "%s%s-%s".formatted(projectMappedName, name, getTargetNamespace().toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getJar(String name) {
|
||||
// Something has gone wrong if this gets called.
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<RemappedJars> getRemappedJars() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Path> getMinecraftJars() {
|
||||
return getParentMinecraftProvider().getMinecraftJars().stream()
|
||||
.map(this::getProcessedPath)
|
||||
.toList();
|
||||
}
|
||||
|
||||
public P getParentMinecraftProvider() {
|
||||
return parentMinecraftProvider;
|
||||
}
|
||||
|
||||
public Path getProcessedPath(Path input) {
|
||||
return projectMappedDir.resolve(input.getFileName().toString().replace("minecraft-", projectMappedName));
|
||||
}
|
||||
|
||||
public static final class MergedImpl extends ProcessedNamedMinecraftProvider<MergedMinecraftProvider, NamedMinecraftProvider.MergedImpl> implements Merged {
|
||||
public MergedImpl(NamedMinecraftProvider.MergedImpl parentMinecraftProvide, JarProcessorManager jarProcessorManager) {
|
||||
super(parentMinecraftProvide, jarProcessorManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getMergedJar() {
|
||||
return getProcessedPath(getParentMinecraftProvider().getMergedJar());
|
||||
}
|
||||
}
|
||||
|
||||
public static final class SplitImpl extends ProcessedNamedMinecraftProvider<SplitMinecraftProvider, NamedMinecraftProvider.SplitImpl> implements Split {
|
||||
public SplitImpl(NamedMinecraftProvider.SplitImpl parentMinecraftProvide, JarProcessorManager jarProcessorManager) {
|
||||
super(parentMinecraftProvide, jarProcessorManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getCommonJar() {
|
||||
return getProcessedPath(getParentMinecraftProvider().getCommonJar());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getClientOnlyJar() {
|
||||
return getProcessedPath(getParentMinecraftProvider().getClientOnlyJar());
|
||||
}
|
||||
}
|
||||
|
||||
public static final class ServerOnlyImpl extends ProcessedNamedMinecraftProvider<ServerOnlyMinecraftProvider, NamedMinecraftProvider.ServerOnlyImpl> implements ServerOnly {
|
||||
public ServerOnlyImpl(NamedMinecraftProvider.ServerOnlyImpl parentMinecraftProvide, JarProcessorManager jarProcessorManager) {
|
||||
super(parentMinecraftProvide, jarProcessorManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getServerOnlyJar() {
|
||||
return getProcessedPath(getParentMinecraftProvider().getServerOnlyJar());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,7 @@ package net.fabricmc.loom.decompilers;
|
||||
import org.gradle.api.Project;
|
||||
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.api.decompilers.LoomDecompiler;
|
||||
import net.fabricmc.loom.decompilers.cfr.LoomCFRDecompiler;
|
||||
import net.fabricmc.loom.decompilers.fernflower.FabricFernFlowerDecompiler;
|
||||
|
||||
@@ -35,8 +36,11 @@ public final class DecompilerConfiguration {
|
||||
}
|
||||
|
||||
public static void setup(Project project) {
|
||||
LoomGradleExtension extension = LoomGradleExtension.get(project);
|
||||
extension.getGameDecompilers().add(new FabricFernFlowerDecompiler());
|
||||
extension.getGameDecompilers().add(new LoomCFRDecompiler());
|
||||
registerDecompiler(project, "fernFlower", FabricFernFlowerDecompiler.class);
|
||||
registerDecompiler(project, "cfr", LoomCFRDecompiler.class);
|
||||
}
|
||||
|
||||
private static void registerDecompiler(Project project, String name, Class<? extends LoomDecompiler> decompilerClass) {
|
||||
LoomGradleExtension.get(project).getDecompilerOptions().register(name, options -> options.getDecompilerClassName().set(decompilerClass.getName()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,8 +30,6 @@ import java.io.Writer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.jar.Attributes;
|
||||
@@ -48,20 +46,14 @@ import org.benf.cfr.reader.util.output.SinkDumperFactory;
|
||||
|
||||
import net.fabricmc.loom.api.decompilers.DecompilationMetadata;
|
||||
import net.fabricmc.loom.api.decompilers.LoomDecompiler;
|
||||
import net.fabricmc.loom.decompilers.LineNumberRemapper;
|
||||
|
||||
public class LoomCFRDecompiler implements LoomDecompiler {
|
||||
public final class LoomCFRDecompiler implements LoomDecompiler {
|
||||
private static final Map<String, String> DECOMPILE_OPTIONS = Map.of(
|
||||
"renameillegalidents", "true",
|
||||
"trackbytecodeloc", "true",
|
||||
"comments", "false"
|
||||
);
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return "Cfr";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decompile(Path compiledJar, Path sourcesDestination, Path linemapDestination, DecompilationMetadata metaData) {
|
||||
final String path = compiledJar.toAbsolutePath().toString();
|
||||
@@ -132,21 +124,4 @@ public class LoomCFRDecompiler implements LoomDecompiler {
|
||||
throw new UncheckedIOException("Failed to write line map", e);
|
||||
}
|
||||
}
|
||||
|
||||
// A test main class to make it quicker/easier to debug with minimal jars
|
||||
public static void main(String[] args) throws IOException {
|
||||
LoomCFRDecompiler decompiler = new LoomCFRDecompiler();
|
||||
|
||||
Path lineMap = Paths.get("linemap.txt");
|
||||
|
||||
decompiler.decompile(Paths.get("input.jar"),
|
||||
Paths.get("output-sources.jar"),
|
||||
lineMap,
|
||||
new DecompilationMetadata(4, null, Collections.emptyList(), null, Collections.emptyMap())
|
||||
);
|
||||
|
||||
LineNumberRemapper lineNumberRemapper = new LineNumberRemapper();
|
||||
lineNumberRemapper.readMappings(lineMap.toFile());
|
||||
lineNumberRemapper.process(null, Paths.get("input.jar"), Paths.get("output.jar"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,11 +37,6 @@ import net.fabricmc.loom.api.decompilers.DecompilationMetadata;
|
||||
import net.fabricmc.loom.api.decompilers.LoomDecompiler;
|
||||
|
||||
public final class FabricFernFlowerDecompiler implements LoomDecompiler {
|
||||
@Override
|
||||
public String name() {
|
||||
return "FernFlower";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decompile(Path compiledJar, Path sourcesDestination, Path linemapDestination, DecompilationMetadata metaData) {
|
||||
final Map<String, Object> options = new HashMap<>(
|
||||
|
||||
@@ -47,4 +47,5 @@ public interface LoomFiles {
|
||||
File getDefaultLog4jConfigFile();
|
||||
File getDevLauncherConfig();
|
||||
File getUnpickLoggingConfigFile();
|
||||
File getRemapClasspathFile();
|
||||
}
|
||||
|
||||
@@ -92,4 +92,9 @@ public abstract class LoomFilesBaseImpl implements LoomFiles {
|
||||
public File getUnpickLoggingConfigFile() {
|
||||
return new File(getProjectPersistentCache(), "unpick-logging.properties");
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getRemapClasspathFile() {
|
||||
return new File(getProjectPersistentCache(), "remapClasspath.txt");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,6 @@ import java.util.function.Consumer;
|
||||
|
||||
import com.google.common.base.Suppliers;
|
||||
import org.gradle.api.Action;
|
||||
import org.gradle.api.DomainObjectCollection;
|
||||
import org.gradle.api.NamedDomainObjectContainer;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.artifacts.Dependency;
|
||||
@@ -47,7 +46,7 @@ import org.gradle.api.publish.maven.MavenPublication;
|
||||
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.decompilers.DecompilerOptions;
|
||||
import net.fabricmc.loom.api.decompilers.architectury.ArchitecturyLoomDecompiler;
|
||||
import net.fabricmc.loom.api.mappings.layered.spec.LayeredMappingSpecBuilder;
|
||||
import net.fabricmc.loom.configuration.ide.RunConfig;
|
||||
@@ -59,6 +58,7 @@ import net.fabricmc.loom.configuration.providers.mappings.GradleMappingContext;
|
||||
import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingSpec;
|
||||
import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingSpecBuilderImpl;
|
||||
import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingsDependency;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftJarConfiguration;
|
||||
import net.fabricmc.loom.util.DeprecationHelper;
|
||||
import net.fabricmc.loom.util.ModPlatform;
|
||||
|
||||
@@ -70,7 +70,6 @@ public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionA
|
||||
private static final String PLATFORM_PROPERTY = "loom.platform";
|
||||
|
||||
protected final DeprecationHelper deprecationHelper;
|
||||
protected final DomainObjectCollection<LoomDecompiler> decompilers;
|
||||
protected final ListProperty<JarProcessor> jarProcessors;
|
||||
protected final ConfigurableFileCollection log4jConfigs;
|
||||
protected final RegularFileProperty accessWidener;
|
||||
@@ -81,10 +80,12 @@ public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionA
|
||||
protected final Property<Boolean> transitiveAccessWideners;
|
||||
protected final Property<String> intermediary;
|
||||
protected final Property<Boolean> enableInterfaceInjection;
|
||||
private final Property<MinecraftJarConfiguration> minecraftJarConfiguration;
|
||||
|
||||
private final ModVersionParser versionParser;
|
||||
|
||||
private NamedDomainObjectContainer<RunConfigSettings> runConfigs;
|
||||
private final NamedDomainObjectContainer<RunConfigSettings> runConfigs;
|
||||
private final NamedDomainObjectContainer<DecompilerOptions> decompilers;
|
||||
|
||||
// ===================
|
||||
// Architectury Loom
|
||||
@@ -98,9 +99,6 @@ public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionA
|
||||
private NamedDomainObjectContainer<LaunchProviderSettings> launchConfigs;
|
||||
|
||||
protected LoomGradleExtensionApiImpl(Project project, LoomFiles directories) {
|
||||
this.runConfigs = project.container(RunConfigSettings.class,
|
||||
baseName -> new RunConfigSettings(project, baseName));
|
||||
this.decompilers = project.getObjects().domainObjectSet(LoomDecompiler.class);
|
||||
this.jarProcessors = project.getObjects().listProperty(JarProcessor.class)
|
||||
.empty();
|
||||
this.log4jConfigs = project.files(directories.getDefaultLog4jConfigFile());
|
||||
@@ -124,6 +122,16 @@ public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionA
|
||||
this.versionParser = new ModVersionParser(project);
|
||||
|
||||
this.deprecationHelper = new DeprecationHelper.ProjectBased(project);
|
||||
|
||||
this.runConfigs = project.container(RunConfigSettings.class,
|
||||
baseName -> new RunConfigSettings(project, baseName));
|
||||
this.decompilers = project.getObjects().domainObjectContainer(DecompilerOptions.class);
|
||||
|
||||
this.minecraftJarConfiguration = project.getObjects().property(MinecraftJarConfiguration.class).convention(MinecraftJarConfiguration.MERGED);
|
||||
this.minecraftJarConfiguration.finalizeValueOnRead();
|
||||
|
||||
this.accessWidener.finalizeValueOnRead();
|
||||
this.getGameJarProcessors().finalizeValueOnRead();
|
||||
this.platform = project.provider(Suppliers.memoize(() -> {
|
||||
Object platformProperty = project.findProperty(PLATFORM_PROPERTY);
|
||||
|
||||
@@ -161,10 +169,15 @@ public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionA
|
||||
}
|
||||
|
||||
@Override
|
||||
public DomainObjectCollection<LoomDecompiler> getGameDecompilers() {
|
||||
public NamedDomainObjectContainer<DecompilerOptions> getDecompilerOptions() {
|
||||
return decompilers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decompilers(Action<NamedDomainObjectContainer<DecompilerOptions>> action) {
|
||||
action.execute(decompilers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListProperty<JarProcessor> getGameJarProcessors() {
|
||||
return jarProcessors;
|
||||
@@ -244,6 +257,11 @@ public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionA
|
||||
net.fabricmc.loom.configuration.MavenPublication.excludePublication(publication);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Property<MinecraftJarConfiguration> getMinecraftJarConfiguration() {
|
||||
return minecraftJarConfiguration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void silentMojangMappingsLicense() {
|
||||
this.silentMojangMappingsLicense = true;
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
package net.fabricmc.loom.extension;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@@ -41,14 +41,18 @@ import org.gradle.api.Project;
|
||||
import org.gradle.api.artifacts.Configuration;
|
||||
import org.gradle.api.file.ConfigurableFileCollection;
|
||||
import org.gradle.api.file.FileCollection;
|
||||
import org.gradle.api.tasks.SourceSet;
|
||||
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
|
||||
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.configuration.providers.mappings.MappingsProviderImpl;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftProvider;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.mapped.IntermediaryMinecraftProvider;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.mapped.NamedMinecraftProvider;
|
||||
import net.fabricmc.loom.util.ModPlatform;
|
||||
import net.fabricmc.loom.util.function.LazyBool;
|
||||
|
||||
@@ -59,7 +63,6 @@ public class LoomGradleExtensionImpl extends LoomGradleExtensionApiImpl implemen
|
||||
private final ConfigurableFileCollection unmappedMods;
|
||||
private final Supplier<ForgeExtensionAPI> forgeExtension;
|
||||
|
||||
private final ConfigurableFileCollection mixinMappings;
|
||||
private final MappingSet[] srcMappingCache = new MappingSet[2];
|
||||
private final Mercury[] srcMercuryCache = new Mercury[2];
|
||||
private final Map<String, NamedDomainObjectProvider<Configuration>> lazyConfigurations = new HashMap<>();
|
||||
@@ -67,6 +70,10 @@ public class LoomGradleExtensionImpl extends LoomGradleExtensionApiImpl implemen
|
||||
|
||||
private LoomDependencyManager dependencyManager;
|
||||
private JarProcessorManager jarProcessorManager;
|
||||
private MinecraftProvider minecraftProvider;
|
||||
private MappingsProviderImpl mappingsProvider;
|
||||
private NamedMinecraftProvider<?> namedMinecraftProvider;
|
||||
private IntermediaryMinecraftProvider<?> intermediaryMinecraftProvider;
|
||||
private InstallerData installerData;
|
||||
|
||||
// +-------------------+
|
||||
@@ -80,7 +87,6 @@ public class LoomGradleExtensionImpl extends LoomGradleExtensionApiImpl implemen
|
||||
this.project = project;
|
||||
// Initiate with newInstance to allow gradle to decorate our extension
|
||||
this.mixinApExtension = project.getObjects().newInstance(MixinExtensionImpl.class, project);
|
||||
this.mixinMappings = project.getObjects().fileCollection();
|
||||
this.loomFiles = files;
|
||||
this.unmappedMods = project.files();
|
||||
this.forgeExtension = Suppliers.memoize(() -> isForge() ? project.getObjects().newInstance(ForgeExtensionImpl.class, project, this) : null);
|
||||
@@ -97,18 +103,6 @@ public class LoomGradleExtensionImpl extends LoomGradleExtensionApiImpl implemen
|
||||
return loomFiles;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized File getMixinMappings(SourceSet sourceSet) {
|
||||
File mixinMapping = new File(getFiles().getProjectBuildCache(), "mixin-map-" + getMappingsProvider().mappingsIdentifier() + "." + sourceSet.getName() + ".tiny");
|
||||
mixinMappings.from(getProject().files(mixinMapping));
|
||||
return mixinMapping;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileCollection getAllMixinMappings() {
|
||||
return mixinMappings.filter(File::exists);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDependencyManager(LoomDependencyManager dependencyManager) {
|
||||
this.dependencyManager = dependencyManager;
|
||||
@@ -129,6 +123,55 @@ public class LoomGradleExtensionImpl extends LoomGradleExtensionApiImpl implemen
|
||||
return Objects.requireNonNull(jarProcessorManager, "Cannot get JarProcessorManager before it has been setup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public MinecraftProvider getMinecraftProvider() {
|
||||
return Objects.requireNonNull(minecraftProvider, "Cannot get MinecraftProvider before it has been setup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMinecraftProvider(MinecraftProvider minecraftProvider) {
|
||||
this.minecraftProvider = minecraftProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MappingsProviderImpl getMappingsProvider() {
|
||||
return Objects.requireNonNull(mappingsProvider, "Cannot get MappingsProvider before it has been setup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMappingsProvider(MappingsProviderImpl mappingsProvider) {
|
||||
this.mappingsProvider = mappingsProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NamedMinecraftProvider<?> getNamedMinecraftProvider() {
|
||||
return Objects.requireNonNull(namedMinecraftProvider, "Cannot get NamedMinecraftProvider before it has been setup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntermediaryMinecraftProvider<?> getIntermediaryMinecraftProvider() {
|
||||
return Objects.requireNonNull(intermediaryMinecraftProvider, "Cannot get IntermediaryMinecraftProvider before it has been setup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNamedMinecraftProvider(NamedMinecraftProvider<?> namedMinecraftProvider) {
|
||||
this.namedMinecraftProvider = namedMinecraftProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIntermediaryMinecraftProvider(IntermediaryMinecraftProvider<?> intermediaryMinecraftProvider) {
|
||||
this.intermediaryMinecraftProvider = intermediaryMinecraftProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileCollection getMinecraftJarsCollection(MappingsNamespace mappingsNamespace) {
|
||||
return getProject().files(
|
||||
getProject().provider(() ->
|
||||
getProject().files(getMinecraftJars(mappingsNamespace).stream().map(Path::toFile).toList())
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MappingSet getOrCreateSrcMappingCache(int id, Supplier<MappingSet> factory) {
|
||||
if (id < 0 || id >= srcMappingCache.length) return factory.get();
|
||||
|
||||
@@ -43,13 +43,9 @@ import javax.inject.Inject;
|
||||
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.file.ConfigurableFileCollection;
|
||||
import org.gradle.api.file.FileCollection;
|
||||
import org.gradle.api.file.RegularFileProperty;
|
||||
import org.gradle.api.provider.MapProperty;
|
||||
import org.gradle.api.provider.Property;
|
||||
import org.gradle.api.tasks.Input;
|
||||
import org.gradle.api.tasks.InputFile;
|
||||
import org.gradle.api.tasks.InputFiles;
|
||||
import org.gradle.api.tasks.TaskAction;
|
||||
import org.gradle.workers.WorkAction;
|
||||
import org.gradle.workers.WorkParameters;
|
||||
@@ -58,12 +54,11 @@ import org.gradle.workers.WorkerExecutor;
|
||||
import org.gradle.workers.internal.WorkerDaemonClientsManager;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.api.decompilers.DecompilationMetadata;
|
||||
import net.fabricmc.loom.api.decompilers.DecompilerOptions;
|
||||
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;
|
||||
import net.fabricmc.loom.util.FileSystemUtil;
|
||||
@@ -76,22 +71,19 @@ import net.fabricmc.loom.util.ipc.IPCClient;
|
||||
import net.fabricmc.loom.util.ipc.IPCServer;
|
||||
|
||||
public abstract class GenerateSourcesTask extends AbstractLoomTask {
|
||||
public final LoomDecompiler decompiler;
|
||||
private final DecompilerOptions decompilerOptions;
|
||||
|
||||
/**
|
||||
* The jar to decompile, can be the unpick jar.
|
||||
*/
|
||||
@InputFile
|
||||
public abstract RegularFileProperty getInputJar();
|
||||
|
||||
/**
|
||||
* Max memory for forked JVM in megabytes.
|
||||
* The jar used at runtime.
|
||||
*/
|
||||
@Input
|
||||
public abstract Property<Long> getMaxMemory();
|
||||
|
||||
@Input
|
||||
public abstract MapProperty<String, String> getOptions();
|
||||
|
||||
@InputFiles
|
||||
public abstract ConfigurableFileCollection getClasspath();
|
||||
@InputFile
|
||||
public abstract RegularFileProperty getRuntimeJar();
|
||||
|
||||
@Inject
|
||||
public abstract WorkerExecutor getWorkerExecutor();
|
||||
@@ -100,21 +92,10 @@ public abstract class GenerateSourcesTask extends AbstractLoomTask {
|
||||
public abstract WorkerDaemonClientsManager getWorkerDaemonClientsManager();
|
||||
|
||||
@Inject
|
||||
public GenerateSourcesTask(LoomDecompiler decompiler) {
|
||||
this.decompiler = decompiler;
|
||||
|
||||
Objects.requireNonNull(getDecompilerConstructor(this.decompiler.getClass().getCanonicalName()),
|
||||
"%s must have a no args constructor".formatted(this.decompiler.getClass().getCanonicalName()));
|
||||
|
||||
FileCollection decompilerClasspath = decompiler.getBootstrapClasspath(getProject());
|
||||
|
||||
if (decompilerClasspath != null) {
|
||||
getClasspath().from(decompilerClasspath);
|
||||
}
|
||||
public GenerateSourcesTask(DecompilerOptions decompilerOptions) {
|
||||
this.decompilerOptions = decompilerOptions;
|
||||
|
||||
getOutputs().upToDateWhen((o) -> false);
|
||||
getMaxMemory().convention(4096L).finalizeValueOnRead();
|
||||
getOptions().finalizeValueOnRead();
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
@@ -134,9 +115,9 @@ public abstract class GenerateSourcesTask extends AbstractLoomTask {
|
||||
final Path ipcPath = Files.createTempFile("loom", "ipc");
|
||||
Files.deleteIfExists(ipcPath);
|
||||
|
||||
try (ThreadedProgressLoggerConsumer loggerConsumer = new ThreadedProgressLoggerConsumer(getProject(), decompiler.name(), "Decompiling minecraft sources");
|
||||
try (ThreadedProgressLoggerConsumer loggerConsumer = new ThreadedProgressLoggerConsumer(getProject(), decompilerOptions.getName(), "Decompiling minecraft sources");
|
||||
IPCServer logReceiver = new IPCServer(ipcPath, loggerConsumer)) {
|
||||
doWork(ipcPath);
|
||||
doWork(logReceiver);
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException("Failed to shutdown log receiver", e);
|
||||
} finally {
|
||||
@@ -144,24 +125,22 @@ public abstract class GenerateSourcesTask extends AbstractLoomTask {
|
||||
}
|
||||
}
|
||||
|
||||
private void doWork(@Nullable Path ipcPath) {
|
||||
private void doWork(@Nullable IPCServer ipcServer) {
|
||||
final String jvmMarkerValue = UUID.randomUUID().toString();
|
||||
final WorkQueue workQueue = createWorkQueue(jvmMarkerValue);
|
||||
|
||||
workQueue.submit(DecompileAction.class, params -> {
|
||||
params.getDecompilerClass().set(decompiler.getClass().getCanonicalName());
|
||||
|
||||
params.getOptions().set(getOptions());
|
||||
params.getDecompilerOptions().set(decompilerOptions.toDto());
|
||||
|
||||
params.getInputJar().set(getInputJar());
|
||||
params.getRuntimeJar().set(getExtension().getMappingsProvider().mappedProvider.getMappedJar());
|
||||
params.getRuntimeJar().set(getRuntimeJar());
|
||||
params.getSourcesDestinationJar().set(getMappedJarFileWithSuffix("-sources.jar"));
|
||||
params.getLinemap().set(getMappedJarFileWithSuffix("-sources.lmap"));
|
||||
params.getLinemapJar().set(getMappedJarFileWithSuffix("-linemapped.jar"));
|
||||
params.getMappings().set(getMappings(getProject(), getExtension()).toFile());
|
||||
|
||||
if (ipcPath != null) {
|
||||
params.getIPCPath().set(ipcPath.toFile());
|
||||
if (ipcServer != null) {
|
||||
params.getIPCPath().set(ipcServer.getPath().toFile());
|
||||
}
|
||||
|
||||
params.getClassPath().setFrom(getProject().getConfigurations().getByName(Constants.Configurations.MINECRAFT_DEPENDENCIES));
|
||||
@@ -170,10 +149,10 @@ public abstract class GenerateSourcesTask extends AbstractLoomTask {
|
||||
try {
|
||||
workQueue.await();
|
||||
} finally {
|
||||
if (useProcessIsolation()) {
|
||||
if (ipcServer != null) {
|
||||
boolean stopped = WorkerDaemonClientsManagerHelper.stopIdleJVM(getWorkerDaemonClientsManager(), jvmMarkerValue);
|
||||
|
||||
if (!stopped) {
|
||||
if (!stopped && ipcServer.hasReceivedMessage()) {
|
||||
throw new RuntimeException("Failed to stop decompile worker JVM");
|
||||
}
|
||||
}
|
||||
@@ -187,9 +166,9 @@ public abstract class GenerateSourcesTask extends AbstractLoomTask {
|
||||
|
||||
return getWorkerExecutor().processIsolation(spec -> {
|
||||
spec.forkOptions(forkOptions -> {
|
||||
forkOptions.setMaxHeapSize("%dm".formatted(getMaxMemory().get()));
|
||||
forkOptions.setMaxHeapSize("%dm".formatted(decompilerOptions.getMemory().get()));
|
||||
forkOptions.systemProperty(WorkerDaemonClientsManagerHelper.MARKER_PROP, jvmMarkerValue);
|
||||
forkOptions.bootstrapClasspath(getClasspath());
|
||||
forkOptions.bootstrapClasspath(decompilerOptions.getClasspath());
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -200,9 +179,7 @@ public abstract class GenerateSourcesTask extends AbstractLoomTask {
|
||||
}
|
||||
|
||||
public interface DecompileParams extends WorkParameters {
|
||||
Property<String> getDecompilerClass();
|
||||
|
||||
MapProperty<String, String> getOptions();
|
||||
Property<DecompilerOptions.Dto> getDecompilerOptions();
|
||||
|
||||
RegularFileProperty getInputJar();
|
||||
RegularFileProperty getRuntimeJar();
|
||||
@@ -241,20 +218,26 @@ public abstract class GenerateSourcesTask extends AbstractLoomTask {
|
||||
final Path linemapJar = getParameters().getLinemapJar().get().getAsFile().toPath();
|
||||
final Path runtimeJar = getParameters().getRuntimeJar().get().getAsFile().toPath();
|
||||
|
||||
final DecompilerOptions.Dto decompilerOptions = getParameters().getDecompilerOptions().get();
|
||||
|
||||
final LoomDecompiler decompiler;
|
||||
|
||||
try {
|
||||
decompiler = getDecompilerConstructor(getParameters().getDecompilerClass().get()).newInstance();
|
||||
final String className = decompilerOptions.className();
|
||||
final Constructor<LoomDecompiler> decompilerConstructor = getDecompilerConstructor(className);
|
||||
Objects.requireNonNull(decompilerConstructor, "%s must have a no args constructor".formatted(className));
|
||||
|
||||
decompiler = decompilerConstructor.newInstance();
|
||||
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
|
||||
throw new RuntimeException("Failed to create decompiler", e);
|
||||
}
|
||||
|
||||
DecompilationMetadata metadata = new DecompilationMetadata(
|
||||
Runtime.getRuntime().availableProcessors(),
|
||||
decompilerOptions.maxThreads(),
|
||||
getParameters().getMappings().get().getAsFile().toPath(),
|
||||
getLibraries(),
|
||||
logger,
|
||||
getParameters().getOptions().get()
|
||||
decompilerOptions.options()
|
||||
);
|
||||
|
||||
decompiler.decompile(
|
||||
@@ -304,18 +287,7 @@ public abstract class GenerateSourcesTask extends AbstractLoomTask {
|
||||
}
|
||||
|
||||
private File getMappedJarFileWithSuffix(String suffix) {
|
||||
return getMappedJarFileWithSuffix(getProject(), suffix);
|
||||
}
|
||||
|
||||
public static File getMappedJarFileWithSuffix(Project project, String suffix) {
|
||||
return getMappedJarFileWithSuffix(project, suffix, false);
|
||||
}
|
||||
|
||||
public static File getMappedJarFileWithSuffix(Project project, String suffix, boolean forgeJar) {
|
||||
LoomGradleExtension extension = LoomGradleExtension.get(project);
|
||||
MappingsProviderImpl mappingsProvider = extension.getMappingsProvider();
|
||||
File mappedJar = forgeJar ? mappingsProvider.mappedProvider.getForgeMappedJar() : mappingsProvider.mappedProvider.getMappedJar();
|
||||
String path = mappedJar.getAbsolutePath();
|
||||
String path = getRuntimeJar().get().getAsFile().getAbsolutePath();
|
||||
|
||||
if (!path.toLowerCase(Locale.ROOT).endsWith(".jar")) {
|
||||
throw new RuntimeException("Invalid mapped JAR path: " + path);
|
||||
|
||||
@@ -26,11 +26,17 @@ package net.fabricmc.loom.task;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.Task;
|
||||
import org.gradle.api.provider.Provider;
|
||||
import org.gradle.api.tasks.TaskContainer;
|
||||
import org.gradle.api.tasks.TaskProvider;
|
||||
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.configuration.ide.RunConfigSettings;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftJarConfiguration;
|
||||
import net.fabricmc.loom.task.launch.GenerateDLIConfigTask;
|
||||
import net.fabricmc.loom.task.launch.GenerateLog4jConfigTask;
|
||||
import net.fabricmc.loom.task.launch.GenerateRemapClasspathTask;
|
||||
import net.fabricmc.loom.util.Constants;
|
||||
|
||||
public final class LoomTasks {
|
||||
@@ -47,11 +53,39 @@ public final class LoomTasks {
|
||||
|
||||
RemapTaskConfiguration.setupRemap(project);
|
||||
|
||||
TaskProvider<ExtractNativesTask> extractNatives = tasks.register("extractNatives", ExtractNativesTask.class);
|
||||
tasks.register("extractNatives", ExtractNativesTask.class, t -> {
|
||||
t.setDescription("Extracts the minecraft platform specific natives.");
|
||||
});
|
||||
tasks.register("downloadAssets", DownloadAssetsTask.class, t -> {
|
||||
t.dependsOn(extractNatives);
|
||||
t.setDescription("Downloads required assets for Fabric.");
|
||||
});
|
||||
tasks.register("generateDLIConfig", GenerateDLIConfigTask.class, t -> {
|
||||
t.setDescription("Generate the DevLaunchInjector config file");
|
||||
});
|
||||
tasks.register("generateLog4jConfig", GenerateLog4jConfigTask.class, t -> {
|
||||
t.setDescription("Generate the log4j config file");
|
||||
});
|
||||
tasks.register("generateRemapClasspath", GenerateRemapClasspathTask.class, t -> {
|
||||
t.setDescription("Generate the remap classpath file");
|
||||
});
|
||||
|
||||
tasks.register("configureLaunch", task -> {
|
||||
task.dependsOn(tasks.named("generateDLIConfig"));
|
||||
task.dependsOn(tasks.named("generateLog4jConfig"));
|
||||
task.dependsOn(tasks.named("generateRemapClasspath"));
|
||||
|
||||
task.setDescription("Setup the required files to launch Minecraft");
|
||||
task.setGroup(Constants.TaskGroup.FABRIC);
|
||||
});
|
||||
|
||||
tasks.register("configureClientLaunch", task -> {
|
||||
task.dependsOn(tasks.named("extractNatives"));
|
||||
task.dependsOn(tasks.named("downloadAssets"));
|
||||
task.dependsOn(tasks.named("configureLaunch"));
|
||||
|
||||
task.setDescription("Setup the required files to launch the Minecraft client");
|
||||
task.setGroup(Constants.TaskGroup.FABRIC);
|
||||
});
|
||||
|
||||
TaskProvider<ValidateAccessWidenerTask> validateAccessWidener = tasks.register("validateAccessWidener", ValidateAccessWidenerTask.class, t -> {
|
||||
t.setDescription("Validate all the rules in the access widener against the Minecraft jar");
|
||||
@@ -62,20 +96,18 @@ public final class LoomTasks {
|
||||
|
||||
registerIDETasks(tasks);
|
||||
registerRunTasks(tasks, project);
|
||||
registerLaunchSettings(project);
|
||||
registerDecompileTasks(tasks, project);
|
||||
}
|
||||
|
||||
private static void registerIDETasks(TaskContainer tasks) {
|
||||
tasks.register("genIdeaWorkspace", GenIdeaProjectTask.class, t -> {
|
||||
t.setDescription("Generates an IntelliJ IDEA workspace from this project.");
|
||||
t.dependsOn("idea", "downloadAssets");
|
||||
t.dependsOn("idea", getIDELaunchConfigureTaskName(t.getProject()));
|
||||
t.setGroup(Constants.TaskGroup.IDE);
|
||||
});
|
||||
|
||||
tasks.register("genEclipseRuns", GenEclipseRunsTask.class, t -> {
|
||||
t.setDescription("Generates Eclipse run configurations for this project.");
|
||||
t.dependsOn("downloadAssets");
|
||||
t.dependsOn(getIDELaunchConfigureTaskName(t.getProject()));
|
||||
t.setGroup(Constants.TaskGroup.IDE);
|
||||
});
|
||||
|
||||
@@ -86,7 +118,7 @@ public final class LoomTasks {
|
||||
|
||||
tasks.register("vscode", GenVsCodeProjectTask.class, t -> {
|
||||
t.setDescription("Generates VSCode launch configurations.");
|
||||
t.dependsOn("downloadAssets");
|
||||
t.dependsOn(getIDELaunchConfigureTaskName(t.getProject()));
|
||||
t.setGroup(Constants.TaskGroup.IDE);
|
||||
});
|
||||
}
|
||||
@@ -103,52 +135,25 @@ public final class LoomTasks {
|
||||
tasks.register(taskName, RunGameTask.class, config).configure(t -> {
|
||||
t.setDescription("Starts the '" + config.getConfigName() + "' run configuration");
|
||||
|
||||
if (config.getEnvironment().equals("client")) {
|
||||
t.dependsOn("downloadAssets");
|
||||
}
|
||||
t.dependsOn(config.getEnvironment().equals("client") ? "configureClientLaunch" : "configureLaunch");
|
||||
});
|
||||
});
|
||||
|
||||
extension.getRunConfigs().create("client", RunConfigSettings::client);
|
||||
extension.getRunConfigs().create("server", RunConfigSettings::server);
|
||||
|
||||
// Remove the client run config when server only. Done by name to not remove any possible custom run configs
|
||||
project.afterEvaluate(p -> {
|
||||
if (extension.getMinecraftJarConfiguration().get() == MinecraftJarConfiguration.SERVER_ONLY) {
|
||||
extension.getRunConfigs().removeIf(settings -> settings.getName().equals("client"));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void registerLaunchSettings(Project project) {
|
||||
LoomGradleExtension extension = LoomGradleExtension.get(project);
|
||||
Preconditions.checkArgument(extension.getLaunchConfigs().size() == 0, "Launch configurations must not be registered before loom");
|
||||
extension.getLaunchConfigs().create("client");
|
||||
extension.getLaunchConfigs().create("server");
|
||||
|
||||
if (extension.isForge()) {
|
||||
extension.getLaunchConfigs().create("data");
|
||||
}
|
||||
}
|
||||
|
||||
private static void registerDecompileTasks(TaskContainer tasks, Project project) {
|
||||
LoomGradleExtension.get(project).getGameDecompilers().configureEach(decompiler -> {
|
||||
String taskName = "genSourcesWith" + decompiler.name();
|
||||
// Decompiler will be passed to the constructor of GenerateSourcesTask
|
||||
tasks.register(taskName, GenerateSourcesTask.class, decompiler).configure(task -> {
|
||||
task.setDescription("Decompile minecraft using %s.".formatted(decompiler.name()));
|
||||
task.setGroup(Constants.TaskGroup.FABRIC);
|
||||
task.dependsOn(tasks.named("validateAccessWidener"));
|
||||
});
|
||||
});
|
||||
|
||||
LoomGradleExtension.get(project).getArchGameDecompilers().configureEach(decompiler -> {
|
||||
String taskName = "genSourcesWith" + decompiler.name();
|
||||
// Decompiler will be passed to the constructor of ArchitecturyGenerateSourcesTask
|
||||
tasks.register(taskName, ArchitecturyGenerateSourcesTask.class, decompiler).configure(task -> {
|
||||
task.setDescription("Decompile minecraft using %s.".formatted(decompiler.name()));
|
||||
task.setGroup(Constants.TaskGroup.FABRIC);
|
||||
});
|
||||
});
|
||||
|
||||
tasks.register("genSources", task -> {
|
||||
task.setDescription("Decompile minecraft using the default decompiler.");
|
||||
task.setGroup(Constants.TaskGroup.FABRIC);
|
||||
|
||||
task.dependsOn(project.getTasks().named("genSourcesWithCfr"));
|
||||
public static Provider<Task> getIDELaunchConfigureTaskName(Project project) {
|
||||
return project.provider(() -> {
|
||||
final MinecraftJarConfiguration jarConfiguration = LoomGradleExtension.get(project).getMinecraftJarConfiguration().get();
|
||||
final String name = jarConfiguration == MinecraftJarConfiguration.SERVER_ONLY ? "configureLaunch" : "configureClientLaunch";
|
||||
return project.getTasks().getByName(name);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,7 +51,6 @@ 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.util.SourceRemapper;
|
||||
import net.fabricmc.lorenztiny.TinyMappingsJoiner;
|
||||
import net.fabricmc.mappingio.MappingReader;
|
||||
@@ -101,7 +100,7 @@ public class MigrateMappingsTask extends AbstractLoomTask {
|
||||
try {
|
||||
MemoryMappingTree currentMappings = mappingsProvider.getMappings();
|
||||
MemoryMappingTree targetMappings = getMappings(mappings);
|
||||
migrateMappings(project, extension, extension.getMinecraftMappedProvider(), inputDir, outputDir, currentMappings, targetMappings);
|
||||
migrateMappings(project, extension, extension, inputDir, outputDir, currentMappings, targetMappings);
|
||||
project.getLogger().lifecycle(":remapped project written to " + outputDir.toAbsolutePath());
|
||||
} catch (IOException e) {
|
||||
throw new IllegalArgumentException("Error while loading mappings", e);
|
||||
@@ -157,8 +156,8 @@ public class MigrateMappingsTask extends AbstractLoomTask {
|
||||
return mappingTree;
|
||||
}
|
||||
|
||||
private static void migrateMappings(Project project, LoomGradleExtension extension, MinecraftMappedProvider minecraftMappedProvider,
|
||||
Path inputDir, Path outputDir, MemoryMappingTree currentMappings, MemoryMappingTree targetMappings
|
||||
private static void migrateMappings(Project project, LoomGradleExtension extension,
|
||||
Path inputDir, Path outputDir, MemoryMappingTree currentMappings, MemoryMappingTree targetMappings
|
||||
) throws IOException {
|
||||
project.getLogger().info(":joining mappings");
|
||||
|
||||
@@ -174,8 +173,13 @@ public class MigrateMappingsTask extends AbstractLoomTask {
|
||||
final JavaVersion javaVersion = project.getExtensions().getByType(JavaPluginExtension.class).getSourceCompatibility();
|
||||
mercury.setSourceCompatibility(javaVersion.toString());
|
||||
|
||||
mercury.getClassPath().add(minecraftMappedProvider.getMappedJar().toPath());
|
||||
mercury.getClassPath().add(minecraftMappedProvider.getIntermediaryJar().toPath());
|
||||
for (Path intermediaryJar : extension.getMinecraftJars(MappingsNamespace.INTERMEDIARY)) {
|
||||
mercury.getClassPath().add(intermediaryJar);
|
||||
}
|
||||
|
||||
for (Path intermediaryJar : extension.getMinecraftJars(MappingsNamespace.NAMED)) {
|
||||
mercury.getClassPath().add(intermediaryJar);
|
||||
}
|
||||
|
||||
if (extension.isForge()) {
|
||||
mercury.getClassPath().add(minecraftMappedProvider.getSrgJar().toPath());
|
||||
|
||||
106
src/main/java/net/fabricmc/loom/task/PrepareJarRemapTask.java
Normal file
106
src/main/java/net/fabricmc/loom/task/PrepareJarRemapTask.java
Normal file
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2022 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.nio.file.Path;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import org.gradle.api.file.RegularFileProperty;
|
||||
import org.gradle.api.provider.Property;
|
||||
import org.gradle.api.tasks.InputFile;
|
||||
import org.gradle.api.tasks.TaskAction;
|
||||
import org.gradle.workers.WorkAction;
|
||||
import org.gradle.workers.WorkParameters;
|
||||
import org.gradle.workers.WorkQueue;
|
||||
import org.gradle.workers.WorkerExecutor;
|
||||
|
||||
import net.fabricmc.loom.task.service.TinyRemapperService;
|
||||
import net.fabricmc.loom.util.service.UnsafeWorkQueueHelper;
|
||||
import net.fabricmc.tinyremapper.TinyRemapper;
|
||||
|
||||
/**
|
||||
* The prepare remap task runs before all other jar remap tasks, should be used to setup tiny remapper.
|
||||
*/
|
||||
public abstract class PrepareJarRemapTask extends AbstractLoomTask {
|
||||
private final RemapJarTask remapJarTask;
|
||||
@InputFile
|
||||
public abstract RegularFileProperty getInputFile();
|
||||
|
||||
@Inject
|
||||
public PrepareJarRemapTask(RemapJarTask remapJarTask) {
|
||||
this.remapJarTask = remapJarTask;
|
||||
|
||||
getInputFile().set(remapJarTask.getInputFile());
|
||||
// TODO can this be up-to-date when the main task is up-to date?
|
||||
getOutputs().upToDateWhen((o) -> false);
|
||||
|
||||
getProject().getGradle().allprojects(project -> {
|
||||
project.getTasks().configureEach(task -> {
|
||||
if (task instanceof PrepareJarRemapTask otherTask) {
|
||||
if (otherTask == this) return;
|
||||
|
||||
// Ensure that all other prepare tasks inputs have completed
|
||||
dependsOn(otherTask.getInputs());
|
||||
mustRunAfter(otherTask.getInputs());
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@Inject
|
||||
protected abstract WorkerExecutor getWorkerExecutor();
|
||||
|
||||
@TaskAction
|
||||
public void run() {
|
||||
final WorkQueue workQueue = getWorkerExecutor().noIsolation();
|
||||
|
||||
workQueue.submit(ReadInputsAction.class, params -> {
|
||||
params.getTinyRemapperBuildServiceUuid().set(UnsafeWorkQueueHelper.create(getProject(), remapJarTask.getTinyRemapperService()));
|
||||
params.getInputFile().set(getInputFile());
|
||||
});
|
||||
}
|
||||
|
||||
public interface ReadInputsParams extends WorkParameters {
|
||||
Property<String> getTinyRemapperBuildServiceUuid();
|
||||
RegularFileProperty getInputFile();
|
||||
}
|
||||
|
||||
public abstract static class ReadInputsAction implements WorkAction<ReadInputsParams> {
|
||||
private final TinyRemapperService tinyRemapperService;
|
||||
|
||||
public ReadInputsAction() {
|
||||
this.tinyRemapperService = UnsafeWorkQueueHelper.get(getParameters().getTinyRemapperBuildServiceUuid(), TinyRemapperService.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
final TinyRemapper tinyRemapper = tinyRemapperService.getTinyRemapperForInputs();
|
||||
final Path inputFile = getParameters().getInputFile().getAsFile().get().toPath();
|
||||
|
||||
tinyRemapper.readInputsAsync(tinyRemapperService.getOrCreateTag(inputFile), inputFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,7 +27,6 @@ package net.fabricmc.loom.task;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.io.Writer;
|
||||
@@ -41,6 +40,7 @@ import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.Set;
|
||||
import java.util.jar.Manifest;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -48,6 +48,7 @@ import java.util.stream.Collectors;
|
||||
import javax.inject.Inject;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.base.Suppliers;
|
||||
import com.google.gson.JsonObject;
|
||||
import dev.architectury.tinyremapper.InputTag;
|
||||
import dev.architectury.tinyremapper.OutputConsumerPath;
|
||||
@@ -66,9 +67,9 @@ import org.gradle.api.provider.Provider;
|
||||
import org.gradle.api.provider.SetProperty;
|
||||
import org.gradle.api.tasks.Input;
|
||||
import org.gradle.api.tasks.InputFiles;
|
||||
import org.gradle.api.tasks.Internal;
|
||||
import org.gradle.api.tasks.SourceSet;
|
||||
import org.gradle.api.tasks.TaskAction;
|
||||
import org.objectweb.asm.commons.Remapper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -76,20 +77,22 @@ import net.fabricmc.accesswidener.AccessWidenerReader;
|
||||
import net.fabricmc.accesswidener.AccessWidenerRemapper;
|
||||
import net.fabricmc.accesswidener.AccessWidenerWriter;
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
|
||||
import net.fabricmc.loom.build.MixinRefmapHelper;
|
||||
import net.fabricmc.loom.build.nesting.IncludedJarFactory;
|
||||
import net.fabricmc.loom.build.nesting.JarNester;
|
||||
import net.fabricmc.loom.configuration.accesswidener.AccessWidenerFile;
|
||||
import net.fabricmc.loom.extension.MixinExtension;
|
||||
import net.fabricmc.loom.task.service.JarManifestService;
|
||||
import net.fabricmc.loom.task.service.MappingsService;
|
||||
import net.fabricmc.loom.task.service.TinyRemapperService;
|
||||
import net.fabricmc.loom.util.Constants;
|
||||
import net.fabricmc.loom.util.FileSystemUtil;
|
||||
import net.fabricmc.loom.util.LfWriter;
|
||||
import net.fabricmc.loom.util.ZipUtils;
|
||||
import net.fabricmc.loom.util.aw2at.Aw2At;
|
||||
import net.fabricmc.lorenztiny.TinyMappingsReader;
|
||||
import net.fabricmc.loom.util.service.UnsafeWorkQueueHelper;
|
||||
import net.fabricmc.tinyremapper.OutputConsumerPath;
|
||||
import net.fabricmc.tinyremapper.TinyRemapper;
|
||||
|
||||
public abstract class RemapJarTask extends AbstractRemapJarTask {
|
||||
private static final String MANIFEST_PATH = "META-INF/MANIFEST.MF";
|
||||
@@ -111,6 +114,8 @@ public abstract class RemapJarTask extends AbstractRemapJarTask {
|
||||
@Input
|
||||
public abstract SetProperty<String> getAtAccessWideners();
|
||||
|
||||
private Supplier<TinyRemapperService> tinyRemapperService = Suppliers.memoize(() -> TinyRemapperService.getOrCreate(this));
|
||||
|
||||
@Inject
|
||||
public RemapJarTask() {
|
||||
super();
|
||||
@@ -120,6 +125,25 @@ public abstract class RemapJarTask extends AbstractRemapJarTask {
|
||||
|
||||
Configuration includeConfiguration = getProject().getConfigurations().getByName(Constants.Configurations.INCLUDE);
|
||||
getNestedJars().from(new IncludedJarFactory(getProject()).getNestedJars(includeConfiguration));
|
||||
|
||||
setupPreparationTask();
|
||||
}
|
||||
|
||||
private void setupPreparationTask() {
|
||||
PrepareJarRemapTask prepareJarTask = getProject().getTasks().create("prepare" + getName().substring(0, 1).toUpperCase() + getName().substring(1), PrepareJarRemapTask.class, this);
|
||||
|
||||
dependsOn(prepareJarTask);
|
||||
mustRunAfter(prepareJarTask);
|
||||
|
||||
getProject().getGradle().allprojects(project -> {
|
||||
project.getTasks().configureEach(task -> {
|
||||
if (task instanceof PrepareJarRemapTask otherTask) {
|
||||
// Ensure that all remap jars run after all prepare tasks
|
||||
dependsOn(otherTask);
|
||||
mustRunAfter(otherTask);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
@@ -132,14 +156,13 @@ public abstract class RemapJarTask extends AbstractRemapJarTask {
|
||||
}
|
||||
|
||||
params.getJarManifestService().set(JarManifestService.get(getProject()));
|
||||
params.getTinyRemapperBuildServiceUuid().set(UnsafeWorkQueueHelper.create(getProject(), tinyRemapperService.get()));
|
||||
params.getRemapClasspath().from(getClasspath());
|
||||
params.getMappings().add(MappingsService.createDefault(getProject(), getSourceNamespace().get(), getTargetNamespace().get()));
|
||||
|
||||
final boolean legacyMixin = extension.getMixin().getUseLegacyMixinAp().get();
|
||||
params.getUseMixinExtension().set(!legacyMixin);
|
||||
|
||||
if (legacyMixin) {
|
||||
params.getMixinMappings().from(extension.getAllMixinMappings());
|
||||
setupLegacyMixinRefmapRemapping(params);
|
||||
} else if (extension.isForge()) {
|
||||
throw new RuntimeException("Forge must have useLegacyMixinAp enabled");
|
||||
@@ -209,9 +232,6 @@ public abstract class RemapJarTask extends AbstractRemapJarTask {
|
||||
public interface RemapParams extends AbstractRemapParams {
|
||||
ConfigurableFileCollection getNestedJars();
|
||||
ConfigurableFileCollection getRemapClasspath();
|
||||
ConfigurableFileCollection getMixinMappings();
|
||||
|
||||
ListProperty<Provider<MappingsService>> getMappings();
|
||||
|
||||
Property<Boolean> getForge();
|
||||
|
||||
@@ -223,19 +243,25 @@ public abstract class RemapJarTask extends AbstractRemapJarTask {
|
||||
ListProperty<RefmapData> getMixinData();
|
||||
|
||||
Property<JarManifestService> getJarManifestService();
|
||||
Property<String> getTinyRemapperBuildServiceUuid();
|
||||
}
|
||||
|
||||
public abstract static class RemapAction extends AbstractRemapAction<RemapParams> {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(RemapAction.class);
|
||||
|
||||
private final TinyRemapperService tinyRemapperService;
|
||||
private TinyRemapper tinyRemapper;
|
||||
|
||||
public RemapAction() {
|
||||
this.tinyRemapperService = UnsafeWorkQueueHelper.get(getParameters().getTinyRemapperBuildServiceUuid(), TinyRemapperService.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
try {
|
||||
LOGGER.info("Remapping {} to {}", inputFile, outputFile);
|
||||
|
||||
tinyRemapper = createTinyRemapper();
|
||||
tinyRemapper = tinyRemapperService.getTinyRemapperForRemapping();
|
||||
|
||||
remap();
|
||||
remapAccessWidener();
|
||||
@@ -248,9 +274,6 @@ public abstract class RemapJarTask extends AbstractRemapJarTask {
|
||||
|
||||
rewriteJar();
|
||||
|
||||
tinyRemapper.finish();
|
||||
tinyRemapper = null;
|
||||
|
||||
LOGGER.debug("Finished remapping {}", inputFile);
|
||||
} catch (Exception e) {
|
||||
try {
|
||||
@@ -264,13 +287,9 @@ public abstract class RemapJarTask extends AbstractRemapJarTask {
|
||||
}
|
||||
|
||||
private void remap() throws IOException {
|
||||
final InputTag inputTag = tinyRemapper.createInputTag();
|
||||
|
||||
tinyRemapper.readInputsAsync(inputTag, inputFile);
|
||||
|
||||
try (OutputConsumerPath outputConsumer = new OutputConsumerPath.Builder(outputFile).build()) {
|
||||
outputConsumer.addNonClassFiles(inputFile);
|
||||
tinyRemapper.apply(outputConsumer, inputTag);
|
||||
tinyRemapper.apply(outputConsumer, tinyRemapperService.getOrCreateTag(inputFile));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -281,7 +300,7 @@ public abstract class RemapJarTask extends AbstractRemapJarTask {
|
||||
return;
|
||||
}
|
||||
|
||||
byte[] remapped = remapAccessWidener(accessWidenerFile.content(), tinyRemapper.getEnvironment().getRemapper(), MappingsNamespace.INTERMEDIARY.toString());
|
||||
byte[] remapped = remapAccessWidener(accessWidenerFile.content());
|
||||
|
||||
// Finally, replace the output with the remaped aw
|
||||
ZipUtils.replace(outputFile, accessWidenerFile.path(), remapped);
|
||||
@@ -343,15 +362,15 @@ public abstract class RemapJarTask extends AbstractRemapJarTask {
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] remapAccessWidener(byte[] input, Remapper asmRemapper, String targetNamespace) {
|
||||
private byte[] remapAccessWidener(byte[] input) {
|
||||
int version = AccessWidenerReader.readVersion(input);
|
||||
|
||||
AccessWidenerWriter writer = new AccessWidenerWriter(version);
|
||||
AccessWidenerRemapper remapper = new AccessWidenerRemapper(
|
||||
writer,
|
||||
asmRemapper,
|
||||
MappingsNamespace.NAMED.toString(),
|
||||
targetNamespace
|
||||
tinyRemapper.getEnvironment().getRemapper(),
|
||||
getParameters().getSourceNamespace().get(),
|
||||
getParameters().getTargetNamespace().get()
|
||||
);
|
||||
AccessWidenerReader reader = new AccessWidenerReader(remapper);
|
||||
reader.read(input);
|
||||
@@ -400,30 +419,10 @@ public abstract class RemapJarTask extends AbstractRemapJarTask {
|
||||
})));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private TinyRemapper createTinyRemapper() {
|
||||
TinyRemapper.Builder builder = TinyRemapper.newRemapper();
|
||||
|
||||
for (Provider<MappingsService> provider : getParameters().getMappings().get()) {
|
||||
builder.withMappings(provider.get().getMappingsProvider());
|
||||
}
|
||||
|
||||
for (File mixinMapping : getParameters().getMixinMappings()) {
|
||||
builder.withMappings(TinyUtils.createTinyMappingProvider(mixinMapping.toPath(), getParameters().getSourceNamespace().get(), getParameters().getTargetNamespace().get()));
|
||||
}
|
||||
|
||||
if (getParameters().getUseMixinExtension().get()) {
|
||||
builder.extension(new dev.architectury.tinyremapper.extension.mixin.MixinExtension());
|
||||
}
|
||||
|
||||
TinyRemapper remapper = builder.build();
|
||||
|
||||
// Apply classpath
|
||||
for (File file : getParameters().getRemapClasspath()) {
|
||||
remapper.readClassPathAsync(file.toPath());
|
||||
}
|
||||
|
||||
return remapper;
|
||||
}
|
||||
@Internal
|
||||
public TinyRemapperService getTinyRemapperService() {
|
||||
return tinyRemapperService.get();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,8 +35,8 @@ import org.gradle.api.tasks.TaskAction;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import net.fabricmc.loom.task.service.MappingsService;
|
||||
import net.fabricmc.loom.task.service.SourceRemapperService;
|
||||
import net.fabricmc.loom.util.service.UnsafeWorkQueueHelper;
|
||||
|
||||
public abstract class RemapSourcesJarTask extends AbstractRemapJarTask {
|
||||
@Inject
|
||||
@@ -49,12 +49,12 @@ public abstract class RemapSourcesJarTask extends AbstractRemapJarTask {
|
||||
@TaskAction
|
||||
public void run() {
|
||||
submitWork(RemapSourcesAction.class, params -> {
|
||||
params.getSourcesRemapperService().set(SourceRemapperService.create(getProject(), MappingsService.createDefault(getProject(), getSourceNamespace().get(), getTargetNamespace().get()), getClasspath()));
|
||||
params.getSourcesRemapperServiceUuid().set(UnsafeWorkQueueHelper.create(getProject(), SourceRemapperService.create(this)));
|
||||
});
|
||||
}
|
||||
|
||||
public interface RemapSourcesParams extends AbstractRemapParams {
|
||||
Property<SourceRemapperService> getSourcesRemapperService();
|
||||
Property<String> getSourcesRemapperServiceUuid();
|
||||
}
|
||||
|
||||
public abstract static class RemapSourcesAction extends AbstractRemapAction<RemapSourcesParams> {
|
||||
@@ -65,7 +65,7 @@ public abstract class RemapSourcesJarTask extends AbstractRemapJarTask {
|
||||
public RemapSourcesAction() {
|
||||
super();
|
||||
|
||||
sourceRemapperService = getParameters().getSourcesRemapperService().get();
|
||||
sourceRemapperService = UnsafeWorkQueueHelper.get(getParameters().getSourcesRemapperServiceUuid(), SourceRemapperService.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -54,8 +54,8 @@ public class RemapTaskConfiguration {
|
||||
return;
|
||||
}
|
||||
|
||||
// Register the default remap jar task
|
||||
TaskProvider<RemapJarTask> remapJarTaskProvider = tasks.register(REMAP_JAR_TASK_NAME, RemapJarTask.class, task -> {
|
||||
// Register the default remap jar task - must not be lazy to ensure that the prepare tasks get setup for other projects to depend on.
|
||||
RemapJarTask remapJarTask = tasks.create(REMAP_JAR_TASK_NAME, RemapJarTask.class, task -> {
|
||||
final AbstractArchiveTask jarTask = tasks.named(JavaPlugin.JAR_TASK_NAME, AbstractArchiveTask.class).get();
|
||||
|
||||
// Basic task setup
|
||||
@@ -76,7 +76,7 @@ public class RemapTaskConfiguration {
|
||||
task.getDestinationDirectory().set(new File(project.getBuildDir(), "devlibs"));
|
||||
});
|
||||
|
||||
tasks.named(BasePlugin.ASSEMBLE_TASK_NAME).configure(task -> task.dependsOn(remapJarTaskProvider));
|
||||
tasks.named(BasePlugin.ASSEMBLE_TASK_NAME).configure(task -> task.dependsOn(remapJarTask));
|
||||
|
||||
trySetupSourceRemapping(project);
|
||||
|
||||
@@ -84,8 +84,8 @@ public class RemapTaskConfiguration {
|
||||
// Remove -dev jars from the default jar task
|
||||
for (String configurationName : new String[] { JavaPlugin.API_ELEMENTS_CONFIGURATION_NAME, JavaPlugin.RUNTIME_ELEMENTS_CONFIGURATION_NAME }) {
|
||||
Configuration configuration = project.getConfigurations().getByName(configurationName);
|
||||
final Task jarTask = project.getTasks().getByName(JavaPlugin.JAR_TASK_NAME);
|
||||
configuration.getArtifacts().removeIf(artifact -> {
|
||||
Task jarTask = project.getTasks().getByName(JavaPlugin.JAR_TASK_NAME);
|
||||
// if the artifact is a -dev jar and "builtBy jar"
|
||||
return "dev".equals(artifact.getClassifier()) && artifact.getBuildDependencies().getDependencies(null).contains(jarTask);
|
||||
});
|
||||
|
||||
@@ -28,6 +28,7 @@ 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;
|
||||
|
||||
@@ -40,7 +41,7 @@ import org.gradle.api.tasks.JavaExec;
|
||||
import org.gradle.api.tasks.OutputFile;
|
||||
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.configuration.providers.LaunchProvider;
|
||||
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
|
||||
import net.fabricmc.loom.extension.LoomFiles;
|
||||
import net.fabricmc.loom.util.Constants;
|
||||
|
||||
@@ -76,7 +77,9 @@ public abstract class UnpickJarTask extends JavaExec {
|
||||
fileArg(getConstantJar().getSingleFile());
|
||||
|
||||
// Classpath
|
||||
fileArg(getExtension().getMinecraftMappedProvider().getMappedJar());
|
||||
for (Path minecraftJar : getExtension().getMinecraftJars(MappingsNamespace.NAMED)) {
|
||||
fileArg(minecraftJar.toFile());
|
||||
}
|
||||
|
||||
for (File file : getUnpickClasspath()) {
|
||||
fileArg(file);
|
||||
@@ -89,7 +92,7 @@ public abstract class UnpickJarTask extends JavaExec {
|
||||
}
|
||||
|
||||
private void writeUnpickLogConfig() {
|
||||
try (InputStream is = LaunchProvider.class.getClassLoader().getResourceAsStream("unpick-logging.properties")) {
|
||||
try (InputStream is = UnpickJarTask.class.getClassLoader().getResourceAsStream("unpick-logging.properties")) {
|
||||
Files.deleteIfExists(getDirectories().getUnpickLoggingConfigFile().toPath());
|
||||
Files.copy(is, getDirectories().getUnpickLoggingConfigFile().toPath());
|
||||
} catch (IOException e) {
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
package net.fabricmc.loom.task;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
@@ -32,11 +33,11 @@ import java.nio.file.Files;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import dev.architectury.tinyremapper.TinyRemapper;
|
||||
import dev.architectury.tinyremapper.api.TrEnvironment;
|
||||
import org.gradle.api.DefaultTask;
|
||||
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.SkipWhenEmpty;
|
||||
import org.gradle.api.tasks.TaskAction;
|
||||
|
||||
@@ -44,21 +45,24 @@ import net.fabricmc.accesswidener.AccessWidenerFormatException;
|
||||
import net.fabricmc.accesswidener.AccessWidenerReader;
|
||||
import net.fabricmc.accesswidener.AccessWidenerVisitor;
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
|
||||
import net.fabricmc.tinyremapper.TinyRemapper;
|
||||
import net.fabricmc.tinyremapper.api.TrEnvironment;
|
||||
|
||||
public abstract class ValidateAccessWidenerTask extends DefaultTask {
|
||||
@SkipWhenEmpty
|
||||
@InputFile
|
||||
public abstract RegularFileProperty getAccessWidener();
|
||||
|
||||
@InputFile
|
||||
public abstract RegularFileProperty getTargetJar();
|
||||
@InputFiles
|
||||
public abstract ConfigurableFileCollection getTargetJars();
|
||||
|
||||
@Inject
|
||||
public ValidateAccessWidenerTask() {
|
||||
final LoomGradleExtension extension = LoomGradleExtension.get(getProject());
|
||||
|
||||
getAccessWidener().convention(extension.getAccessWidenerPath()).finalizeValueOnRead();
|
||||
getTargetJar().convention(getProject().getObjects().fileProperty().fileValue(extension.getMinecraftMappedProvider().getMappedJar())).finalizeValueOnRead();
|
||||
getTargetJars().from(extension.getMinecraftJarsCollection(MappingsNamespace.NAMED));
|
||||
|
||||
// Ignore outputs for up-to-date checks as there aren't any (so only inputs are checked)
|
||||
getOutputs().upToDateWhen(task -> true);
|
||||
@@ -67,7 +71,10 @@ public abstract class ValidateAccessWidenerTask extends DefaultTask {
|
||||
@TaskAction
|
||||
public void run() {
|
||||
final TinyRemapper tinyRemapper = TinyRemapper.newRemapper().build();
|
||||
tinyRemapper.readClassPath(getTargetJar().get().getAsFile().toPath());
|
||||
|
||||
for (File file : getTargetJars().getFiles()) {
|
||||
tinyRemapper.readClassPath(file.toPath());
|
||||
}
|
||||
|
||||
final AccessWidenerValidator validator = new AccessWidenerValidator(tinyRemapper.getEnvironment());
|
||||
final AccessWidenerReader accessWidenerReader = new AccessWidenerReader(validator);
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* 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.launch;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.StringJoiner;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.gradle.api.logging.configuration.ConsoleOutput;
|
||||
import org.gradle.api.tasks.TaskAction;
|
||||
|
||||
import net.fabricmc.loom.task.AbstractLoomTask;
|
||||
|
||||
public abstract class GenerateDLIConfigTask extends AbstractLoomTask {
|
||||
@TaskAction
|
||||
public void run() throws IOException {
|
||||
final String nativesPath = getExtension().getFiles().getNativesDirectory(getProject()).getAbsolutePath();
|
||||
|
||||
final LaunchConfig launchConfig = new LaunchConfig()
|
||||
.property("fabric.development", "true")
|
||||
.property("fabric.remapClasspathFile", getExtension().getFiles().getRemapClasspathFile().getAbsolutePath())
|
||||
.property("log4j.configurationFile", getAllLog4JConfigFiles())
|
||||
.property("log4j2.formatMsgNoLookups", "true")
|
||||
|
||||
.property("client", "java.library.path", nativesPath)
|
||||
.property("client", "org.lwjgl.librarypath", nativesPath)
|
||||
|
||||
.argument("client", "--assetIndex")
|
||||
.argument("client", getExtension().getMinecraftProvider().getVersionInfo().assetIndex().fabricId(getExtension().getMinecraftProvider().minecraftVersion()))
|
||||
.argument("client", "--assetsDir")
|
||||
.argument("client", new File(getExtension().getFiles().getUserCache(), "assets").getAbsolutePath());
|
||||
|
||||
final boolean plainConsole = getProject().getGradle().getStartParameter().getConsoleOutput() == ConsoleOutput.Plain;
|
||||
final boolean ansiSupportedIDE = new File(getProject().getRootDir(), ".vscode").exists()
|
||||
|| new File(getProject().getRootDir(), ".idea").exists()
|
||||
|| (Arrays.stream(getProject().getRootDir().listFiles()).anyMatch(file -> file.getName().endsWith(".iws")));
|
||||
|
||||
//Enable ansi by default for idea and vscode when gradle is not ran with plain console.
|
||||
if (ansiSupportedIDE && !plainConsole) {
|
||||
launchConfig.property("fabric.log.disableAnsi", "false");
|
||||
}
|
||||
|
||||
FileUtils.writeStringToFile(getExtension().getFiles().getDevLauncherConfig(), launchConfig.asString(), StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
private String getAllLog4JConfigFiles() {
|
||||
return getExtension().getLog4jConfigs().getFiles().stream()
|
||||
.map(File::getAbsolutePath)
|
||||
.collect(Collectors.joining(","));
|
||||
}
|
||||
|
||||
public static class LaunchConfig {
|
||||
private final Map<String, List<String>> values = new HashMap<>();
|
||||
|
||||
public LaunchConfig property(String key, String value) {
|
||||
return property("common", key, value);
|
||||
}
|
||||
|
||||
public LaunchConfig property(String side, String key, String value) {
|
||||
values.computeIfAbsent(side + "Properties", (s -> new ArrayList<>()))
|
||||
.add(String.format("%s=%s", key, value));
|
||||
return this;
|
||||
}
|
||||
|
||||
public LaunchConfig argument(String value) {
|
||||
return argument("common", value);
|
||||
}
|
||||
|
||||
public LaunchConfig argument(String side, String value) {
|
||||
values.computeIfAbsent(side + "Args", (s -> new ArrayList<>()))
|
||||
.add(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public String asString() {
|
||||
StringJoiner stringJoiner = new StringJoiner("\n");
|
||||
|
||||
for (Map.Entry<String, List<String>> entry : values.entrySet()) {
|
||||
stringJoiner.add(entry.getKey());
|
||||
|
||||
for (String s : entry.getValue()) {
|
||||
stringJoiner.add("\t" + s);
|
||||
}
|
||||
}
|
||||
|
||||
return stringJoiner.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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.launch;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import org.gradle.api.tasks.TaskAction;
|
||||
|
||||
import net.fabricmc.loom.task.AbstractLoomTask;
|
||||
|
||||
public abstract class GenerateLog4jConfigTask extends AbstractLoomTask {
|
||||
@TaskAction
|
||||
public void run() {
|
||||
Path outputFile = getExtension().getFiles().getDefaultLog4jConfigFile().toPath();
|
||||
|
||||
try (InputStream is = GenerateLog4jConfigTask.class.getClassLoader().getResourceAsStream("log4j2.fabric.xml")) {
|
||||
Files.deleteIfExists(outputFile);
|
||||
Files.copy(is, outputFile);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Failed to generate log4j config", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.task.launch;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.gradle.api.tasks.TaskAction;
|
||||
|
||||
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
|
||||
import net.fabricmc.loom.configuration.RemappedConfigurationEntry;
|
||||
import net.fabricmc.loom.task.AbstractLoomTask;
|
||||
import net.fabricmc.loom.util.Constants;
|
||||
|
||||
public abstract class GenerateRemapClasspathTask extends AbstractLoomTask {
|
||||
@TaskAction
|
||||
public void run() {
|
||||
List<String> inputConfigurations = new ArrayList<>();
|
||||
inputConfigurations.add(Constants.Configurations.LOADER_DEPENDENCIES);
|
||||
inputConfigurations.addAll(Constants.MOD_COMPILE_ENTRIES.stream().map(RemappedConfigurationEntry::sourceConfiguration).toList());
|
||||
|
||||
List<File> remapClasspath = new ArrayList<>();
|
||||
|
||||
for (String inputConfiguration : inputConfigurations) {
|
||||
remapClasspath.addAll(getProject().getConfigurations().getByName(inputConfiguration).getFiles());
|
||||
}
|
||||
|
||||
for (Path minecraftJar : getExtension().getMinecraftJars(MappingsNamespace.INTERMEDIARY)) {
|
||||
remapClasspath.add(minecraftJar.toFile());
|
||||
}
|
||||
|
||||
String str = remapClasspath.stream()
|
||||
.map(File::getAbsolutePath)
|
||||
.collect(Collectors.joining(File.pathSeparator));
|
||||
|
||||
try {
|
||||
Files.writeString(getExtension().getFiles().getRemapClasspathFile().toPath(), str);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Failed to generate remap classpath", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -53,7 +53,7 @@ public abstract class JarManifestService implements BuildService<JarManifestServ
|
||||
Property<MixinVersion> getMixinVersion();
|
||||
}
|
||||
|
||||
public static Provider<JarManifestService> get(Project project) {
|
||||
public static synchronized Provider<JarManifestService> get(Project project) {
|
||||
return project.getGradle().getSharedServices().registerIfAbsent("LoomJarManifestService:" + project.getName(), JarManifestService.class, spec -> {
|
||||
spec.parameters(params -> {
|
||||
LoomGradleExtension extension = LoomGradleExtension.get(project);
|
||||
|
||||
@@ -24,49 +24,45 @@
|
||||
|
||||
package net.fabricmc.loom.task.service;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import dev.architectury.tinyremapper.IMappingProvider;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.file.RegularFileProperty;
|
||||
import org.gradle.api.provider.Property;
|
||||
import org.gradle.api.provider.Provider;
|
||||
import org.gradle.api.services.BuildService;
|
||||
import org.gradle.api.services.BuildServiceParameters;
|
||||
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl;
|
||||
import net.fabricmc.loom.util.TinyRemapperHelper;
|
||||
import net.fabricmc.loom.util.service.SharedService;
|
||||
import net.fabricmc.loom.util.service.SharedServiceManager;
|
||||
import net.fabricmc.mappingio.MappingReader;
|
||||
import net.fabricmc.mappingio.tree.MemoryMappingTree;
|
||||
|
||||
public abstract class MappingsService implements BuildService<MappingsService.Params>, AutoCloseable {
|
||||
interface Params extends BuildServiceParameters {
|
||||
RegularFileProperty getMappingsFile();
|
||||
public final class MappingsService implements SharedService {
|
||||
private record Options(Path mappingsFile, String from, String to, boolean remapLocals) { }
|
||||
|
||||
Property<String> getFromNamespace();
|
||||
Property<String> getToNamespace();
|
||||
|
||||
Property<Boolean> getRemapLocals();
|
||||
public static MappingsService create(Project project, String name, Path mappingsFile, String from, String to, boolean remapLocals) {
|
||||
return create(SharedServiceManager.get(project), name, mappingsFile, from, to, remapLocals);
|
||||
}
|
||||
|
||||
public static synchronized Provider<MappingsService> create(Project project, String name, File mappingsFile, String from, String to, boolean remapLocals) {
|
||||
return project.getGradle().getSharedServices().registerIfAbsent(name, MappingsService.class, spec -> {
|
||||
spec.parameters(params -> {
|
||||
params.getMappingsFile().set(mappingsFile);
|
||||
params.getFromNamespace().set(from);
|
||||
params.getToNamespace().set(to);
|
||||
params.getRemapLocals().set(remapLocals);
|
||||
});
|
||||
});
|
||||
public static synchronized MappingsService create(SharedServiceManager sharedServiceManager, String name, Path mappingsFile, String from, String to, boolean remapLocals) {
|
||||
final Options options = new Options(mappingsFile, from, to, remapLocals);
|
||||
final String id = name + options.hashCode();
|
||||
return sharedServiceManager.getOrCreateService(id, () -> new MappingsService(options));
|
||||
}
|
||||
|
||||
public static Provider<MappingsService> createDefault(Project project, String from, String to) {
|
||||
public static MappingsService createDefault(Project project, String from, String to) {
|
||||
final MappingsProviderImpl mappingsProvider = LoomGradleExtension.get(project).getMappingsProvider();
|
||||
|
||||
final String name = mappingsProvider.getBuildServiceName("mappingsProvider", from, to);
|
||||
return MappingsService.create(project, name, (from.equals("srg") || to.equals("srg")) && LoomGradleExtension.get(project).shouldGenerateSrgTiny() ? mappingsProvider.tinyMappingsWithSrg.toFile() : mappingsProvider.tinyMappings.toFile(), from, to, false);
|
||||
return MappingsService.create(project, name, (from.equals("srg") || to.equals("srg")) && LoomGradleExtension.get(project).shouldGenerateSrgTiny() ? mappingsProvider.tinyMappingsWithSrg.toFile() : mappingsProvider.tinyMappings, from, to, false);
|
||||
}
|
||||
|
||||
private final Options options;
|
||||
|
||||
public MappingsService(Options options) {
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
private IMappingProvider mappingProvider = null;
|
||||
@@ -76,13 +72,13 @@ public abstract class MappingsService implements BuildService<MappingsService.Pa
|
||||
if (mappingProvider == null) {
|
||||
try {
|
||||
mappingProvider = TinyRemapperHelper.create(
|
||||
getParameters().getMappingsFile().get().getAsFile().toPath(),
|
||||
getParameters().getFromNamespace().get(),
|
||||
getParameters().getToNamespace().get(),
|
||||
getParameters().getRemapLocals().get()
|
||||
options.mappingsFile(),
|
||||
options.from(),
|
||||
options.to(),
|
||||
options.remapLocals()
|
||||
);
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException("Failed to read mappings from: " + getParameters().getMappingsFile().get().getAsFile().getAbsolutePath(), e);
|
||||
throw new UncheckedIOException("Failed to read mappings from: " + options.mappingsFile(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,9 +90,9 @@ public abstract class MappingsService implements BuildService<MappingsService.Pa
|
||||
memoryMappingTree = new MemoryMappingTree();
|
||||
|
||||
try {
|
||||
MappingReader.read(getParameters().getMappingsFile().get().getAsFile().toPath(), memoryMappingTree);
|
||||
MappingReader.read(options.mappingsFile(), memoryMappingTree);
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException("Failed to read mappings from: " + getParameters().getMappingsFile().get().getAsFile().getAbsolutePath(), e);
|
||||
throw new UncheckedIOException("Failed to read mappings from: " + options.mappingsFile(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,11 +100,11 @@ public abstract class MappingsService implements BuildService<MappingsService.Pa
|
||||
}
|
||||
|
||||
public String getFromNamespace() {
|
||||
return getParameters().getFromNamespace().get();
|
||||
return options.from();
|
||||
}
|
||||
|
||||
public String getToNamespace() {
|
||||
return getParameters().getToNamespace().get();
|
||||
return options.to();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2022 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.service;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashSet;
|
||||
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.tasks.SourceSet;
|
||||
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.util.service.SharedService;
|
||||
import net.fabricmc.loom.util.service.SharedServiceManager;
|
||||
import net.fabricmc.tinyremapper.IMappingProvider;
|
||||
|
||||
public final class MixinMappingsService implements SharedService {
|
||||
private final SharedServiceManager sharedServiceManager;
|
||||
private final HashSet<File> mixinMappings = new HashSet<>();
|
||||
|
||||
private MixinMappingsService(SharedServiceManager sharedServiceManager) {
|
||||
this.sharedServiceManager = sharedServiceManager;
|
||||
}
|
||||
|
||||
public static File getMixinMappingFile(Project project, SourceSet sourceSet) {
|
||||
final LoomGradleExtension extension = LoomGradleExtension.get(project);
|
||||
File mixinMapping = new File(extension.getFiles().getProjectBuildCache(), "mixin-map-" + extension.getMappingsProvider().mappingsIdentifier() + "." + sourceSet.getName() + ".tiny");
|
||||
|
||||
getService(SharedServiceManager.get(project)).mixinMappings.add(mixinMapping);
|
||||
|
||||
return mixinMapping;
|
||||
}
|
||||
|
||||
static synchronized MixinMappingsService getService(SharedServiceManager sharedServiceManager) {
|
||||
return sharedServiceManager.getOrCreateService("MixinMappings", () -> new MixinMappingsService(sharedServiceManager));
|
||||
}
|
||||
|
||||
IMappingProvider getMappingProvider(String from, String to) {
|
||||
return out -> {
|
||||
for (File mixinMapping : mixinMappings) {
|
||||
if (!mixinMapping.exists()) continue;
|
||||
|
||||
MappingsService service = MappingsService.create(sharedServiceManager, mixinMapping.getAbsolutePath(), mixinMapping.toPath(), from, to, false);
|
||||
service.getMappingsProvider().load(out);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -24,49 +24,57 @@
|
||||
|
||||
package net.fabricmc.loom.task.service;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import com.google.common.base.Suppliers;
|
||||
import org.cadixdev.lorenz.MappingSet;
|
||||
import org.cadixdev.mercury.Mercury;
|
||||
import org.cadixdev.mercury.remapper.MercuryRemapper;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.file.ConfigurableFileCollection;
|
||||
import org.gradle.api.file.FileCollection;
|
||||
import org.gradle.api.provider.Property;
|
||||
import org.gradle.api.provider.Provider;
|
||||
import org.gradle.api.services.BuildService;
|
||||
import org.gradle.api.services.BuildServiceParameters;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.task.RemapSourcesJarTask;
|
||||
import net.fabricmc.loom.util.DeletingFileVisitor;
|
||||
import net.fabricmc.loom.util.FileSystemUtil;
|
||||
import net.fabricmc.loom.util.SourceRemapper;
|
||||
import net.fabricmc.loom.util.ZipUtils;
|
||||
import net.fabricmc.loom.util.service.SharedService;
|
||||
import net.fabricmc.loom.util.service.SharedServiceManager;
|
||||
import net.fabricmc.lorenztiny.TinyMappingsReader;
|
||||
|
||||
public abstract class SourceRemapperService implements BuildService<SourceRemapperService.Params>, AutoCloseable {
|
||||
public interface Params extends BuildServiceParameters {
|
||||
Property<Provider<MappingsService>> getMappings();
|
||||
public final class SourceRemapperService implements SharedService {
|
||||
public static synchronized SourceRemapperService create(RemapSourcesJarTask task) {
|
||||
final Project project = task.getProject();
|
||||
final String to = task.getTargetNamespace().get();
|
||||
final String from = task.getSourceNamespace().get();
|
||||
final LoomGradleExtension extension = LoomGradleExtension.get(project);
|
||||
final SharedServiceManager sharedServiceManager = SharedServiceManager.get(project);
|
||||
final String id = extension.getMappingsProvider().getBuildServiceName("sourceremapper", from, to);
|
||||
|
||||
ConfigurableFileCollection getClasspath();
|
||||
}
|
||||
|
||||
public static synchronized Provider<SourceRemapperService> create(Project project, Provider<MappingsService> mappings, FileCollection classpath) {
|
||||
// TODO may need a better name, im not too sure
|
||||
return project.getGradle().getSharedServices().registerIfAbsent("sourceremapper", SourceRemapperService.class, spec ->
|
||||
spec.parameters(params -> {
|
||||
params.getMappings().set(mappings);
|
||||
params.getClasspath().from(classpath);
|
||||
}
|
||||
));
|
||||
return sharedServiceManager.getOrCreateService(id, () ->
|
||||
new SourceRemapperService(MappingsService.createDefault(project, from, to), task.getClasspath()
|
||||
));
|
||||
}
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(SourceRemapperService.class);
|
||||
|
||||
private Mercury mercury;
|
||||
private final MappingsService mappingsService;
|
||||
private final ConfigurableFileCollection classpath;
|
||||
|
||||
private final Supplier<Mercury> mercury = Suppliers.memoize(this::createMercury);
|
||||
|
||||
private SourceRemapperService(MappingsService mappingsService, ConfigurableFileCollection classpath) {
|
||||
this.mappingsService = mappingsService;
|
||||
this.classpath = classpath;
|
||||
}
|
||||
|
||||
public void remapSourcesJar(Path source, Path destination) throws IOException {
|
||||
if (source.equals(destination)) {
|
||||
@@ -99,35 +107,32 @@ public abstract class SourceRemapperService implements BuildService<SourceRemapp
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void doRemap(Path srcPath, Path dstPath, Path source) throws IOException {
|
||||
if (mercury == null) {
|
||||
mercury = new Mercury();
|
||||
mercury.setGracefulClasspathChecks(true);
|
||||
mercury.getProcessors().add(MercuryRemapper.create(getMappings()));
|
||||
|
||||
getParameters().getClasspath().forEach(file -> mercury.getClassPath().add(file.toPath()));
|
||||
}
|
||||
|
||||
private synchronized void doRemap(Path srcPath, Path dstPath, Path source) {
|
||||
try {
|
||||
// Not thread safe!!
|
||||
mercury.rewrite(srcPath, dstPath);
|
||||
mercury.get().rewrite(srcPath, dstPath);
|
||||
} catch (Exception e) {
|
||||
LOGGER.warn("Could not remap " + source + " fully!", e);
|
||||
}
|
||||
}
|
||||
|
||||
private MappingSet getMappings() throws IOException {
|
||||
return new TinyMappingsReader(mappingsService().getMemoryMappingTree(), mappingsService().getFromNamespace(), mappingsService().getToNamespace()).read();
|
||||
return new TinyMappingsReader(mappingsService.getMemoryMappingTree(), mappingsService.getFromNamespace(), mappingsService.getToNamespace()).read();
|
||||
}
|
||||
|
||||
private MappingsService mappingsService() {
|
||||
return getParameters().getMappings().get().get();
|
||||
}
|
||||
private Mercury createMercury() {
|
||||
var mercury = new Mercury();
|
||||
mercury.setGracefulClasspathChecks(true);
|
||||
|
||||
@Override
|
||||
public void close() throws Exception {
|
||||
mercury = null;
|
||||
// This is required (:
|
||||
System.gc();
|
||||
try {
|
||||
mercury.getProcessors().add(MercuryRemapper.create(getMappings()));
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException("Failed to read mercury mappings", e);
|
||||
}
|
||||
|
||||
for (File file : classpath.getFiles()) {
|
||||
mercury.getClassPath().add(file.toPath());
|
||||
}
|
||||
|
||||
return mercury;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2022 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.service;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.gradle.api.Project;
|
||||
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.kotlin.remapping.KotlinMetadataTinyRemapperExtension;
|
||||
import net.fabricmc.loom.task.AbstractRemapJarTask;
|
||||
import net.fabricmc.loom.util.service.SharedService;
|
||||
import net.fabricmc.loom.util.service.SharedServiceManager;
|
||||
import net.fabricmc.tinyremapper.IMappingProvider;
|
||||
import net.fabricmc.tinyremapper.InputTag;
|
||||
import net.fabricmc.tinyremapper.TinyRemapper;
|
||||
|
||||
public class TinyRemapperService implements SharedService {
|
||||
public static synchronized TinyRemapperService getOrCreate(AbstractRemapJarTask remapJarTask) {
|
||||
final Project project = remapJarTask.getProject();
|
||||
final String to = remapJarTask.getTargetNamespace().get();
|
||||
final String from = remapJarTask.getSourceNamespace().get();
|
||||
final LoomGradleExtension extension = LoomGradleExtension.get(project);
|
||||
final SharedServiceManager sharedServiceManager = SharedServiceManager.get(project);
|
||||
final boolean legacyMixin = extension.getMixin().getUseLegacyMixinAp().get();
|
||||
final boolean useKotlinExtension = project.getPluginManager().hasPlugin("org.jetbrains.kotlin.jvm");
|
||||
|
||||
// Generates an id that is used to share the remapper across projects. This tasks in the remap jar task name to handle custom remap jar tasks separately.
|
||||
final String id = extension.getMappingsProvider().getBuildServiceName("remapJarService", from, to) + ":" + remapJarTask.getName() + (useKotlinExtension ? ":kotlin" : "");
|
||||
|
||||
TinyRemapperService service = sharedServiceManager.getOrCreateService(id, () -> {
|
||||
List<IMappingProvider> mappings = new ArrayList<>();
|
||||
mappings.add(MappingsService.createDefault(project, from, to).getMappingsProvider());
|
||||
|
||||
if (legacyMixin) {
|
||||
mappings.add(MixinMappingsService.getService(SharedServiceManager.get(project)).getMappingProvider(from, to));
|
||||
}
|
||||
|
||||
return new TinyRemapperService(mappings, !legacyMixin, useKotlinExtension);
|
||||
});
|
||||
|
||||
service.readClasspath(remapJarTask.getClasspath().getFiles().stream().map(File::toPath).toList());
|
||||
|
||||
return service;
|
||||
}
|
||||
|
||||
private TinyRemapper tinyRemapper;
|
||||
private final Map<String, InputTag> inputTagMap = new HashMap<>();
|
||||
private final HashSet<Path> classpath = new HashSet<>();
|
||||
// Set to true once remapping has started, once set no inputs can be read.
|
||||
private boolean isRemapping = false;
|
||||
|
||||
public TinyRemapperService(List<IMappingProvider> mappings, boolean useMixinExtension, boolean useKotlinExtension) {
|
||||
TinyRemapper.Builder builder = TinyRemapper.newRemapper();
|
||||
|
||||
for (IMappingProvider provider : mappings) {
|
||||
builder.withMappings(provider);
|
||||
}
|
||||
|
||||
if (useMixinExtension) {
|
||||
builder.extension(new net.fabricmc.tinyremapper.extension.mixin.MixinExtension());
|
||||
}
|
||||
|
||||
if (useKotlinExtension) {
|
||||
builder.extension(KotlinMetadataTinyRemapperExtension.INSTANCE);
|
||||
}
|
||||
|
||||
tinyRemapper = builder.build();
|
||||
}
|
||||
|
||||
public synchronized InputTag getOrCreateTag(Path file) {
|
||||
InputTag tag = inputTagMap.get(file.toAbsolutePath().toString());
|
||||
|
||||
if (tag == null) {
|
||||
tag = tinyRemapper.createInputTag();
|
||||
inputTagMap.put(file.toAbsolutePath().toString(), tag);
|
||||
}
|
||||
|
||||
return tag;
|
||||
}
|
||||
|
||||
public TinyRemapper getTinyRemapperForRemapping() {
|
||||
synchronized (this) {
|
||||
isRemapping = true;
|
||||
return Objects.requireNonNull(tinyRemapper, "Tiny remapper has not been setup");
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized TinyRemapper getTinyRemapperForInputs() {
|
||||
synchronized (this) {
|
||||
if (isRemapping) {
|
||||
throw new IllegalStateException("Cannot read inputs as remapping has already started");
|
||||
}
|
||||
|
||||
return tinyRemapper;
|
||||
}
|
||||
}
|
||||
|
||||
void readClasspath(List<Path> paths) {
|
||||
List<Path> toRead;
|
||||
|
||||
synchronized (classpath) {
|
||||
toRead = paths.stream().filter(path -> !classpath.contains(path)).toList();
|
||||
classpath.addAll(paths);
|
||||
}
|
||||
|
||||
tinyRemapper.readClassPathAsync(toRead.toArray(Path[]::new));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
if (tinyRemapper != null) {
|
||||
tinyRemapper.finish();
|
||||
tinyRemapper = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,6 +31,7 @@ import java.nio.charset.StandardCharsets;
|
||||
|
||||
import com.google.common.hash.HashCode;
|
||||
import com.google.common.hash.Hashing;
|
||||
import com.google.common.io.BaseEncoding;
|
||||
import com.google.common.io.Files;
|
||||
import org.gradle.api.logging.Logger;
|
||||
import org.gradle.api.logging.Logging;
|
||||
@@ -77,4 +78,8 @@ public class Checksum {
|
||||
HashCode hash = Hashing.sha256().hashString(string, StandardCharsets.UTF_8);
|
||||
return hash.asBytes();
|
||||
}
|
||||
|
||||
public static String toHex(byte[] bytes) {
|
||||
return BaseEncoding.base16().lowerCase().encode(bytes);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ import java.util.zip.GZIPInputStream;
|
||||
import com.google.common.io.Files;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.logging.Logger;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import net.fabricmc.loom.LoomGradlePlugin;
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ public class HashedDownloadUtil {
|
||||
}
|
||||
|
||||
public static void downloadIfInvalid(URL from, File to, String expectedHash, Logger logger, boolean quiet, boolean strict, Runnable startDownload) throws IOException {
|
||||
if (LoomGradlePlugin.refreshDeps) {
|
||||
if (LoomGradlePlugin.refreshDeps && !Boolean.getBoolean("loom.refresh")) {
|
||||
delete(to);
|
||||
}
|
||||
|
||||
|
||||
59
src/main/java/net/fabricmc/loom/util/SidedClassVisitor.java
Normal file
59
src/main/java/net/fabricmc/loom/util/SidedClassVisitor.java
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* 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.util.Locale;
|
||||
|
||||
import org.objectweb.asm.AnnotationVisitor;
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
|
||||
import net.fabricmc.tinyremapper.TinyRemapper;
|
||||
|
||||
/**
|
||||
* Applies the @Environment annotation to all classes.
|
||||
*/
|
||||
public final class SidedClassVisitor extends ClassVisitor {
|
||||
public static final TinyRemapper.ApplyVisitorProvider CLIENT = (cls, next) -> new SidedClassVisitor("client", next);
|
||||
public static final TinyRemapper.ApplyVisitorProvider SERVER = (cls, next) -> new SidedClassVisitor("server", next);
|
||||
|
||||
private static final String ENVIRONMENT_DESCRIPTOR = "Lnet/fabricmc/api/Environment;";
|
||||
private static final String SIDE_DESCRIPTOR = "Lnet/fabricmc/api/EnvType;";
|
||||
|
||||
private final String side;
|
||||
|
||||
private SidedClassVisitor(String side, ClassVisitor next) {
|
||||
super(Constants.ASM_VERSION, next);
|
||||
this.side = side;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
|
||||
super.visit(version, access, name, signature, superName, interfaces);
|
||||
|
||||
final AnnotationVisitor annotationVisitor = visitAnnotation(ENVIRONMENT_DESCRIPTOR, true);
|
||||
annotationVisitor.visitEnum("value", SIDE_DESCRIPTOR, side.toUpperCase(Locale.ROOT));
|
||||
annotationVisitor.visitEnd();
|
||||
}
|
||||
}
|
||||
@@ -202,8 +202,13 @@ public class SourceRemapper {
|
||||
}
|
||||
}
|
||||
|
||||
m.getClassPath().add(extension.getMinecraftMappedProvider().getMappedJar().toPath());
|
||||
m.getClassPath().add(extension.getMinecraftMappedProvider().getIntermediaryJar().toPath());
|
||||
for (Path intermediaryJar : extension.getMinecraftJars(MappingsNamespace.INTERMEDIARY)) {
|
||||
m.getClassPath().add(intermediaryJar);
|
||||
}
|
||||
|
||||
for (Path intermediaryJar : extension.getMinecraftJars(MappingsNamespace.NAMED)) {
|
||||
m.getClassPath().add(intermediaryJar);
|
||||
}
|
||||
|
||||
if (extension.isForge()) {
|
||||
m.getClassPath().add(extension.getMinecraftMappedProvider().getSrgJar().toPath());
|
||||
|
||||
@@ -147,21 +147,31 @@ public final class TinyRemapperHelper {
|
||||
|
||||
public static IMappingProvider create(MappingTree mappings, String from, String to, boolean remapLocalVariables) {
|
||||
return (acceptor) -> {
|
||||
final int fromId = mappings.getNamespaceId(from);
|
||||
final int toId = mappings.getNamespaceId(to);
|
||||
|
||||
for (MappingTree.ClassMapping classDef : mappings.getClasses()) {
|
||||
String className = classDef.getName(from);
|
||||
acceptor.acceptClass(className, classDef.getName(to));
|
||||
String className = classDef.getName(fromId);
|
||||
String dstName = classDef.getName(toId);
|
||||
|
||||
if (dstName == null) {
|
||||
// Unsure if this is correct, should be better than crashing tho.
|
||||
dstName = className;
|
||||
}
|
||||
|
||||
acceptor.acceptClass(className, dstName);
|
||||
|
||||
for (MappingTree.FieldMapping field : classDef.getFields()) {
|
||||
acceptor.acceptField(memberOf(className, field.getName(from), field.getDesc(from)), field.getName(to));
|
||||
acceptor.acceptField(memberOf(className, field.getName(fromId), field.getDesc(fromId)), field.getName(toId));
|
||||
}
|
||||
|
||||
for (MappingTree.MethodMapping method : classDef.getMethods()) {
|
||||
IMappingProvider.Member methodIdentifier = memberOf(className, method.getName(from), method.getDesc(from));
|
||||
acceptor.acceptMethod(methodIdentifier, method.getName(to));
|
||||
IMappingProvider.Member methodIdentifier = memberOf(className, method.getName(fromId), method.getDesc(fromId));
|
||||
acceptor.acceptMethod(methodIdentifier, method.getName(toId));
|
||||
|
||||
if (remapLocalVariables) {
|
||||
for (MappingTree.MethodArgMapping parameter : method.getArgs()) {
|
||||
String name = parameter.getName(to);
|
||||
String name = parameter.getName(toId);
|
||||
|
||||
if (name == null) {
|
||||
continue;
|
||||
@@ -173,7 +183,7 @@ public final class TinyRemapperHelper {
|
||||
for (MappingTree.MethodVarMapping localVariable : method.getVars()) {
|
||||
acceptor.acceptMethodVar(methodIdentifier, localVariable.getLvIndex(),
|
||||
localVariable.getStartOpIdx(), localVariable.getLvtRowIndex(),
|
||||
localVariable.getName(to));
|
||||
localVariable.getName(toId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,6 +46,8 @@ public class IPCServer implements AutoCloseable {
|
||||
|
||||
private final CountDownLatch startupLock = new CountDownLatch(1);
|
||||
|
||||
private boolean receivedMessage = false;
|
||||
|
||||
public IPCServer(Path path, Consumer<String> consumer) {
|
||||
this.path = path;
|
||||
this.consumer = consumer;
|
||||
@@ -71,6 +73,7 @@ public class IPCServer implements AutoCloseable {
|
||||
Scanner scanner = new Scanner(clientChannel, StandardCharsets.UTF_8)) {
|
||||
while (!Thread.currentThread().isInterrupted()) {
|
||||
if (scanner.hasNextLine()) {
|
||||
receivedMessage = true;
|
||||
this.consumer.accept(scanner.nextLine());
|
||||
}
|
||||
}
|
||||
@@ -85,4 +88,12 @@ public class IPCServer implements AutoCloseable {
|
||||
loggerReceiverService.shutdownNow();
|
||||
loggerReceiverService.awaitTermination(10, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
public boolean hasReceivedMessage() {
|
||||
return receivedMessage;
|
||||
}
|
||||
|
||||
public Path getPath() {
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2018-2021 FabricMC
|
||||
* Copyright (c) 2022 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,20 +22,13 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.fabricmc.loom.configuration.providers;
|
||||
package net.fabricmc.loom.util.service;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftVersionMeta;
|
||||
|
||||
public interface MinecraftProvider {
|
||||
File workingDir();
|
||||
|
||||
File dir(String path);
|
||||
|
||||
File file(String path);
|
||||
|
||||
String minecraftVersion();
|
||||
|
||||
MinecraftVersionMeta getVersionInfo();
|
||||
public interface SharedService extends Closeable {
|
||||
@Override
|
||||
default void close() throws IOException {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2022 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.service;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.gradle.BuildResult;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.invocation.Gradle;
|
||||
|
||||
/**
|
||||
* A simple manager for {@link SharedService} to be used across gradle (sub) projects.
|
||||
* This is a basic replacement for gradle's build service api.
|
||||
*/
|
||||
public final class SharedServiceManager {
|
||||
private static final Map<Gradle, SharedServiceManager> SERVICE_FACTORY_MAP = new ConcurrentHashMap<>();
|
||||
private final Gradle gradle;
|
||||
|
||||
private final Map<String, SharedService> sharedServiceMap = new ConcurrentHashMap<>();
|
||||
|
||||
private boolean shutdown = false;
|
||||
|
||||
private SharedServiceManager(Gradle gradle) {
|
||||
this.gradle = gradle;
|
||||
this.gradle.buildFinished(this::onFinish);
|
||||
}
|
||||
|
||||
public static SharedServiceManager get(Project project) {
|
||||
return get(project.getGradle());
|
||||
}
|
||||
|
||||
public static SharedServiceManager get(Gradle gradle) {
|
||||
return SERVICE_FACTORY_MAP.computeIfAbsent(gradle, SharedServiceManager::new);
|
||||
}
|
||||
|
||||
public <S extends SharedService> S getOrCreateService(String id, Supplier<S> function) {
|
||||
synchronized (sharedServiceMap) {
|
||||
if (shutdown) {
|
||||
throw new UnsupportedOperationException("Cannot get or create service has the manager has been shutdown.");
|
||||
}
|
||||
|
||||
//noinspection unchecked
|
||||
S sharedService = (S) sharedServiceMap.get(id);
|
||||
|
||||
if (sharedService == null) {
|
||||
sharedService = function.get();
|
||||
sharedServiceMap.put(id, sharedService);
|
||||
}
|
||||
|
||||
return sharedService;
|
||||
}
|
||||
}
|
||||
|
||||
private void onFinish(BuildResult buildResult) {
|
||||
synchronized (sharedServiceMap) {
|
||||
shutdown = true;
|
||||
}
|
||||
|
||||
SERVICE_FACTORY_MAP.remove(gradle);
|
||||
|
||||
final List<IOException> exceptionList = new ArrayList<>();
|
||||
|
||||
for (SharedService sharedService : sharedServiceMap.values()) {
|
||||
try {
|
||||
sharedService.close();
|
||||
} catch (IOException e) {
|
||||
exceptionList.add(e);
|
||||
}
|
||||
}
|
||||
|
||||
sharedServiceMap.clear();
|
||||
|
||||
if (!exceptionList.isEmpty()) {
|
||||
// Done to try and close all the services.
|
||||
RuntimeException exception = new RuntimeException("Failed to close all shared services");
|
||||
exceptionList.forEach(exception::addSuppressed);
|
||||
throw exception;
|
||||
}
|
||||
|
||||
// This is required to ensure that mercury releases all of the file handles.
|
||||
System.gc();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2022 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.service;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.provider.Property;
|
||||
|
||||
// Massive hack to work around WorkerExecutor.noIsolation() doing isolation checks.
|
||||
public final class UnsafeWorkQueueHelper {
|
||||
private static final Map<String, SharedService> SERVICE_MAP = new ConcurrentHashMap<>();
|
||||
|
||||
private UnsafeWorkQueueHelper() {
|
||||
}
|
||||
|
||||
public static String create(Project project, SharedService service) {
|
||||
final String uuid = UUID.randomUUID().toString();
|
||||
SERVICE_MAP.put(uuid, service);
|
||||
|
||||
// Ensure we don't make a mess if things go wrong.
|
||||
project.getGradle().buildFinished(buildResult -> SERVICE_MAP.remove(uuid));
|
||||
return uuid;
|
||||
}
|
||||
|
||||
public static <S> S get(Property<String> property, Class<S> clazz) {
|
||||
SharedService service = SERVICE_MAP.remove(property.get());
|
||||
|
||||
if (service == null) {
|
||||
throw new NullPointerException("Failed to get service for " + clazz);
|
||||
}
|
||||
|
||||
//noinspection unchecked
|
||||
return (S) service;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user