Experimental support for split common and clientonly minecraft jars. (#561)
This lays the ground work for split client and server mod code. With this first phase when enabled loom will generate a clientonly and common minecraft jar. Fabric loader and API will both need changes to support this before it can be used to develop mods. Phase two of this project will handle splitting mod code into a client and common source set along with spliting any dependencies. Mostly fixes #539 by sepreating decompile tasks
This commit is contained in:
parent
ccfe12eb17
commit
4158062ce5
49 changed files with 2150 additions and 999 deletions
|
@ -25,6 +25,7 @@
|
||||||
package net.fabricmc.loom;
|
package net.fabricmc.loom;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.nio.file.Path;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
@ -39,13 +40,15 @@ import org.gradle.api.file.FileCollection;
|
||||||
import org.gradle.api.tasks.SourceSet;
|
import org.gradle.api.tasks.SourceSet;
|
||||||
|
|
||||||
import net.fabricmc.loom.api.LoomGradleExtensionAPI;
|
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.InstallerData;
|
||||||
import net.fabricmc.loom.configuration.LoomDependencyManager;
|
import net.fabricmc.loom.configuration.LoomDependencyManager;
|
||||||
import net.fabricmc.loom.configuration.accesswidener.AccessWidenerFile;
|
import net.fabricmc.loom.configuration.accesswidener.AccessWidenerFile;
|
||||||
import net.fabricmc.loom.configuration.processors.JarProcessorManager;
|
import net.fabricmc.loom.configuration.processors.JarProcessorManager;
|
||||||
import net.fabricmc.loom.configuration.providers.MinecraftProviderImpl;
|
|
||||||
import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl;
|
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.LoomFiles;
|
||||||
import net.fabricmc.loom.extension.MixinExtension;
|
import net.fabricmc.loom.extension.MixinExtension;
|
||||||
|
|
||||||
|
@ -83,17 +86,31 @@ public interface LoomGradleExtension extends LoomGradleExtensionAPI {
|
||||||
|
|
||||||
JarProcessorManager getJarProcessorManager();
|
JarProcessorManager getJarProcessorManager();
|
||||||
|
|
||||||
default MinecraftProviderImpl getMinecraftProvider() {
|
MinecraftProvider getMinecraftProvider();
|
||||||
return getDependencyManager().getProvider(MinecraftProviderImpl.class);
|
|
||||||
|
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() {
|
FileCollection getMinecraftJarsCollection(MappingsNamespace mappingsNamespace);
|
||||||
return getDependencyManager().getProvider(MappingsProviderImpl.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
default MinecraftMappedProvider getMinecraftMappedProvider() {
|
|
||||||
return getMappingsProvider().mappedProvider;
|
|
||||||
}
|
|
||||||
|
|
||||||
File getMixinMappings(SourceSet sourceSet);
|
File getMixinMappings(SourceSet sourceSet);
|
||||||
|
|
||||||
|
|
|
@ -30,8 +30,8 @@ import org.gradle.api.artifacts.Dependency;
|
||||||
import org.gradle.api.logging.Logger;
|
import org.gradle.api.logging.Logger;
|
||||||
import org.jetbrains.annotations.ApiStatus;
|
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.mappings.MappingsProvider;
|
||||||
|
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftProvider;
|
||||||
|
|
||||||
@ApiStatus.Experimental /* Very Experimental and not cleanly separated from the impl atm */
|
@ApiStatus.Experimental /* Very Experimental and not cleanly separated from the impl atm */
|
||||||
public interface MappingContext {
|
public interface MappingContext {
|
||||||
|
|
|
@ -24,7 +24,6 @@
|
||||||
|
|
||||||
package net.fabricmc.loom.configuration;
|
package net.fabricmc.loom.configuration;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
import org.gradle.api.NamedDomainObjectProvider;
|
import org.gradle.api.NamedDomainObjectProvider;
|
||||||
|
@ -34,7 +33,6 @@ import org.gradle.api.plugins.JavaPlugin;
|
||||||
import org.gradle.api.plugins.JavaPluginExtension;
|
import org.gradle.api.plugins.JavaPluginExtension;
|
||||||
import org.gradle.api.tasks.AbstractCopyTask;
|
import org.gradle.api.tasks.AbstractCopyTask;
|
||||||
import org.gradle.api.tasks.SourceSet;
|
import org.gradle.api.tasks.SourceSet;
|
||||||
import org.gradle.api.tasks.TaskContainer;
|
|
||||||
import org.gradle.api.tasks.compile.JavaCompile;
|
import org.gradle.api.tasks.compile.JavaCompile;
|
||||||
import org.gradle.api.tasks.javadoc.Javadoc;
|
import org.gradle.api.tasks.javadoc.Javadoc;
|
||||||
|
|
||||||
|
@ -42,12 +40,21 @@ import net.fabricmc.loom.LoomGradleExtension;
|
||||||
import net.fabricmc.loom.build.mixin.JavaApInvoker;
|
import net.fabricmc.loom.build.mixin.JavaApInvoker;
|
||||||
import net.fabricmc.loom.build.mixin.KaptApInvoker;
|
import net.fabricmc.loom.build.mixin.KaptApInvoker;
|
||||||
import net.fabricmc.loom.build.mixin.ScalaApInvoker;
|
import net.fabricmc.loom.build.mixin.ScalaApInvoker;
|
||||||
import net.fabricmc.loom.configuration.providers.LaunchProvider;
|
import net.fabricmc.loom.configuration.accesswidener.AccessWidenerJarProcessor;
|
||||||
import net.fabricmc.loom.configuration.providers.MinecraftProviderImpl;
|
import net.fabricmc.loom.configuration.accesswidener.TransitiveAccessWidenerJarProcessor;
|
||||||
|
import net.fabricmc.loom.configuration.decompile.MergedDecompileConfiguration;
|
||||||
|
import net.fabricmc.loom.configuration.decompile.SplitDecompileConfiguration;
|
||||||
|
import net.fabricmc.loom.configuration.ifaceinject.InterfaceInjectionProcessor;
|
||||||
|
import net.fabricmc.loom.configuration.processors.JarProcessorManager;
|
||||||
import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl;
|
import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl;
|
||||||
|
import net.fabricmc.loom.configuration.providers.minecraft.MergedMinecraftProvider;
|
||||||
|
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftProvider;
|
||||||
|
import net.fabricmc.loom.configuration.providers.minecraft.SplitMinecraftProvider;
|
||||||
|
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;
|
||||||
import net.fabricmc.loom.extension.MixinExtension;
|
import net.fabricmc.loom.extension.MixinExtension;
|
||||||
import net.fabricmc.loom.task.GenerateSourcesTask;
|
|
||||||
import net.fabricmc.loom.task.UnpickJarTask;
|
|
||||||
import net.fabricmc.loom.util.Constants;
|
import net.fabricmc.loom.util.Constants;
|
||||||
|
|
||||||
public final class CompileConfiguration {
|
public final class CompileConfiguration {
|
||||||
|
@ -123,6 +130,11 @@ public final class CompileConfiguration {
|
||||||
|
|
||||||
extendsFrom(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME, Constants.Configurations.LOOM_DEVELOPMENT_DEPENDENCIES, project);
|
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);
|
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) {
|
public static void configureCompile(Project p) {
|
||||||
|
@ -135,13 +147,14 @@ public final class CompileConfiguration {
|
||||||
});
|
});
|
||||||
|
|
||||||
p.afterEvaluate(project -> {
|
p.afterEvaluate(project -> {
|
||||||
|
try {
|
||||||
|
setupMinecraft(project);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("Failed to setup minecraft", e);
|
||||||
|
}
|
||||||
|
|
||||||
LoomDependencyManager dependencyManager = new LoomDependencyManager();
|
LoomDependencyManager dependencyManager = new LoomDependencyManager();
|
||||||
extension.setDependencyManager(dependencyManager);
|
extension.setDependencyManager(dependencyManager);
|
||||||
|
|
||||||
dependencyManager.addProvider(new MinecraftProviderImpl(project));
|
|
||||||
dependencyManager.addProvider(new MappingsProviderImpl(project));
|
|
||||||
dependencyManager.addProvider(new LaunchProvider(project));
|
|
||||||
|
|
||||||
dependencyManager.handleDependencies(project);
|
dependencyManager.handleDependencies(project);
|
||||||
|
|
||||||
extension.getRemapArchives().finalizeValue();
|
extension.getRemapArchives().finalizeValue();
|
||||||
|
@ -174,6 +187,82 @@ 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);
|
||||||
|
|
||||||
|
boolean split = project.getProperties().get("fabric.loom.experimental.splitMcJars") != null;
|
||||||
|
|
||||||
|
// Provide the vanilla mc jars
|
||||||
|
final MinecraftProvider minecraftProvider = split ? new SplitMinecraftProvider(project) : new MergedMinecraftProvider(project);
|
||||||
|
extension.setMinecraftProvider(minecraftProvider);
|
||||||
|
minecraftProvider.provide();
|
||||||
|
|
||||||
|
// Provide the mappings
|
||||||
|
final MappingsProviderImpl mappingsProvider = new MappingsProviderImpl(project, minecraftProvider);
|
||||||
|
extension.setMappingsProvider(mappingsProvider);
|
||||||
|
mappingsProvider.provide();
|
||||||
|
|
||||||
|
// Provide the remapped mc jars
|
||||||
|
final IntermediaryMinecraftProvider<?> intermediaryMinecraftProvider;
|
||||||
|
NamedMinecraftProvider<?> namedMinecraftProvider;
|
||||||
|
|
||||||
|
if (split) {
|
||||||
|
intermediaryMinecraftProvider = new IntermediaryMinecraftProvider.SplitImpl(project, (SplitMinecraftProvider) minecraftProvider);
|
||||||
|
namedMinecraftProvider = new NamedMinecraftProvider.SplitImpl(project, (SplitMinecraftProvider) minecraftProvider);
|
||||||
|
} else {
|
||||||
|
intermediaryMinecraftProvider = new IntermediaryMinecraftProvider.MergedImpl(project, (MergedMinecraftProvider) minecraftProvider);
|
||||||
|
namedMinecraftProvider = new NamedMinecraftProvider.MergedImpl(project, (MergedMinecraftProvider) minecraftProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
final JarProcessorManager jarProcessorManager = createJarProcessorManager(project);
|
||||||
|
|
||||||
|
if (jarProcessorManager.active()) {
|
||||||
|
// Wrap the named MC provider for one that will provide the processed jars
|
||||||
|
if (split) {
|
||||||
|
namedMinecraftProvider = new ProcessedNamedMinecraftProvider.SplitImpl((NamedMinecraftProvider.SplitImpl) namedMinecraftProvider, jarProcessorManager);
|
||||||
|
} else {
|
||||||
|
namedMinecraftProvider = new ProcessedNamedMinecraftProvider.MergedImpl((NamedMinecraftProvider.MergedImpl) 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) {
|
private static void setupMixinAp(Project project, MixinExtension mixin) {
|
||||||
mixin.init();
|
mixin.init();
|
||||||
|
|
||||||
|
@ -198,39 +287,15 @@ public final class CompileConfiguration {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void configureDecompileTasks(Project project) {
|
private static void configureDecompileTasks(Project project) {
|
||||||
final TaskContainer tasks = project.getTasks();
|
|
||||||
final LoomGradleExtension extension = LoomGradleExtension.get(project);
|
final LoomGradleExtension extension = LoomGradleExtension.get(project);
|
||||||
|
|
||||||
MappingsProviderImpl mappingsProvider = extension.getMappingsProvider();
|
if (extension.getNamedMinecraftProvider() instanceof MappedMinecraftProvider.Merged mergedMappedMinecraftProvider) {
|
||||||
|
new MergedDecompileConfiguration(project, mergedMappedMinecraftProvider).afterEvaluation();
|
||||||
File mappedJar = mappingsProvider.mappedProvider.getMappedJar();
|
} else if (extension.getNamedMinecraftProvider() instanceof MappedMinecraftProvider.Split splitMinecraftProvider) {
|
||||||
|
new SplitDecompileConfiguration(project, splitMinecraftProvider).afterEvaluation();
|
||||||
if (mappingsProvider.hasUnpickDefinitions()) {
|
} else {
|
||||||
File outputJar = mappingsProvider.mappedProvider.getUnpickedJar();
|
throw new UnsupportedOperationException();
|
||||||
|
|
||||||
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"));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void extendsFrom(String a, String b, Project project) {
|
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?");
|
|
||||||
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.io.UncheckedIOException;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
import org.gradle.api.Project;
|
import org.gradle.api.Project;
|
||||||
import org.gradle.api.artifacts.Configuration;
|
import org.gradle.api.artifacts.Configuration;
|
||||||
import org.gradle.api.artifacts.Dependency;
|
import org.gradle.api.artifacts.Dependency;
|
||||||
import org.gradle.api.artifacts.DependencySet;
|
|
||||||
import org.gradle.api.artifacts.ExternalModuleDependency;
|
import org.gradle.api.artifacts.ExternalModuleDependency;
|
||||||
import org.gradle.api.artifacts.repositories.MavenArtifactRepository;
|
import org.gradle.api.artifacts.repositories.MavenArtifactRepository;
|
||||||
|
|
||||||
|
@ -45,105 +42,17 @@ import net.fabricmc.loom.LoomGradleExtension;
|
||||||
import net.fabricmc.loom.LoomGradlePlugin;
|
import net.fabricmc.loom.LoomGradlePlugin;
|
||||||
import net.fabricmc.loom.LoomRepositoryPlugin;
|
import net.fabricmc.loom.LoomRepositoryPlugin;
|
||||||
import net.fabricmc.loom.build.ModCompileRemapper;
|
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.ide.idea.IdeaUtils;
|
||||||
import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl;
|
|
||||||
import net.fabricmc.loom.util.Constants;
|
import net.fabricmc.loom.util.Constants;
|
||||||
import net.fabricmc.loom.util.SourceRemapper;
|
import net.fabricmc.loom.util.SourceRemapper;
|
||||||
import net.fabricmc.loom.util.ZipUtils;
|
import net.fabricmc.loom.util.ZipUtils;
|
||||||
|
|
||||||
public class LoomDependencyManager {
|
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<T> clazz) {
|
|
||||||
for (DependencyProvider provider : dependencyProviderList) {
|
|
||||||
if (provider.getClass() == clazz) {
|
|
||||||
return (T) provider;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void handleDependencies(Project project) {
|
public void handleDependencies(Project project) {
|
||||||
List<Runnable> afterTasks = new ArrayList<>();
|
List<Runnable> afterTasks = new ArrayList<>();
|
||||||
|
|
||||||
MappingsProviderImpl mappingsProvider = null;
|
|
||||||
|
|
||||||
project.getLogger().info(":setting up loom dependencies");
|
project.getLogger().info(":setting up loom dependencies");
|
||||||
LoomGradleExtension extension = LoomGradleExtension.get(project);
|
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(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SourceRemapper sourceRemapper = new SourceRemapper(project, true);
|
|
||||||
String mappingsIdentifier = mappingsProvider.mappingsIdentifier();
|
|
||||||
|
|
||||||
if (extension.getInstallerData() == null) {
|
if (extension.getInstallerData() == null) {
|
||||||
//If we've not found the installer JSON we've probably skipped remapping Fabric loader, let's go looking
|
//If we've not found the installer JSON we've probably skipped remapping Fabric loader, let's go looking
|
||||||
|
@ -168,14 +77,17 @@ public class LoomDependencyManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (extension.getInstallerData() == null) {
|
SourceRemapper sourceRemapper = new SourceRemapper(project, true);
|
||||||
project.getLogger().warn("fabric-installer.json not found in classpath!");
|
String mappingsIdentifier = extension.getMappingsProvider().mappingsIdentifier();
|
||||||
}
|
|
||||||
|
|
||||||
ModCompileRemapper.remapDependencies(project, mappingsIdentifier, extension, sourceRemapper);
|
ModCompileRemapper.remapDependencies(project, mappingsIdentifier, extension, sourceRemapper);
|
||||||
|
|
||||||
sourceRemapper.remapAll();
|
sourceRemapper.remapAll();
|
||||||
|
|
||||||
|
if (extension.getInstallerData() == null) {
|
||||||
|
project.getLogger().warn("fabric-installer.json not found in classpath!");
|
||||||
|
}
|
||||||
|
|
||||||
for (Runnable runnable : afterTasks) {
|
for (Runnable runnable : afterTasks) {
|
||||||
runnable.run();
|
runnable.run();
|
||||||
}
|
}
|
||||||
|
|
|
@ -174,7 +174,10 @@ public class TransitiveAccessWidenerJarProcessor implements JarProcessor {
|
||||||
TinyRemapper tinyRemapper = TinyRemapperHelper.getTinyRemapper(project, "intermediary", "named");
|
TinyRemapper tinyRemapper = TinyRemapperHelper.getTinyRemapper(project, "intermediary", "named");
|
||||||
|
|
||||||
tinyRemapper.readClassPath(TinyRemapperHelper.getMinecraftDependencies(project));
|
tinyRemapper.readClassPath(TinyRemapperHelper.getMinecraftDependencies(project));
|
||||||
tinyRemapper.readClassPath(extension.getMinecraftMappedProvider().getIntermediaryJar().toPath());
|
|
||||||
|
for (Path minecraftJar : extension.getMinecraftJars(MappingsNamespace.INTERMEDIARY)) {
|
||||||
|
tinyRemapper.readClassPath(minecraftJar);
|
||||||
|
}
|
||||||
|
|
||||||
return tinyRemapper;
|
return tinyRemapper;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
|
|
@ -0,0 +1,92 @@
|
||||||
|
/*
|
||||||
|
* 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.Project;
|
||||||
|
|
||||||
|
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.GenerateSourcesTask;
|
||||||
|
import net.fabricmc.loom.task.UnpickJarTask;
|
||||||
|
import net.fabricmc.loom.util.Constants;
|
||||||
|
|
||||||
|
public final class MergedDecompileConfiguration {
|
||||||
|
private final Project project;
|
||||||
|
private final MappedMinecraftProvider.Merged minecraftProvider;
|
||||||
|
private final LoomGradleExtension extension;
|
||||||
|
private final MappingsProviderImpl mappingsProvider;
|
||||||
|
|
||||||
|
public MergedDecompileConfiguration(Project project, MappedMinecraftProvider.Merged minecraftProvider) {
|
||||||
|
this.project = project;
|
||||||
|
this.minecraftProvider = minecraftProvider;
|
||||||
|
this.extension = LoomGradleExtension.get(project);
|
||||||
|
this.mappingsProvider = extension.getMappingsProvider();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void afterEvaluation() {
|
||||||
|
File mappedJar = minecraftProvider.getMergedJar().toFile();
|
||||||
|
|
||||||
|
if (mappingsProvider.hasUnpickDefinitions()) {
|
||||||
|
File outputJar = new File(extension.getMappingsProvider().mappingsWorkingDir().toFile(), "minecraft-unpicked.jar");
|
||||||
|
|
||||||
|
project.getTasks().register("unpickJar", UnpickJarTask.class, unpickJarTask -> {
|
||||||
|
unpickJarTask.getUnpickDefinitions().set(mappingsProvider.getUnpickDefinitionsFile());
|
||||||
|
unpickJarTask.getInputJar().set(minecraftProvider.getMergedJar().toFile());
|
||||||
|
unpickJarTask.getOutputJar().set(outputJar);
|
||||||
|
});
|
||||||
|
|
||||||
|
mappedJar = outputJar;
|
||||||
|
}
|
||||||
|
|
||||||
|
final File inputJar = mappedJar;
|
||||||
|
|
||||||
|
LoomGradleExtension.get(project).getGameDecompilers().forEach(decompiler -> {
|
||||||
|
String taskName = "genSourcesWith" + decompiler.name();
|
||||||
|
// Decompiler will be passed to the constructor of GenerateSourcesTask
|
||||||
|
project.getTasks().register(taskName, GenerateSourcesTask.class, decompiler).configure(task -> {
|
||||||
|
task.getInputJar().set(inputJar);
|
||||||
|
task.getRuntimeJar().set(minecraftProvider.getMergedJar().toFile());
|
||||||
|
|
||||||
|
task.dependsOn(project.getTasks().named("validateAccessWidener"));
|
||||||
|
task.setDescription("Decompile minecraft using %s.".formatted(decompiler.name()));
|
||||||
|
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,132 @@
|
||||||
|
/*
|
||||||
|
* 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.LoomGradleExtension;
|
||||||
|
import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl;
|
||||||
|
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 {
|
||||||
|
private final Project project;
|
||||||
|
private final MappedMinecraftProvider.Split minecraftProvider;
|
||||||
|
private final LoomGradleExtension extension;
|
||||||
|
private final MappingsProviderImpl mappingsProvider;
|
||||||
|
|
||||||
|
public SplitDecompileConfiguration(Project project, MappedMinecraftProvider.Split minecraftProvider) {
|
||||||
|
this.project = project;
|
||||||
|
this.minecraftProvider = minecraftProvider;
|
||||||
|
this.extension = LoomGradleExtension.get(project);
|
||||||
|
this.mappingsProvider = extension.getMappingsProvider();
|
||||||
|
}
|
||||||
|
|
||||||
|
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("Common", minecraftProvider.getCommonJar().toFile(), commonJarToDecompile);
|
||||||
|
unpickClientOnlyJar = createUnpickJarTask("ClientOnly", 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<UnpickJarTask> createUnpickJarTask(String name, File inputJar, File outputJar) {
|
||||||
|
return project.getTasks().register("unpick%sJar".formatted(name), UnpickJarTask.class, unpickJarTask -> {
|
||||||
|
unpickJarTask.getUnpickDefinitions().set(mappingsProvider.getUnpickDefinitionsFile());
|
||||||
|
unpickJarTask.getInputJar().set(inputJar);
|
||||||
|
unpickJarTask.getOutputJar().set(outputJar);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private TaskProvider<Task> createDecompileTasks(String name, Action<GenerateSourcesTask> configureAction) {
|
||||||
|
extension.getGameDecompilers().forEach(decompiler -> {
|
||||||
|
final String taskName = "gen%sSourcesWith%s".formatted(name, decompiler.name());
|
||||||
|
|
||||||
|
project.getTasks().register(taskName, GenerateSourcesTask.class, decompiler).configure(task -> {
|
||||||
|
configureAction.execute(task);
|
||||||
|
task.dependsOn(project.getTasks().named("validateAccessWidener"));
|
||||||
|
task.setDescription("Decompile minecraft using %s.".formatted(decompiler.name()));
|
||||||
|
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)));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -33,7 +33,7 @@ import org.gradle.execution.taskgraph.TaskExecutionGraphInternal;
|
||||||
public class IdeaConfiguration {
|
public class IdeaConfiguration {
|
||||||
public static void setup(Project project) {
|
public static void setup(Project project) {
|
||||||
TaskProvider<IdeaSyncTask> ideaSyncTask = project.getTasks().register("ideaSyncTask", IdeaSyncTask.class, ideaSyncTask1 -> {
|
TaskProvider<IdeaSyncTask> ideaSyncTask = project.getTasks().register("ideaSyncTask", IdeaSyncTask.class, ideaSyncTask1 -> {
|
||||||
ideaSyncTask1.dependsOn(project.getTasks().named("downloadAssets"));
|
ideaSyncTask1.dependsOn(project.getTasks().named("configureLaunch"));
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!IdeaUtils.isIdeaSync()) {
|
if (!IdeaUtils.isIdeaSync()) {
|
||||||
|
|
|
@ -51,6 +51,7 @@ import org.objectweb.asm.ClassWriter;
|
||||||
import org.objectweb.asm.commons.Remapper;
|
import org.objectweb.asm.commons.Remapper;
|
||||||
|
|
||||||
import net.fabricmc.loom.LoomGradleExtension;
|
import net.fabricmc.loom.LoomGradleExtension;
|
||||||
|
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
|
||||||
import net.fabricmc.loom.configuration.RemappedConfigurationEntry;
|
import net.fabricmc.loom.configuration.RemappedConfigurationEntry;
|
||||||
import net.fabricmc.loom.configuration.processors.JarProcessor;
|
import net.fabricmc.loom.configuration.processors.JarProcessor;
|
||||||
import net.fabricmc.loom.util.Constants;
|
import net.fabricmc.loom.util.Constants;
|
||||||
|
@ -272,7 +273,10 @@ public class InterfaceInjectionProcessor implements JarProcessor {
|
||||||
try {
|
try {
|
||||||
TinyRemapper tinyRemapper = TinyRemapperHelper.getTinyRemapper(project, "intermediary", "named");
|
TinyRemapper tinyRemapper = TinyRemapperHelper.getTinyRemapper(project, "intermediary", "named");
|
||||||
tinyRemapper.readClassPath(TinyRemapperHelper.getMinecraftDependencies(project));
|
tinyRemapper.readClassPath(TinyRemapperHelper.getMinecraftDependencies(project));
|
||||||
tinyRemapper.readClassPath(extension.getMinecraftMappedProvider().getIntermediaryJar().toPath());
|
|
||||||
|
for (Path minecraftJar : extension.getMinecraftJars(MappingsNamespace.INTERMEDIARY)) {
|
||||||
|
tinyRemapper.readClassPath(minecraftJar);
|
||||||
|
}
|
||||||
|
|
||||||
return tinyRemapper;
|
return tinyRemapper;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
|
|
@ -46,7 +46,6 @@ import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
|
||||||
import net.fabricmc.loom.configuration.RemappedConfigurationEntry;
|
import net.fabricmc.loom.configuration.RemappedConfigurationEntry;
|
||||||
import net.fabricmc.loom.configuration.processors.dependency.ModDependencyInfo;
|
import net.fabricmc.loom.configuration.processors.dependency.ModDependencyInfo;
|
||||||
import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl;
|
import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl;
|
||||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftMappedProvider;
|
|
||||||
import net.fabricmc.loom.util.Constants;
|
import net.fabricmc.loom.util.Constants;
|
||||||
import net.fabricmc.loom.util.TinyRemapperHelper;
|
import net.fabricmc.loom.util.TinyRemapperHelper;
|
||||||
import net.fabricmc.loom.util.ZipUtils;
|
import net.fabricmc.loom.util.ZipUtils;
|
||||||
|
@ -134,10 +133,8 @@ public class ModProcessor {
|
||||||
|
|
||||||
private void remapJars(List<ModDependencyInfo> remapList) throws IOException {
|
private void remapJars(List<ModDependencyInfo> remapList) throws IOException {
|
||||||
final LoomGradleExtension extension = LoomGradleExtension.get(project);
|
final LoomGradleExtension extension = LoomGradleExtension.get(project);
|
||||||
final MinecraftMappedProvider mappedProvider = extension.getMinecraftMappedProvider();
|
|
||||||
final MappingsProviderImpl mappingsProvider = extension.getMappingsProvider();
|
final MappingsProviderImpl mappingsProvider = extension.getMappingsProvider();
|
||||||
|
|
||||||
Path intermediaryJar = mappedProvider.getIntermediaryJar().toPath();
|
|
||||||
Path[] mcDeps = project.getConfigurations().getByName(Constants.Configurations.LOADER_DEPENDENCIES).getFiles()
|
Path[] mcDeps = project.getConfigurations().getByName(Constants.Configurations.LOADER_DEPENDENCIES).getFiles()
|
||||||
.stream().map(File::toPath).toArray(Path[]::new);
|
.stream().map(File::toPath).toArray(Path[]::new);
|
||||||
|
|
||||||
|
@ -148,7 +145,10 @@ public class ModProcessor {
|
||||||
.renameInvalidLocals(false)
|
.renameInvalidLocals(false)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
remapper.readClassPathAsync(intermediaryJar);
|
for (Path minecraftJar : extension.getMinecraftJars(MappingsNamespace.INTERMEDIARY)) {
|
||||||
|
remapper.readClassPathAsync(minecraftJar);
|
||||||
|
}
|
||||||
|
|
||||||
remapper.readClassPathAsync(mcDeps);
|
remapper.readClassPathAsync(mcDeps);
|
||||||
|
|
||||||
final Map<ModDependencyInfo, InputTag> tagMap = new HashMap<>();
|
final Map<ModDependencyInfo, InputTag> tagMap = new HashMap<>();
|
||||||
|
|
|
@ -1,96 +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) {
|
|
||||||
if (jarProcessorManager.isInvalid(projectMappedJar) || isRefreshDeps()) {
|
|
||||||
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: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() + "/minecraft-" + projectMappedClassifier + ".jar");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public File getMappedJar() {
|
|
||||||
return projectMappedJar;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -35,7 +35,7 @@ import org.gradle.api.logging.Logger;
|
||||||
|
|
||||||
import net.fabricmc.loom.LoomGradleExtension;
|
import net.fabricmc.loom.LoomGradleExtension;
|
||||||
import net.fabricmc.loom.api.mappings.layered.MappingContext;
|
import net.fabricmc.loom.api.mappings.layered.MappingContext;
|
||||||
import net.fabricmc.loom.configuration.providers.MinecraftProvider;
|
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftProvider;
|
||||||
|
|
||||||
public class GradleMappingContext implements MappingContext {
|
public class GradleMappingContext implements MappingContext {
|
||||||
private final Project project;
|
private final Project project;
|
||||||
|
|
|
@ -39,7 +39,6 @@ import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.function.Consumer;
|
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import com.google.common.base.Stopwatch;
|
import com.google.common.base.Stopwatch;
|
||||||
|
@ -53,14 +52,9 @@ import org.objectweb.asm.Opcodes;
|
||||||
import net.fabricmc.loom.LoomGradleExtension;
|
import net.fabricmc.loom.LoomGradleExtension;
|
||||||
import net.fabricmc.loom.LoomGradlePlugin;
|
import net.fabricmc.loom.LoomGradlePlugin;
|
||||||
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
|
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
|
||||||
import net.fabricmc.loom.configuration.DependencyProvider;
|
import net.fabricmc.loom.configuration.DependencyInfo;
|
||||||
import net.fabricmc.loom.configuration.accesswidener.AccessWidenerJarProcessor;
|
import net.fabricmc.loom.configuration.providers.minecraft.MergedMinecraftProvider;
|
||||||
import net.fabricmc.loom.configuration.accesswidener.TransitiveAccessWidenerJarProcessor;
|
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftProvider;
|
||||||
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.minecraft.MinecraftMappedProvider;
|
|
||||||
import net.fabricmc.loom.util.Constants;
|
import net.fabricmc.loom.util.Constants;
|
||||||
import net.fabricmc.loom.util.DeletingFileVisitor;
|
import net.fabricmc.loom.util.DeletingFileVisitor;
|
||||||
import net.fabricmc.loom.util.DownloadUtil;
|
import net.fabricmc.loom.util.DownloadUtil;
|
||||||
|
@ -76,9 +70,7 @@ import net.fabricmc.mappingio.tree.MemoryMappingTree;
|
||||||
import net.fabricmc.stitch.Command;
|
import net.fabricmc.stitch.Command;
|
||||||
import net.fabricmc.stitch.commands.CommandProposeFieldNames;
|
import net.fabricmc.stitch.commands.CommandProposeFieldNames;
|
||||||
|
|
||||||
public class MappingsProviderImpl extends DependencyProvider implements MappingsProvider {
|
public class MappingsProviderImpl implements MappingsProvider {
|
||||||
public MinecraftMappedProvider mappedProvider;
|
|
||||||
|
|
||||||
public String mappingsIdentifier;
|
public String mappingsIdentifier;
|
||||||
|
|
||||||
private Path mappingsWorkingDir;
|
private Path mappingsWorkingDir;
|
||||||
|
@ -95,19 +87,23 @@ public class MappingsProviderImpl extends DependencyProvider implements Mappings
|
||||||
private MemoryMappingTree mappingTree;
|
private MemoryMappingTree mappingTree;
|
||||||
private Map<String, String> signatureFixes;
|
private Map<String, String> signatureFixes;
|
||||||
|
|
||||||
public MappingsProviderImpl(Project project) {
|
private final Project project;
|
||||||
super(project);
|
private final MinecraftProvider minecraftProvider;
|
||||||
|
private final LoomGradleExtension extension;
|
||||||
|
public MappingsProviderImpl(Project project, MinecraftProvider minecraftProvider) {
|
||||||
|
this.project = project;
|
||||||
|
this.minecraftProvider = minecraftProvider;
|
||||||
|
this.extension = LoomGradleExtension.get(project);
|
||||||
}
|
}
|
||||||
|
|
||||||
public MemoryMappingTree getMappings() throws IOException {
|
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");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public void provide() throws Exception {
|
||||||
public void provide(DependencyInfo dependency, Consumer<Runnable> postPopulationScheduler) throws Exception {
|
final DependencyInfo dependency = DependencyInfo.create(project, Constants.Configurations.MAPPINGS);
|
||||||
MinecraftProviderImpl minecraftProvider = getDependencyManager().getProvider(MinecraftProviderImpl.class);
|
|
||||||
|
|
||||||
getProject().getLogger().info(":setting up mappings (" + dependency.getDependency().getName() + " " + dependency.getResolvedVersion() + ")");
|
project.getLogger().info(":setting up mappings (" + dependency.getDependency().getName() + " " + dependency.getResolvedVersion() + ")");
|
||||||
|
|
||||||
String version = dependency.getResolvedVersion();
|
String version = dependency.getResolvedVersion();
|
||||||
File mappingsJar = dependency.resolveFile().orElseThrow(() -> new RuntimeException("Could not find yarn mappings: " + dependency));
|
File mappingsJar = dependency.resolveFile().orElseThrow(() -> new RuntimeException("Could not find yarn mappings: " + dependency));
|
||||||
|
@ -119,7 +115,7 @@ public class MappingsProviderImpl extends DependencyProvider implements Mappings
|
||||||
initFiles();
|
initFiles();
|
||||||
|
|
||||||
if (Files.notExists(tinyMappings) || isRefreshDeps()) {
|
if (Files.notExists(tinyMappings) || isRefreshDeps()) {
|
||||||
storeMappings(getProject(), minecraftProvider, mappingsJar.toPath());
|
storeMappings(project, minecraftProvider, mappingsJar.toPath());
|
||||||
} else {
|
} else {
|
||||||
try (FileSystem fileSystem = FileSystems.newFileSystem(mappingsJar.toPath(), (ClassLoader) null)) {
|
try (FileSystem fileSystem = FileSystems.newFileSystem(mappingsJar.toPath(), (ClassLoader) null)) {
|
||||||
extractExtras(fileSystem);
|
extractExtras(fileSystem);
|
||||||
|
@ -140,49 +136,11 @@ public class MappingsProviderImpl extends DependencyProvider implements Mappings
|
||||||
dependency.getDependency().getVersion()
|
dependency.getDependency().getVersion()
|
||||||
);
|
);
|
||||||
|
|
||||||
getProject().getDependencies().add(Constants.Configurations.MAPPING_CONSTANTS, notation);
|
project.getDependencies().add(Constants.Configurations.MAPPING_CONSTANTS, notation);
|
||||||
populateUnpickClasspath();
|
populateUnpickClasspath();
|
||||||
}
|
}
|
||||||
|
|
||||||
addDependency(tinyMappingsJar.toFile(), Constants.Configurations.MAPPINGS_FINAL);
|
project.getDependencies().add(Constants.Configurations.MAPPINGS_FINAL, project.files(tinyMappingsJar.toFile()));
|
||||||
|
|
||||||
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 (processorManager.active()) {
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getMappingsClassifier(DependencyInfo dependency, boolean isV2) {
|
private String getMappingsClassifier(DependencyInfo dependency, boolean isV2) {
|
||||||
|
@ -196,7 +154,7 @@ public class MappingsProviderImpl extends DependencyProvider implements Mappings
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isV2(DependencyInfo dependency, File mappingsJar) throws IOException {
|
private boolean isV2(DependencyInfo dependency, File mappingsJar) throws IOException {
|
||||||
String minecraftVersion = getMinecraftProvider().minecraftVersion();
|
String minecraftVersion = minecraftProvider.minecraftVersion();
|
||||||
|
|
||||||
// Only do this for official yarn, there isn't really a way we can get the mc version for all mappings
|
// 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) {
|
if (dependency.getDependency().getGroup() != null && dependency.getDependency().getGroup().equals("net.fabricmc") && dependency.getDependency().getName().equals("yarn") && dependency.getDependency().getVersion() != null) {
|
||||||
|
@ -205,7 +163,7 @@ public class MappingsProviderImpl extends DependencyProvider implements Mappings
|
||||||
String yarnMinecraftVersion = yarnVersion.substring(0, yarnVersion.lastIndexOf(separator));
|
String yarnMinecraftVersion = yarnVersion.substring(0, yarnVersion.lastIndexOf(separator));
|
||||||
|
|
||||||
if (!yarnMinecraftVersion.equalsIgnoreCase(minecraftVersion)) {
|
if (!yarnMinecraftVersion.equalsIgnoreCase(minecraftVersion)) {
|
||||||
getProject().getLogger().warn("Minecraft Version ({}) does not match yarn's minecraft version ({})", minecraftVersion, yarnMinecraftVersion);
|
project.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
|
// We can save reading the zip file + header by checking the file name
|
||||||
|
@ -215,7 +173,7 @@ public class MappingsProviderImpl extends DependencyProvider implements Mappings
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void storeMappings(Project project, MinecraftProviderImpl minecraftProvider, Path yarnJar) throws IOException {
|
private void storeMappings(Project project, MinecraftProvider minecraftProvider, Path yarnJar) throws IOException {
|
||||||
project.getLogger().info(":extracting " + yarnJar.getFileName());
|
project.getLogger().info(":extracting " + yarnJar.getFileName());
|
||||||
|
|
||||||
try (FileSystem fileSystem = FileSystems.newFileSystem(yarnJar, (ClassLoader) null)) {
|
try (FileSystem fileSystem = FileSystems.newFileSystem(yarnJar, (ClassLoader) null)) {
|
||||||
|
@ -227,10 +185,14 @@ public class MappingsProviderImpl extends DependencyProvider implements Mappings
|
||||||
// These are unmerged v2 mappings
|
// These are unmerged v2 mappings
|
||||||
mergeAndSaveMappings(project, baseTinyMappings, tinyMappings);
|
mergeAndSaveMappings(project, baseTinyMappings, tinyMappings);
|
||||||
} else {
|
} else {
|
||||||
|
if (minecraftProvider instanceof MergedMinecraftProvider mergedMinecraftProvider) {
|
||||||
// These are merged v1 mappings
|
// These are merged v1 mappings
|
||||||
Files.deleteIfExists(tinyMappings);
|
Files.deleteIfExists(tinyMappings);
|
||||||
project.getLogger().lifecycle(":populating field names");
|
project.getLogger().lifecycle(":populating field names");
|
||||||
suggestFieldNames(minecraftProvider, baseTinyMappings, tinyMappings);
|
suggestFieldNames(mergedMinecraftProvider, baseTinyMappings, tinyMappings);
|
||||||
|
} else {
|
||||||
|
throw new UnsupportedOperationException("V1 mappings only support merged minecraft");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -311,7 +273,7 @@ public class MappingsProviderImpl extends DependencyProvider implements Mappings
|
||||||
|
|
||||||
private void populateUnpickClasspath() {
|
private void populateUnpickClasspath() {
|
||||||
String unpickCliName = "unpick-cli";
|
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)
|
String.format("%s:%s:%s", unpickMetadata.unpickGroup, unpickCliName, unpickMetadata.unpickVersion)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -324,7 +286,7 @@ public class MappingsProviderImpl extends DependencyProvider implements Mappings
|
||||||
};
|
};
|
||||||
|
|
||||||
for (String asm : asmDeps) {
|
for (String asm : asmDeps) {
|
||||||
getProject().getDependencies().add(Constants.Configurations.UNPICK_CLASSPATH,
|
project.getDependencies().add(Constants.Configurations.UNPICK_CLASSPATH,
|
||||||
asm.formatted(Opcodes.class.getPackage().getImplementationVersion())
|
asm.formatted(Opcodes.class.getPackage().getImplementationVersion())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -400,7 +362,7 @@ public class MappingsProviderImpl extends DependencyProvider implements Mappings
|
||||||
return tree;
|
return tree;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void suggestFieldNames(MinecraftProviderImpl minecraftProvider, Path oldMappings, Path newMappings) {
|
private void suggestFieldNames(MergedMinecraftProvider minecraftProvider, Path oldMappings, Path newMappings) {
|
||||||
Command command = new CommandProposeFieldNames();
|
Command command = new CommandProposeFieldNames();
|
||||||
runCommand(command, minecraftProvider.getMergedJar().getAbsolutePath(),
|
runCommand(command, minecraftProvider.getMergedJar().getAbsolutePath(),
|
||||||
oldMappings.toAbsolutePath().toString(),
|
oldMappings.toAbsolutePath().toString(),
|
||||||
|
@ -416,7 +378,7 @@ public class MappingsProviderImpl extends DependencyProvider implements Mappings
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initFiles() {
|
private void initFiles() {
|
||||||
mappingsWorkingDir = getMinecraftProvider().dir(mappingsIdentifier).toPath();
|
mappingsWorkingDir = minecraftProvider.dir(mappingsIdentifier).toPath();
|
||||||
baseTinyMappings = mappingsWorkingDir.resolve("mappings-base.tiny");
|
baseTinyMappings = mappingsWorkingDir.resolve("mappings-base.tiny");
|
||||||
tinyMappings = mappingsWorkingDir.resolve("mappings.tiny");
|
tinyMappings = mappingsWorkingDir.resolve("mappings.tiny");
|
||||||
tinyMappingsJar = mappingsWorkingDir.resolve("mappings.jar");
|
tinyMappingsJar = mappingsWorkingDir.resolve("mappings.jar");
|
||||||
|
@ -439,23 +401,18 @@ public class MappingsProviderImpl extends DependencyProvider implements Mappings
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getTargetConfig() {
|
|
||||||
return Constants.Configurations.MAPPINGS;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Path getIntermediaryTiny() throws IOException {
|
public Path getIntermediaryTiny() throws IOException {
|
||||||
if (intermediaryTiny == null) {
|
if (intermediaryTiny == null) {
|
||||||
intermediaryTiny = getMinecraftProvider().file("intermediary-v2.tiny").toPath();
|
intermediaryTiny = minecraftProvider.file("intermediary-v2.tiny").toPath();
|
||||||
|
|
||||||
if (!Files.exists(intermediaryTiny) || (isRefreshDeps() && !hasRefreshed)) {
|
if (!Files.exists(intermediaryTiny) || (isRefreshDeps() && !hasRefreshed)) {
|
||||||
hasRefreshed = true;
|
hasRefreshed = true;
|
||||||
|
|
||||||
// Download and extract intermediary
|
// Download and extract intermediary
|
||||||
String encodedMinecraftVersion = UrlEscapers.urlFragmentEscaper().escape(getMinecraftProvider().minecraftVersion());
|
String encodedMinecraftVersion = UrlEscapers.urlFragmentEscaper().escape(minecraftProvider.minecraftVersion());
|
||||||
String intermediaryArtifactUrl = getExtension().getIntermediaryUrl(encodedMinecraftVersion);
|
String intermediaryArtifactUrl = extension.getIntermediaryUrl(encodedMinecraftVersion);
|
||||||
File intermediaryJar = getMinecraftProvider().file("intermediary-v2.jar");
|
File intermediaryJar = minecraftProvider.file("intermediary-v2.jar");
|
||||||
DownloadUtil.downloadIfChanged(new URL(intermediaryArtifactUrl), intermediaryJar, getProject().getLogger());
|
DownloadUtil.downloadIfChanged(new URL(intermediaryArtifactUrl), intermediaryJar, project.getLogger());
|
||||||
extractMappings(intermediaryJar.toPath(), intermediaryTiny);
|
extractMappings(intermediaryJar.toPath(), intermediaryTiny);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -471,7 +428,7 @@ public class MappingsProviderImpl extends DependencyProvider implements Mappings
|
||||||
private String createMappingsIdentifier(String mappingsName, String version, String classifier) {
|
private String createMappingsIdentifier(String mappingsName, String version, String classifier) {
|
||||||
// mappingsName . mcVersion . version classifier
|
// mappingsName . mcVersion . version classifier
|
||||||
// Example: net.fabricmc.yarn . 1_16_5 . 1.16.5+build.5 -v2
|
// Example: net.fabricmc.yarn . 1_16_5 . 1.16.5+build.5 -v2
|
||||||
return mappingsName + "." + getMinecraftProvider().minecraftVersion().replace(' ', '_').replace('.', '_').replace('-', '_') + "." + version + classifier;
|
return mappingsName + "." + minecraftProvider.minecraftVersion().replace(' ', '_').replace('.', '_').replace('-', '_') + "." + version + classifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String mappingsIdentifier() {
|
public String mappingsIdentifier() {
|
||||||
|
@ -506,4 +463,8 @@ public class MappingsProviderImpl extends DependencyProvider implements Mappings
|
||||||
|
|
||||||
public record UnpickMetadata(String unpickGroup, String unpickVersion) {
|
public record UnpickMetadata(String unpickGroup, String unpickVersion) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected boolean isRefreshDeps() {
|
||||||
|
return LoomGradlePlugin.refreshDeps;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,95 @@
|
||||||
|
/*
|
||||||
|
* 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.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 File minecraftMergedJar;
|
||||||
|
|
||||||
|
public MergedMinecraftProvider(Project project) {
|
||||||
|
super(project);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void initFiles() {
|
||||||
|
super.initFiles();
|
||||||
|
minecraftMergedJar = file("minecraft-merged.jar");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Path> getMinecraftJars() {
|
||||||
|
return List.of(minecraftMergedJar.toPath());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void provide() throws Exception {
|
||||||
|
super.provide();
|
||||||
|
|
||||||
|
if (!minecraftMergedJar.exists() || isRefreshDeps()) {
|
||||||
|
try {
|
||||||
|
mergeJars();
|
||||||
|
} catch (Throwable e) {
|
||||||
|
HashedDownloadUtil.delete(getMinecraftClientJar());
|
||||||
|
HashedDownloadUtil.delete(getMinecraftServerJar());
|
||||||
|
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 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)) {
|
||||||
|
jarMerger.enableSyntheticParamsOffset();
|
||||||
|
jarMerger.merge();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public File getMergedJar() {
|
||||||
|
return minecraftMergedJar;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -31,13 +31,12 @@ import org.gradle.api.Project;
|
||||||
import org.gradle.api.artifacts.ExternalModuleDependency;
|
import org.gradle.api.artifacts.ExternalModuleDependency;
|
||||||
|
|
||||||
import net.fabricmc.loom.configuration.providers.BundleMetadata;
|
import net.fabricmc.loom.configuration.providers.BundleMetadata;
|
||||||
import net.fabricmc.loom.configuration.providers.MinecraftProviderImpl;
|
|
||||||
import net.fabricmc.loom.util.Constants;
|
import net.fabricmc.loom.util.Constants;
|
||||||
|
|
||||||
public class MinecraftLibraryProvider {
|
public class MinecraftLibraryProvider {
|
||||||
private static final Pattern NATIVES_PATTERN = Pattern.compile("^(?<group>.*)/(.*?)/(?<version>.*)/((?<name>.*?)-([0-9].*?)-)(?<classifier>.*).jar$");
|
private static final Pattern NATIVES_PATTERN = Pattern.compile("^(?<group>.*)/(.*?)/(?<version>.*)/((?<name>.*?)-([0-9].*?)-)(?<classifier>.*).jar$");
|
||||||
|
|
||||||
public void provide(MinecraftProviderImpl minecraftProvider, Project project) {
|
public void provide(MinecraftProvider minecraftProvider, Project project) {
|
||||||
MinecraftVersionMeta versionInfo = minecraftProvider.getVersionInfo();
|
MinecraftVersionMeta versionInfo = minecraftProvider.getVersionInfo();
|
||||||
BundleMetadata serverBundleMetadata = minecraftProvider.getServerBundleMetadata();
|
BundleMetadata serverBundleMetadata = minecraftProvider.getServerBundleMetadata();
|
||||||
|
|
||||||
|
|
|
@ -1,170 +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.Arrays;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.function.Consumer;
|
|
||||||
|
|
||||||
import org.gradle.api.Project;
|
|
||||||
|
|
||||||
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.util.Constants;
|
|
||||||
import net.fabricmc.loom.util.TinyRemapperHelper;
|
|
||||||
import net.fabricmc.tinyremapper.OutputConsumerPath;
|
|
||||||
import net.fabricmc.tinyremapper.TinyRemapper;
|
|
||||||
|
|
||||||
public class MinecraftMappedProvider extends DependencyProvider {
|
|
||||||
private File minecraftMappedJar;
|
|
||||||
private File minecraftIntermediaryJar;
|
|
||||||
|
|
||||||
private 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 (!getExtension().getMinecraftProvider().getMergedJar().exists()) {
|
|
||||||
throw new RuntimeException("input merged jar not found");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!minecraftMappedJar.exists() || !getIntermediaryJar().exists() || isRefreshDeps()) {
|
|
||||||
if (minecraftMappedJar.exists()) {
|
|
||||||
minecraftMappedJar.delete();
|
|
||||||
}
|
|
||||||
|
|
||||||
minecraftMappedJar.getParentFile().mkdirs();
|
|
||||||
|
|
||||||
if (minecraftIntermediaryJar.exists()) {
|
|
||||||
minecraftIntermediaryJar.delete();
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
mapMinecraftJar();
|
|
||||||
} catch (Throwable t) {
|
|
||||||
// Cleanup some some things that may be in a bad state now
|
|
||||||
minecraftMappedJar.delete();
|
|
||||||
minecraftIntermediaryJar.delete();
|
|
||||||
getExtension().getMappingsProvider().cleanFiles();
|
|
||||||
throw new RuntimeException("Failed to remap minecraft", t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!minecraftMappedJar.exists()) {
|
|
||||||
throw new RuntimeException("mapped jar not found");
|
|
||||||
}
|
|
||||||
|
|
||||||
addDependencies(dependency, postPopulationScheduler);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void mapMinecraftJar() throws IOException {
|
|
||||||
String fromM = MappingsNamespace.OFFICIAL.toString();
|
|
||||||
|
|
||||||
MappingsProviderImpl mappingsProvider = getExtension().getMappingsProvider();
|
|
||||||
|
|
||||||
Path input = minecraftProvider.getMergedJar().toPath();
|
|
||||||
Path outputMapped = minecraftMappedJar.toPath();
|
|
||||||
Path outputIntermediary = minecraftIntermediaryJar.toPath();
|
|
||||||
|
|
||||||
for (String toM : Arrays.asList(MappingsNamespace.NAMED.toString(), MappingsNamespace.INTERMEDIARY.toString())) {
|
|
||||||
final boolean toNamed = MappingsNamespace.NAMED.toString().equals(toM);
|
|
||||||
final boolean toIntermediary = MappingsNamespace.INTERMEDIARY.toString().equals(toM);
|
|
||||||
final Path output = toNamed ? outputMapped : outputIntermediary;
|
|
||||||
|
|
||||||
getProject().getLogger().info(":remapping minecraft (TinyRemapper, " + fromM + " -> " + toM + ")");
|
|
||||||
|
|
||||||
Files.deleteIfExists(output);
|
|
||||||
|
|
||||||
final Map<String, String> remappedSignatures = SignatureFixerApplyVisitor.getRemappedSignatures(toIntermediary, mappingsProvider, getProject(), toM);
|
|
||||||
TinyRemapper remapper = TinyRemapperHelper.getTinyRemapper(getProject(), fromM, toM, true, (builder) -> {
|
|
||||||
builder.extraPostApplyVisitor(new SignatureFixerApplyVisitor(remappedSignatures));
|
|
||||||
});
|
|
||||||
|
|
||||||
try (OutputConsumerPath outputConsumer = new OutputConsumerPath.Builder(output).build()) {
|
|
||||||
outputConsumer.addNonClassFiles(input);
|
|
||||||
remapper.readClassPath(TinyRemapperHelper.getMinecraftDependencies(getProject()));
|
|
||||||
remapper.readInputs(input);
|
|
||||||
remapper.apply(outputConsumer);
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new RuntimeException("Failed to remap JAR " + input + " with mappings from " + mappingsProvider.tinyMappings, e);
|
|
||||||
} finally {
|
|
||||||
remapper.finish();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void addDependencies(DependencyInfo dependency, Consumer<Runnable> postPopulationScheduler) {
|
|
||||||
getProject().getDependencies().add(Constants.Configurations.MINECRAFT_NAMED,
|
|
||||||
getProject().getDependencies().module("net.minecraft: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");
|
|
||||||
minecraftMappedJar = new File(getExtension().getMappingsProvider().mappingsWorkingDir().toFile(), "minecraft-mapped.jar");
|
|
||||||
}
|
|
||||||
|
|
||||||
protected File getJarDirectory(File parentDirectory, String type) {
|
|
||||||
return new File(parentDirectory, getJarVersionString(type));
|
|
||||||
}
|
|
||||||
|
|
||||||
protected String getJarVersionString(String type) {
|
|
||||||
return String.format("%s-%s", type, getExtension().getMappingsProvider().mappingsIdentifier());
|
|
||||||
}
|
|
||||||
|
|
||||||
public File getIntermediaryJar() {
|
|
||||||
return minecraftIntermediaryJar;
|
|
||||||
}
|
|
||||||
|
|
||||||
public File getMappedJar() {
|
|
||||||
return minecraftMappedJar;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final File getBaseMappedJar() {
|
|
||||||
return minecraftMappedJar;
|
|
||||||
}
|
|
||||||
|
|
||||||
public File getUnpickedJar() {
|
|
||||||
return new File(getExtension().getMappingsProvider().mappingsWorkingDir().toFile(), "minecraft-unpicked.jar");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getTargetConfig() {
|
|
||||||
return Constants.Configurations.MINECRAFT_NAMED;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -22,15 +22,17 @@
|
||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package net.fabricmc.loom.configuration.providers;
|
package net.fabricmc.loom.configuration.providers.minecraft;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileReader;
|
import java.io.FileReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.nio.charset.StandardCharsets;
|
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.Optional;
|
||||||
import java.util.function.Consumer;
|
|
||||||
|
|
||||||
import com.google.common.io.Files;
|
import com.google.common.io.Files;
|
||||||
import org.gradle.api.GradleException;
|
import org.gradle.api.GradleException;
|
||||||
|
@ -38,18 +40,16 @@ import org.gradle.api.Project;
|
||||||
import org.gradle.api.logging.Logger;
|
import org.gradle.api.logging.Logger;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import net.fabricmc.loom.LoomGradleExtension;
|
||||||
import net.fabricmc.loom.LoomGradlePlugin;
|
import net.fabricmc.loom.LoomGradlePlugin;
|
||||||
import net.fabricmc.loom.configuration.DependencyProvider;
|
import net.fabricmc.loom.configuration.DependencyInfo;
|
||||||
import net.fabricmc.loom.configuration.providers.minecraft.ManifestVersion;
|
import net.fabricmc.loom.configuration.providers.BundleMetadata;
|
||||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftLibraryProvider;
|
|
||||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftVersionMeta;
|
|
||||||
import net.fabricmc.loom.util.Constants;
|
import net.fabricmc.loom.util.Constants;
|
||||||
import net.fabricmc.loom.util.DownloadUtil;
|
import net.fabricmc.loom.util.DownloadUtil;
|
||||||
import net.fabricmc.loom.util.HashedDownloadUtil;
|
import net.fabricmc.loom.util.HashedDownloadUtil;
|
||||||
import net.fabricmc.loom.util.MirrorUtil;
|
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 String minecraftVersion;
|
||||||
|
|
||||||
private MinecraftVersionMeta versionInfo;
|
private MinecraftVersionMeta versionInfo;
|
||||||
|
@ -64,16 +64,17 @@ public class MinecraftProviderImpl extends DependencyProvider implements Minecra
|
||||||
private File minecraftExtractedServerJar;
|
private File minecraftExtractedServerJar;
|
||||||
@Nullable
|
@Nullable
|
||||||
private BundleMetadata serverBundleMetadata;
|
private BundleMetadata serverBundleMetadata;
|
||||||
private File minecraftMergedJar;
|
|
||||||
private File versionManifestJson;
|
private File versionManifestJson;
|
||||||
private File experimentalVersionsJson;
|
private File experimentalVersionsJson;
|
||||||
|
|
||||||
public MinecraftProviderImpl(Project project) {
|
private final Project project;
|
||||||
super(project);
|
|
||||||
|
public MinecraftProvider(Project project) {
|
||||||
|
this.project = project;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public void provide() throws Exception {
|
||||||
public void provide(DependencyInfo dependency, Consumer<Runnable> postPopulationScheduler) throws Exception {
|
final DependencyInfo dependency = DependencyInfo.create(getProject(), Constants.Configurations.MINECRAFT);
|
||||||
minecraftVersion = dependency.getDependency().getVersion();
|
minecraftVersion = dependency.getDependency().getVersion();
|
||||||
|
|
||||||
boolean offline = getProject().getGradle().getStartParameter().isOffline();
|
boolean offline = getProject().getGradle().getStartParameter().isOffline();
|
||||||
|
@ -89,9 +90,6 @@ public class MinecraftProviderImpl extends DependencyProvider implements Minecra
|
||||||
if (offline) {
|
if (offline) {
|
||||||
if (minecraftClientJar.exists() && minecraftServerJar.exists()) {
|
if (minecraftClientJar.exists() && minecraftServerJar.exists()) {
|
||||||
getProject().getLogger().debug("Found client and server jars, presuming up-to-date");
|
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 {
|
} else {
|
||||||
throw new GradleException("Missing jar(s); Client: " + minecraftClientJar.exists() + ", Server: " + minecraftServerJar.exists());
|
throw new GradleException("Missing jar(s); Client: " + minecraftClientJar.exists() + ", Server: " + minecraftServerJar.exists());
|
||||||
}
|
}
|
||||||
|
@ -103,31 +101,17 @@ public class MinecraftProviderImpl extends DependencyProvider implements Minecra
|
||||||
|
|
||||||
libraryProvider = new MinecraftLibraryProvider();
|
libraryProvider = new MinecraftLibraryProvider();
|
||||||
libraryProvider.provide(this, getProject());
|
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() {
|
protected void initFiles() {
|
||||||
workingDir = new File(getDirectories().getUserCache(), minecraftVersion);
|
workingDir = new File(getExtension().getFiles().getUserCache(), minecraftVersion);
|
||||||
workingDir.mkdirs();
|
workingDir.mkdirs();
|
||||||
minecraftJson = file("minecraft-info.json");
|
minecraftJson = file("minecraft-info.json");
|
||||||
minecraftClientJar = file("minecraft-client.jar");
|
minecraftClientJar = file("minecraft-client.jar");
|
||||||
minecraftServerJar = file("minecraft-server.jar");
|
minecraftServerJar = file("minecraft-server.jar");
|
||||||
minecraftExtractedServerJar = file("minecraft-extracted_server.jar");
|
minecraftExtractedServerJar = file("minecraft-extracted_server.jar");
|
||||||
minecraftMergedJar = file("minecraft-merged.jar");
|
versionManifestJson = new File(getExtension().getFiles().getUserCache(), "version_manifest.json");
|
||||||
versionManifestJson = new File(getDirectories().getUserCache(), "version_manifest.json");
|
experimentalVersionsJson = new File(getExtension().getFiles().getUserCache(), "experimental_version_manifest.json");
|
||||||
experimentalVersionsJson = new File(getDirectories().getUserCache(), "experimental_version_manifest.json");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void downloadMcJson(boolean offline) throws IOException {
|
private void downloadMcJson(boolean offline) throws IOException {
|
||||||
|
@ -254,55 +238,52 @@ public class MinecraftProviderImpl extends DependencyProvider implements Minecra
|
||||||
HashedDownloadUtil.downloadIfInvalid(new URL(server.url()), minecraftServerJar, server.sha1(), logger, false);
|
HashedDownloadUtil.downloadIfInvalid(new URL(server.url()), minecraftServerJar, server.sha1(), logger, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void mergeJars(Logger logger) throws IOException {
|
protected final void extractBundledServerJar() throws IOException {
|
||||||
logger.info(":merging jars");
|
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) {
|
if (getServerBundleMetadata().versions().size() != 1) {
|
||||||
logger.info(":Extracting server jar from bootstrap");
|
throw new UnsupportedOperationException("Expected only 1 version in META-INF/versions.list, but got %d".formatted(getServerBundleMetadata().versions().size()));
|
||||||
|
|
||||||
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());
|
getServerBundleMetadata().versions().get(0).unpackEntry(minecraftServerJar.toPath(), getMinecraftExtractedServerJar().toPath());
|
||||||
jarToMerge = minecraftExtractedServerJar;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try (JarMerger jarMerger = new JarMerger(minecraftClientJar, jarToMerge, minecraftMergedJar)) {
|
|
||||||
jarMerger.enableSyntheticParamsOffset();
|
|
||||||
jarMerger.merge();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public File getMergedJar() {
|
|
||||||
return minecraftMergedJar;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public File workingDir() {
|
public File workingDir() {
|
||||||
return workingDir;
|
return workingDir;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public File dir(String path) {
|
public File dir(String path) {
|
||||||
File dir = file(path);
|
File dir = file(path);
|
||||||
dir.mkdirs();
|
dir.mkdirs();
|
||||||
return dir;
|
return dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public File file(String path) {
|
public File file(String path) {
|
||||||
return new File(workingDir(), path);
|
return new File(workingDir(), path);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
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.
|
||||||
|
@Deprecated
|
||||||
|
public File getMinecraftServerJar() {
|
||||||
|
return minecraftServerJar;
|
||||||
|
}
|
||||||
|
|
||||||
public String minecraftVersion() {
|
public String minecraftVersion() {
|
||||||
return minecraftVersion;
|
return minecraftVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public MinecraftVersionMeta getVersionInfo() {
|
public MinecraftVersionMeta getVersionInfo() {
|
||||||
return versionInfo;
|
return versionInfo;
|
||||||
}
|
}
|
||||||
|
@ -311,7 +292,6 @@ public class MinecraftProviderImpl extends DependencyProvider implements Minecra
|
||||||
return libraryProvider;
|
return libraryProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getTargetConfig() {
|
public String getTargetConfig() {
|
||||||
return Constants.Configurations.MINECRAFT;
|
return Constants.Configurations.MINECRAFT;
|
||||||
}
|
}
|
||||||
|
@ -320,4 +300,22 @@ public class MinecraftProviderImpl extends DependencyProvider implements Minecra
|
||||||
public BundleMetadata getServerBundleMetadata() {
|
public BundleMetadata getServerBundleMetadata() {
|
||||||
return serverBundleMetadata;
|
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,99 @@
|
||||||
|
/*
|
||||||
|
* 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.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 File minecraftClientOnlyJar;
|
||||||
|
private File minecraftCommonJar;
|
||||||
|
|
||||||
|
public SplitMinecraftProvider(Project project) {
|
||||||
|
super(project);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void initFiles() {
|
||||||
|
super.initFiles();
|
||||||
|
|
||||||
|
minecraftClientOnlyJar = file("minecraft-client-only.jar");
|
||||||
|
minecraftCommonJar = file("minecraft-common.jar");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Path> getMinecraftJars() {
|
||||||
|
return List.of(minecraftClientOnlyJar.toPath(), minecraftCommonJar.toPath());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void provide() throws Exception {
|
||||||
|
super.provide();
|
||||||
|
|
||||||
|
boolean requiresRefresh = isRefreshDeps() || !minecraftClientOnlyJar.exists() || !minecraftCommonJar.exists();
|
||||||
|
|
||||||
|
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.toPath(), minecraftCommonJar.toPath());
|
||||||
|
} catch (Exception e) {
|
||||||
|
Files.deleteIfExists(minecraftClientOnlyJar.toPath());
|
||||||
|
Files.deleteIfExists(minecraftCommonJar.toPath());
|
||||||
|
|
||||||
|
throw new RuntimeException("Failed to split minecraft", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public File getMinecraftClientOnlyJar() {
|
||||||
|
return minecraftClientOnlyJar;
|
||||||
|
}
|
||||||
|
|
||||||
|
public File getMinecraftCommonJar() {
|
||||||
|
return minecraftCommonJar;
|
||||||
|
}
|
||||||
|
}
|
|
@ -41,14 +41,14 @@ import org.gradle.api.Project;
|
||||||
|
|
||||||
import net.fabricmc.loom.LoomGradleExtension;
|
import net.fabricmc.loom.LoomGradleExtension;
|
||||||
import net.fabricmc.loom.LoomGradlePlugin;
|
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.configuration.providers.minecraft.MinecraftVersionMeta;
|
||||||
import net.fabricmc.loom.util.MirrorUtil;
|
import net.fabricmc.loom.util.MirrorUtil;
|
||||||
import net.fabricmc.loom.util.HashedDownloadUtil;
|
import net.fabricmc.loom.util.HashedDownloadUtil;
|
||||||
import net.fabricmc.loom.util.gradle.ProgressLoggerHelper;
|
import net.fabricmc.loom.util.gradle.ProgressLoggerHelper;
|
||||||
|
|
||||||
public class MinecraftAssetsProvider {
|
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);
|
LoomGradleExtension extension = LoomGradleExtension.get(project);
|
||||||
boolean offline = project.getGradle().getStartParameter().isOffline();
|
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,87 @@
|
||||||
|
/*
|
||||||
|
* 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.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.SplitImpl, IntermediaryMinecraftProvider.MergedImpl {
|
||||||
|
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().toPath(), 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().toPath(), getCommonJar(), MappingsNamespace.OFFICIAL),
|
||||||
|
new RemappedJars(minecraftProvider.getMinecraftClientOnlyJar().toPath(), getClientOnlyJar(), MappingsNamespace.OFFICIAL, minecraftProvider.getMinecraftCommonJar().toPath())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configureRemapper(RemappedJars remappedJars, TinyRemapper.Builder tinyRemapperBuilder) {
|
||||||
|
if (remappedJars.outputJar().equals(getClientOnlyJar())) {
|
||||||
|
tinyRemapperBuilder.extraPostApplyVisitor(SidedClassVisitor.CLIENT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,67 @@
|
||||||
|
/*
|
||||||
|
* 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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,100 @@
|
||||||
|
/*
|
||||||
|
* 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.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().toPath(), 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().toPath(), getCommonJar(), MappingsNamespace.OFFICIAL),
|
||||||
|
new RemappedJars(minecraftProvider.getMinecraftClientOnlyJar().toPath(), getClientOnlyJar(), MappingsNamespace.OFFICIAL, minecraftProvider.getMinecraftCommonJar().toPath())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,147 @@
|
||||||
|
/*
|
||||||
|
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||||
|
*
|
||||||
|
* Copyright (c) 2021 FabricMC
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.fabricmc.loom.configuration.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.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);
|
||||||
|
|
||||||
|
Files.copy(inputJar, outputJar, StandardCopyOption.REPLACE_EXISTING);
|
||||||
|
jarProcessorManager.process(outputJar.toFile());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (applyDependencies) {
|
||||||
|
parentMinecraftProvider.applyDependencies((configuration, name) -> getProject().getDependencies().add(configuration, getDependencyNotation(name)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -47,4 +47,5 @@ public interface LoomFiles {
|
||||||
File getDefaultLog4jConfigFile();
|
File getDefaultLog4jConfigFile();
|
||||||
File getDevLauncherConfig();
|
File getDevLauncherConfig();
|
||||||
File getUnpickLoggingConfigFile();
|
File getUnpickLoggingConfigFile();
|
||||||
|
File getRemapClasspathFile();
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,4 +92,9 @@ public abstract class LoomFilesBaseImpl implements LoomFiles {
|
||||||
public File getUnpickLoggingConfigFile() {
|
public File getUnpickLoggingConfigFile() {
|
||||||
return new File(getProjectPersistentCache(), "unpick-logging.properties");
|
return new File(getProjectPersistentCache(), "unpick-logging.properties");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public File getRemapClasspathFile() {
|
||||||
|
return new File(getProjectPersistentCache(), "remapClasspath.txt");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -96,6 +96,9 @@ public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionA
|
||||||
this.versionParser = new ModVersionParser(project);
|
this.versionParser = new ModVersionParser(project);
|
||||||
|
|
||||||
this.deprecationHelper = new DeprecationHelper.ProjectBased(project);
|
this.deprecationHelper = new DeprecationHelper.ProjectBased(project);
|
||||||
|
|
||||||
|
this.accessWidener.finalizeValueOnRead();
|
||||||
|
this.getGameJarProcessors().finalizeValueOnRead();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
package net.fabricmc.loom.extension;
|
package net.fabricmc.loom.extension;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.nio.file.Path;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -43,10 +44,15 @@ import org.gradle.api.file.FileCollection;
|
||||||
import org.gradle.api.tasks.SourceSet;
|
import org.gradle.api.tasks.SourceSet;
|
||||||
|
|
||||||
import net.fabricmc.loom.LoomGradleExtension;
|
import net.fabricmc.loom.LoomGradleExtension;
|
||||||
|
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
|
||||||
import net.fabricmc.loom.configuration.InstallerData;
|
import net.fabricmc.loom.configuration.InstallerData;
|
||||||
import net.fabricmc.loom.configuration.LoomDependencyManager;
|
import net.fabricmc.loom.configuration.LoomDependencyManager;
|
||||||
import net.fabricmc.loom.configuration.accesswidener.AccessWidenerFile;
|
import net.fabricmc.loom.configuration.accesswidener.AccessWidenerFile;
|
||||||
import net.fabricmc.loom.configuration.processors.JarProcessorManager;
|
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;
|
||||||
|
|
||||||
public class LoomGradleExtensionImpl extends LoomGradleExtensionApiImpl implements LoomGradleExtension {
|
public class LoomGradleExtensionImpl extends LoomGradleExtensionApiImpl implements LoomGradleExtension {
|
||||||
private final Project project;
|
private final Project project;
|
||||||
|
@ -62,6 +68,10 @@ public class LoomGradleExtensionImpl extends LoomGradleExtensionApiImpl implemen
|
||||||
|
|
||||||
private LoomDependencyManager dependencyManager;
|
private LoomDependencyManager dependencyManager;
|
||||||
private JarProcessorManager jarProcessorManager;
|
private JarProcessorManager jarProcessorManager;
|
||||||
|
private MinecraftProvider minecraftProvider;
|
||||||
|
private MappingsProviderImpl mappingsProvider;
|
||||||
|
private NamedMinecraftProvider<?> namedMinecraftProvider;
|
||||||
|
private IntermediaryMinecraftProvider<?> intermediaryMinecraftProvider;
|
||||||
private InstallerData installerData;
|
private InstallerData installerData;
|
||||||
|
|
||||||
public LoomGradleExtensionImpl(Project project, LoomFiles files) {
|
public LoomGradleExtensionImpl(Project project, LoomFiles files) {
|
||||||
|
@ -116,6 +126,55 @@ public class LoomGradleExtensionImpl extends LoomGradleExtensionApiImpl implemen
|
||||||
return Objects.requireNonNull(jarProcessorManager, "Cannot get JarProcessorManager before it has been setup");
|
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
|
@Override
|
||||||
public MappingSet getOrCreateSrcMappingCache(int id, Supplier<MappingSet> factory) {
|
public MappingSet getOrCreateSrcMappingCache(int id, Supplier<MappingSet> factory) {
|
||||||
return srcMappingCache[id] != null ? srcMappingCache[id] : (srcMappingCache[id] = factory.get());
|
return srcMappingCache[id] != null ? srcMappingCache[id] : (srcMappingCache[id] = factory.get());
|
||||||
|
|
|
@ -57,12 +57,10 @@ import org.gradle.workers.WorkerExecutor;
|
||||||
import org.gradle.workers.internal.WorkerDaemonClientsManager;
|
import org.gradle.workers.internal.WorkerDaemonClientsManager;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import net.fabricmc.loom.LoomGradleExtension;
|
|
||||||
import net.fabricmc.loom.api.decompilers.DecompilationMetadata;
|
import net.fabricmc.loom.api.decompilers.DecompilationMetadata;
|
||||||
import net.fabricmc.loom.api.decompilers.LoomDecompiler;
|
import net.fabricmc.loom.api.decompilers.LoomDecompiler;
|
||||||
import net.fabricmc.loom.configuration.accesswidener.AccessWidenerFile;
|
import net.fabricmc.loom.configuration.accesswidener.AccessWidenerFile;
|
||||||
import net.fabricmc.loom.configuration.accesswidener.TransitiveAccessWidenerMappingsProcessor;
|
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.decompilers.LineNumberRemapper;
|
||||||
import net.fabricmc.loom.util.Constants;
|
import net.fabricmc.loom.util.Constants;
|
||||||
import net.fabricmc.loom.util.FileSystemUtil;
|
import net.fabricmc.loom.util.FileSystemUtil;
|
||||||
|
@ -77,9 +75,18 @@ import net.fabricmc.loom.util.ipc.IPCServer;
|
||||||
public abstract class GenerateSourcesTask extends AbstractLoomTask {
|
public abstract class GenerateSourcesTask extends AbstractLoomTask {
|
||||||
public final LoomDecompiler decompiler;
|
public final LoomDecompiler decompiler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The jar to decompile, can be the unpick jar.
|
||||||
|
*/
|
||||||
@InputFile
|
@InputFile
|
||||||
public abstract RegularFileProperty getInputJar();
|
public abstract RegularFileProperty getInputJar();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The jar used at runtime.
|
||||||
|
*/
|
||||||
|
@InputFile
|
||||||
|
public abstract RegularFileProperty getRuntimeJar();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Max memory for forked JVM in megabytes.
|
* Max memory for forked JVM in megabytes.
|
||||||
*/
|
*/
|
||||||
|
@ -153,7 +160,7 @@ public abstract class GenerateSourcesTask extends AbstractLoomTask {
|
||||||
params.getOptions().set(getOptions());
|
params.getOptions().set(getOptions());
|
||||||
|
|
||||||
params.getInputJar().set(getInputJar());
|
params.getInputJar().set(getInputJar());
|
||||||
params.getRuntimeJar().set(getExtension().getMappingsProvider().mappedProvider.getMappedJar());
|
params.getRuntimeJar().set(getRuntimeJar());
|
||||||
params.getSourcesDestinationJar().set(getMappedJarFileWithSuffix("-sources.jar"));
|
params.getSourcesDestinationJar().set(getMappedJarFileWithSuffix("-sources.jar"));
|
||||||
params.getLinemap().set(getMappedJarFileWithSuffix("-sources.lmap"));
|
params.getLinemap().set(getMappedJarFileWithSuffix("-sources.lmap"));
|
||||||
params.getLinemapJar().set(getMappedJarFileWithSuffix("-linemapped.jar"));
|
params.getLinemapJar().set(getMappedJarFileWithSuffix("-linemapped.jar"));
|
||||||
|
@ -299,10 +306,7 @@ public abstract class GenerateSourcesTask extends AbstractLoomTask {
|
||||||
}
|
}
|
||||||
|
|
||||||
private File getMappedJarFileWithSuffix(String suffix) {
|
private File getMappedJarFileWithSuffix(String suffix) {
|
||||||
LoomGradleExtension extension = LoomGradleExtension.get(getProject());
|
String path = getRuntimeJar().get().getAsFile().getAbsolutePath();
|
||||||
MappingsProviderImpl mappingsProvider = extension.getMappingsProvider();
|
|
||||||
File mappedJar = mappingsProvider.mappedProvider.getMappedJar();
|
|
||||||
String path = mappedJar.getAbsolutePath();
|
|
||||||
|
|
||||||
if (!path.toLowerCase(Locale.ROOT).endsWith(".jar")) {
|
if (!path.toLowerCase(Locale.ROOT).endsWith(".jar")) {
|
||||||
throw new RuntimeException("Invalid mapped JAR path: " + path);
|
throw new RuntimeException("Invalid mapped JAR path: " + path);
|
||||||
|
|
|
@ -31,6 +31,9 @@ import org.gradle.api.tasks.TaskProvider;
|
||||||
|
|
||||||
import net.fabricmc.loom.LoomGradleExtension;
|
import net.fabricmc.loom.LoomGradleExtension;
|
||||||
import net.fabricmc.loom.configuration.ide.RunConfigSettings;
|
import net.fabricmc.loom.configuration.ide.RunConfigSettings;
|
||||||
|
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;
|
import net.fabricmc.loom.util.Constants;
|
||||||
|
|
||||||
public final class LoomTasks {
|
public final class LoomTasks {
|
||||||
|
@ -47,11 +50,32 @@ public final class LoomTasks {
|
||||||
|
|
||||||
RemapTaskConfiguration.setupRemap(project);
|
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 -> {
|
tasks.register("downloadAssets", DownloadAssetsTask.class, t -> {
|
||||||
t.dependsOn(extractNatives);
|
|
||||||
t.setDescription("Downloads required assets for Fabric.");
|
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("extractNatives"));
|
||||||
|
task.dependsOn(tasks.named("downloadAssets"));
|
||||||
|
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);
|
||||||
|
});
|
||||||
|
|
||||||
TaskProvider<ValidateAccessWidenerTask> validateAccessWidener = tasks.register("validateAccessWidener", ValidateAccessWidenerTask.class, t -> {
|
TaskProvider<ValidateAccessWidenerTask> validateAccessWidener = tasks.register("validateAccessWidener", ValidateAccessWidenerTask.class, t -> {
|
||||||
t.setDescription("Validate all the rules in the access widener against the Minecraft jar");
|
t.setDescription("Validate all the rules in the access widener against the Minecraft jar");
|
||||||
|
@ -62,19 +86,18 @@ public final class LoomTasks {
|
||||||
|
|
||||||
registerIDETasks(tasks);
|
registerIDETasks(tasks);
|
||||||
registerRunTasks(tasks, project);
|
registerRunTasks(tasks, project);
|
||||||
registerDecompileTasks(tasks, project);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void registerIDETasks(TaskContainer tasks) {
|
private static void registerIDETasks(TaskContainer tasks) {
|
||||||
tasks.register("genIdeaWorkspace", GenIdeaProjectTask.class, t -> {
|
tasks.register("genIdeaWorkspace", GenIdeaProjectTask.class, t -> {
|
||||||
t.setDescription("Generates an IntelliJ IDEA workspace from this project.");
|
t.setDescription("Generates an IntelliJ IDEA workspace from this project.");
|
||||||
t.dependsOn("idea", "downloadAssets");
|
t.dependsOn("idea", "configureLaunch");
|
||||||
t.setGroup(Constants.TaskGroup.IDE);
|
t.setGroup(Constants.TaskGroup.IDE);
|
||||||
});
|
});
|
||||||
|
|
||||||
tasks.register("genEclipseRuns", GenEclipseRunsTask.class, t -> {
|
tasks.register("genEclipseRuns", GenEclipseRunsTask.class, t -> {
|
||||||
t.setDescription("Generates Eclipse run configurations for this project.");
|
t.setDescription("Generates Eclipse run configurations for this project.");
|
||||||
t.dependsOn("downloadAssets");
|
t.dependsOn("configureLaunch");
|
||||||
t.setGroup(Constants.TaskGroup.IDE);
|
t.setGroup(Constants.TaskGroup.IDE);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -85,7 +108,7 @@ public final class LoomTasks {
|
||||||
|
|
||||||
tasks.register("vscode", GenVsCodeProjectTask.class, t -> {
|
tasks.register("vscode", GenVsCodeProjectTask.class, t -> {
|
||||||
t.setDescription("Generates VSCode launch configurations.");
|
t.setDescription("Generates VSCode launch configurations.");
|
||||||
t.dependsOn("downloadAssets");
|
t.dependsOn("configureLaunch");
|
||||||
t.setGroup(Constants.TaskGroup.IDE);
|
t.setGroup(Constants.TaskGroup.IDE);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -102,32 +125,11 @@ public final class LoomTasks {
|
||||||
tasks.register(taskName, RunGameTask.class, config).configure(t -> {
|
tasks.register(taskName, RunGameTask.class, config).configure(t -> {
|
||||||
t.setDescription("Starts the '" + config.getConfigName() + "' run configuration");
|
t.setDescription("Starts the '" + config.getConfigName() + "' run configuration");
|
||||||
|
|
||||||
if (config.getEnvironment().equals("client")) {
|
t.dependsOn("configureLaunch");
|
||||||
t.dependsOn("downloadAssets");
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
extension.getRunConfigs().create("client", RunConfigSettings::client);
|
extension.getRunConfigs().create("client", RunConfigSettings::client);
|
||||||
extension.getRunConfigs().create("server", RunConfigSettings::server);
|
extension.getRunConfigs().create("server", RunConfigSettings::server);
|
||||||
}
|
}
|
||||||
|
|
||||||
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"));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
tasks.register("genSources", task -> {
|
|
||||||
task.setDescription("Decompile minecraft using the default decompiler.");
|
|
||||||
task.setGroup(Constants.TaskGroup.FABRIC);
|
|
||||||
|
|
||||||
task.dependsOn(project.getTasks().named("genSourcesWithCfr"));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.api.mappings.layered.spec.LayeredMappingSpecBuilder;
|
||||||
import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingsDependency;
|
import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingsDependency;
|
||||||
import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl;
|
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.loom.util.SourceRemapper;
|
||||||
import net.fabricmc.lorenztiny.TinyMappingsJoiner;
|
import net.fabricmc.lorenztiny.TinyMappingsJoiner;
|
||||||
import net.fabricmc.mappingio.MappingReader;
|
import net.fabricmc.mappingio.MappingReader;
|
||||||
|
@ -101,7 +100,7 @@ public class MigrateMappingsTask extends AbstractLoomTask {
|
||||||
try {
|
try {
|
||||||
MemoryMappingTree currentMappings = mappingsProvider.getMappings();
|
MemoryMappingTree currentMappings = mappingsProvider.getMappings();
|
||||||
MemoryMappingTree targetMappings = getMappings(mappings);
|
MemoryMappingTree targetMappings = getMappings(mappings);
|
||||||
migrateMappings(project, extension.getMinecraftMappedProvider(), inputDir, outputDir, currentMappings, targetMappings);
|
migrateMappings(project, extension, inputDir, outputDir, currentMappings, targetMappings);
|
||||||
project.getLogger().lifecycle(":remapped project written to " + outputDir.toAbsolutePath());
|
project.getLogger().lifecycle(":remapped project written to " + outputDir.toAbsolutePath());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new IllegalArgumentException("Error while loading mappings", e);
|
throw new IllegalArgumentException("Error while loading mappings", e);
|
||||||
|
@ -157,7 +156,7 @@ public class MigrateMappingsTask extends AbstractLoomTask {
|
||||||
return mappingTree;
|
return mappingTree;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void migrateMappings(Project project, MinecraftMappedProvider minecraftMappedProvider,
|
private static void migrateMappings(Project project, LoomGradleExtension extension,
|
||||||
Path inputDir, Path outputDir, MemoryMappingTree currentMappings, MemoryMappingTree targetMappings
|
Path inputDir, Path outputDir, MemoryMappingTree currentMappings, MemoryMappingTree targetMappings
|
||||||
) throws IOException {
|
) throws IOException {
|
||||||
project.getLogger().info(":joining mappings");
|
project.getLogger().info(":joining mappings");
|
||||||
|
@ -174,8 +173,13 @@ public class MigrateMappingsTask extends AbstractLoomTask {
|
||||||
final JavaVersion javaVersion = project.getExtensions().getByType(JavaPluginExtension.class).getSourceCompatibility();
|
final JavaVersion javaVersion = project.getExtensions().getByType(JavaPluginExtension.class).getSourceCompatibility();
|
||||||
mercury.setSourceCompatibility(javaVersion.toString());
|
mercury.setSourceCompatibility(javaVersion.toString());
|
||||||
|
|
||||||
mercury.getClassPath().add(minecraftMappedProvider.getMappedJar().toPath());
|
for (Path intermediaryJar : extension.getMinecraftJars(MappingsNamespace.INTERMEDIARY)) {
|
||||||
mercury.getClassPath().add(minecraftMappedProvider.getIntermediaryJar().toPath());
|
mercury.getClassPath().add(intermediaryJar);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Path intermediaryJar : extension.getMinecraftJars(MappingsNamespace.NAMED)) {
|
||||||
|
mercury.getClassPath().add(intermediaryJar);
|
||||||
|
}
|
||||||
|
|
||||||
mercury.getProcessors().add(MercuryRemapper.create(mappingSet));
|
mercury.getProcessors().add(MercuryRemapper.create(mappingSet));
|
||||||
|
|
||||||
|
|
|
@ -84,8 +84,8 @@ public class RemapTaskConfiguration {
|
||||||
// Remove -dev jars from the default jar task
|
// Remove -dev jars from the default jar task
|
||||||
for (String configurationName : new String[] { JavaPlugin.API_ELEMENTS_CONFIGURATION_NAME, JavaPlugin.RUNTIME_ELEMENTS_CONFIGURATION_NAME }) {
|
for (String configurationName : new String[] { JavaPlugin.API_ELEMENTS_CONFIGURATION_NAME, JavaPlugin.RUNTIME_ELEMENTS_CONFIGURATION_NAME }) {
|
||||||
Configuration configuration = project.getConfigurations().getByName(configurationName);
|
Configuration configuration = project.getConfigurations().getByName(configurationName);
|
||||||
|
final Task jarTask = project.getTasks().getByName(JavaPlugin.JAR_TASK_NAME);
|
||||||
configuration.getArtifacts().removeIf(artifact -> {
|
configuration.getArtifacts().removeIf(artifact -> {
|
||||||
Task jarTask = project.getTasks().getByName(JavaPlugin.JAR_TASK_NAME);
|
|
||||||
// if the artifact is a -dev jar and "builtBy jar"
|
// if the artifact is a -dev jar and "builtBy jar"
|
||||||
return "dev".equals(artifact.getClassifier()) && artifact.getBuildDependencies().getDependencies(null).contains(jarTask);
|
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.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
@ -40,7 +41,7 @@ import org.gradle.api.tasks.JavaExec;
|
||||||
import org.gradle.api.tasks.OutputFile;
|
import org.gradle.api.tasks.OutputFile;
|
||||||
|
|
||||||
import net.fabricmc.loom.LoomGradleExtension;
|
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.extension.LoomFiles;
|
||||||
import net.fabricmc.loom.util.Constants;
|
import net.fabricmc.loom.util.Constants;
|
||||||
|
|
||||||
|
@ -76,7 +77,9 @@ public abstract class UnpickJarTask extends JavaExec {
|
||||||
fileArg(getConstantJar().getSingleFile());
|
fileArg(getConstantJar().getSingleFile());
|
||||||
|
|
||||||
// Classpath
|
// Classpath
|
||||||
fileArg(getExtension().getMinecraftMappedProvider().getMappedJar());
|
for (Path minecraftJar : getExtension().getMinecraftJars(MappingsNamespace.NAMED)) {
|
||||||
|
fileArg(minecraftJar.toFile());
|
||||||
|
}
|
||||||
|
|
||||||
for (File file : getUnpickClasspath()) {
|
for (File file : getUnpickClasspath()) {
|
||||||
fileArg(file);
|
fileArg(file);
|
||||||
|
@ -89,7 +92,7 @@ public abstract class UnpickJarTask extends JavaExec {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeUnpickLogConfig() {
|
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.deleteIfExists(getDirectories().getUnpickLoggingConfigFile().toPath());
|
||||||
Files.copy(is, getDirectories().getUnpickLoggingConfigFile().toPath());
|
Files.copy(is, getDirectories().getUnpickLoggingConfigFile().toPath());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
package net.fabricmc.loom.task;
|
package net.fabricmc.loom.task;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.UncheckedIOException;
|
import java.io.UncheckedIOException;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
@ -33,8 +34,10 @@ import java.nio.file.Files;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import org.gradle.api.DefaultTask;
|
import org.gradle.api.DefaultTask;
|
||||||
|
import org.gradle.api.file.ConfigurableFileCollection;
|
||||||
import org.gradle.api.file.RegularFileProperty;
|
import org.gradle.api.file.RegularFileProperty;
|
||||||
import org.gradle.api.tasks.InputFile;
|
import org.gradle.api.tasks.InputFile;
|
||||||
|
import org.gradle.api.tasks.InputFiles;
|
||||||
import org.gradle.api.tasks.SkipWhenEmpty;
|
import org.gradle.api.tasks.SkipWhenEmpty;
|
||||||
import org.gradle.api.tasks.TaskAction;
|
import org.gradle.api.tasks.TaskAction;
|
||||||
|
|
||||||
|
@ -42,6 +45,7 @@ import net.fabricmc.accesswidener.AccessWidenerFormatException;
|
||||||
import net.fabricmc.accesswidener.AccessWidenerReader;
|
import net.fabricmc.accesswidener.AccessWidenerReader;
|
||||||
import net.fabricmc.accesswidener.AccessWidenerVisitor;
|
import net.fabricmc.accesswidener.AccessWidenerVisitor;
|
||||||
import net.fabricmc.loom.LoomGradleExtension;
|
import net.fabricmc.loom.LoomGradleExtension;
|
||||||
|
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
|
||||||
import net.fabricmc.tinyremapper.TinyRemapper;
|
import net.fabricmc.tinyremapper.TinyRemapper;
|
||||||
import net.fabricmc.tinyremapper.api.TrEnvironment;
|
import net.fabricmc.tinyremapper.api.TrEnvironment;
|
||||||
|
|
||||||
|
@ -50,15 +54,15 @@ public abstract class ValidateAccessWidenerTask extends DefaultTask {
|
||||||
@InputFile
|
@InputFile
|
||||||
public abstract RegularFileProperty getAccessWidener();
|
public abstract RegularFileProperty getAccessWidener();
|
||||||
|
|
||||||
@InputFile
|
@InputFiles
|
||||||
public abstract RegularFileProperty getTargetJar();
|
public abstract ConfigurableFileCollection getTargetJars();
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public ValidateAccessWidenerTask() {
|
public ValidateAccessWidenerTask() {
|
||||||
final LoomGradleExtension extension = LoomGradleExtension.get(getProject());
|
final LoomGradleExtension extension = LoomGradleExtension.get(getProject());
|
||||||
|
|
||||||
getAccessWidener().convention(extension.getAccessWidenerPath()).finalizeValueOnRead();
|
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)
|
// Ignore outputs for up-to-date checks as there aren't any (so only inputs are checked)
|
||||||
getOutputs().upToDateWhen(task -> true);
|
getOutputs().upToDateWhen(task -> true);
|
||||||
|
@ -67,7 +71,10 @@ public abstract class ValidateAccessWidenerTask extends DefaultTask {
|
||||||
@TaskAction
|
@TaskAction
|
||||||
public void run() {
|
public void run() {
|
||||||
final TinyRemapper tinyRemapper = TinyRemapper.newRemapper().build();
|
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 AccessWidenerValidator validator = new AccessWidenerValidator(tinyRemapper.getEnvironment());
|
||||||
final AccessWidenerReader accessWidenerReader = new AccessWidenerReader(validator);
|
final AccessWidenerReader accessWidenerReader = new AccessWidenerReader(validator);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||||
*
|
*
|
||||||
* Copyright (c) 2019-2021 FabricMC
|
* Copyright (c) 2021 FabricMC
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
@ -22,43 +22,33 @@
|
||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package net.fabricmc.loom.configuration.providers;
|
package net.fabricmc.loom.task.launch;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.StringJoiner;
|
import java.util.StringJoiner;
|
||||||
import java.util.function.Consumer;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.apache.commons.io.FileUtils;
|
import org.apache.commons.io.FileUtils;
|
||||||
import org.gradle.api.Project;
|
|
||||||
import org.gradle.api.logging.configuration.ConsoleOutput;
|
import org.gradle.api.logging.configuration.ConsoleOutput;
|
||||||
import org.gradle.api.plugins.JavaPlugin;
|
import org.gradle.api.tasks.TaskAction;
|
||||||
|
|
||||||
import net.fabricmc.loom.configuration.DependencyProvider;
|
import net.fabricmc.loom.task.AbstractLoomTask;
|
||||||
import net.fabricmc.loom.configuration.RemappedConfigurationEntry;
|
|
||||||
import net.fabricmc.loom.util.Constants;
|
|
||||||
|
|
||||||
public class LaunchProvider extends DependencyProvider {
|
public abstract class GenerateDLIConfigTask extends AbstractLoomTask {
|
||||||
public LaunchProvider(Project project) {
|
@TaskAction
|
||||||
super(project);
|
public void run() throws IOException {
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void provide(DependencyInfo dependency, Consumer<Runnable> postPopulationScheduler) throws IOException {
|
|
||||||
final String nativesPath = getExtension().getFiles().getNativesDirectory(getProject()).getAbsolutePath();
|
final String nativesPath = getExtension().getFiles().getNativesDirectory(getProject()).getAbsolutePath();
|
||||||
|
|
||||||
final LaunchConfig launchConfig = new LaunchConfig()
|
final LaunchConfig launchConfig = new LaunchConfig()
|
||||||
.property("fabric.development", "true")
|
.property("fabric.development", "true")
|
||||||
.property("fabric.remapClasspathFile", getRemapClasspathFile().getAbsolutePath())
|
.property("fabric.remapClasspathFile", getExtension().getFiles().getRemapClasspathFile().getAbsolutePath())
|
||||||
.property("log4j.configurationFile", getAllLog4JConfigFiles())
|
.property("log4j.configurationFile", getAllLog4JConfigFiles())
|
||||||
.property("log4j2.formatMsgNoLookups", "true")
|
.property("log4j2.formatMsgNoLookups", "true")
|
||||||
|
|
||||||
|
@ -68,7 +58,7 @@ public class LaunchProvider extends DependencyProvider {
|
||||||
.argument("client", "--assetIndex")
|
.argument("client", "--assetIndex")
|
||||||
.argument("client", getExtension().getMinecraftProvider().getVersionInfo().assetIndex().fabricId(getExtension().getMinecraftProvider().minecraftVersion()))
|
.argument("client", getExtension().getMinecraftProvider().getVersionInfo().assetIndex().fabricId(getExtension().getMinecraftProvider().minecraftVersion()))
|
||||||
.argument("client", "--assetsDir")
|
.argument("client", "--assetsDir")
|
||||||
.argument("client", new File(getDirectories().getUserCache(), "assets").getAbsolutePath());
|
.argument("client", new File(getExtension().getFiles().getUserCache(), "assets").getAbsolutePath());
|
||||||
|
|
||||||
final boolean plainConsole = getProject().getGradle().getStartParameter().getConsoleOutput() == ConsoleOutput.Plain;
|
final boolean plainConsole = getProject().getGradle().getStartParameter().getConsoleOutput() == ConsoleOutput.Plain;
|
||||||
final boolean ansiSupportedIDE = new File(getProject().getRootDir(), ".vscode").exists()
|
final boolean ansiSupportedIDE = new File(getProject().getRootDir(), ".vscode").exists()
|
||||||
|
@ -80,18 +70,7 @@ public class LaunchProvider extends DependencyProvider {
|
||||||
launchConfig.property("fabric.log.disableAnsi", "false");
|
launchConfig.property("fabric.log.disableAnsi", "false");
|
||||||
}
|
}
|
||||||
|
|
||||||
writeLog4jConfig();
|
FileUtils.writeStringToFile(getExtension().getFiles().getDevLauncherConfig(), launchConfig.asString(), StandardCharsets.UTF_8);
|
||||||
FileUtils.writeStringToFile(getDirectories().getDevLauncherConfig(), launchConfig.asString(), StandardCharsets.UTF_8);
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
postPopulationScheduler.accept(this::writeRemapClassPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
private File getLog4jConfigFile() {
|
|
||||||
return getDirectories().getDefaultLog4jConfigFile();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getAllLog4JConfigFiles() {
|
private String getAllLog4JConfigFiles() {
|
||||||
|
@ -100,48 +79,6 @@ public class LaunchProvider extends DependencyProvider {
|
||||||
.collect(Collectors.joining(","));
|
.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());
|
|
||||||
|
|
||||||
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 {
|
public static class LaunchConfig {
|
||||||
private final Map<String, List<String>> values = new HashMap<>();
|
private final Map<String, List<String>> values = new HashMap<>();
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||||
*
|
*
|
||||||
* Copyright (c) 2018-2021 FabricMC
|
* Copyright (c) 2021 FabricMC
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
@ -22,20 +22,27 @@
|
||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package net.fabricmc.loom.configuration.providers;
|
package net.fabricmc.loom.task.launch;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftVersionMeta;
|
import org.gradle.api.tasks.TaskAction;
|
||||||
|
|
||||||
public interface MinecraftProvider {
|
import net.fabricmc.loom.task.AbstractLoomTask;
|
||||||
File workingDir();
|
|
||||||
|
|
||||||
File dir(String path);
|
public abstract class GenerateLog4jConfigTask extends AbstractLoomTask {
|
||||||
|
@TaskAction
|
||||||
|
public void run() {
|
||||||
|
Path outputFile = getExtension().getFiles().getDefaultLog4jConfigFile().toPath();
|
||||||
|
|
||||||
File file(String path);
|
try (InputStream is = GenerateLog4jConfigTask.class.getClassLoader().getResourceAsStream("log4j2.fabric.xml")) {
|
||||||
|
Files.deleteIfExists(outputFile);
|
||||||
String minecraftVersion();
|
Files.copy(is, outputFile);
|
||||||
|
} catch (IOException e) {
|
||||||
MinecraftVersionMeta getVersionInfo();
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -48,7 +48,7 @@ public class HashedDownloadUtil {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void downloadIfInvalid(URL from, File to, String expectedHash, Logger logger, boolean quiet, Runnable startDownload) throws IOException {
|
public static void downloadIfInvalid(URL from, File to, String expectedHash, Logger logger, boolean quiet, Runnable startDownload) throws IOException {
|
||||||
if (LoomGradlePlugin.refreshDeps) {
|
if (LoomGradlePlugin.refreshDeps && !Boolean.getBoolean("loom.refresh")) {
|
||||||
delete(to);
|
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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -183,8 +183,13 @@ public class SourceRemapper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m.getClassPath().add(extension.getMinecraftMappedProvider().getMappedJar().toPath());
|
for (Path intermediaryJar : extension.getMinecraftJars(MappingsNamespace.INTERMEDIARY)) {
|
||||||
m.getClassPath().add(extension.getMinecraftMappedProvider().getIntermediaryJar().toPath());
|
m.getClassPath().add(intermediaryJar);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Path intermediaryJar : extension.getMinecraftJars(MappingsNamespace.NAMED)) {
|
||||||
|
m.getClassPath().add(intermediaryJar);
|
||||||
|
}
|
||||||
|
|
||||||
Set<File> files = project.getConfigurations()
|
Set<File> files = project.getConfigurations()
|
||||||
.detachedConfiguration(project.getDependencies().create(Constants.Dependencies.JETBRAINS_ANNOTATIONS + Constants.Dependencies.Versions.JETBRAINS_ANNOTATIONS))
|
.detachedConfiguration(project.getDependencies().create(Constants.Dependencies.JETBRAINS_ANNOTATIONS + Constants.Dependencies.Versions.JETBRAINS_ANNOTATIONS))
|
||||||
|
|
|
@ -28,7 +28,7 @@ import org.gradle.util.GradleVersion
|
||||||
|
|
||||||
class LoomTestConstants {
|
class LoomTestConstants {
|
||||||
public final static String DEFAULT_GRADLE = GradleVersion.current().getVersion()
|
public final static String DEFAULT_GRADLE = GradleVersion.current().getVersion()
|
||||||
public final static String PRE_RELEASE_GRADLE = "7.5-20211228231407+0000"
|
public final static String PRE_RELEASE_GRADLE = "7.5-20220101231120+0000"
|
||||||
|
|
||||||
public final static String[] STANDARD_TEST_VERSIONS = [DEFAULT_GRADLE, PRE_RELEASE_GRADLE]
|
public final static String[] STANDARD_TEST_VERSIONS = [DEFAULT_GRADLE, PRE_RELEASE_GRADLE]
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,75 @@
|
||||||
|
/*
|
||||||
|
* 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.test.benchmark
|
||||||
|
|
||||||
|
import groovy.time.TimeCategory
|
||||||
|
import groovy.time.TimeDuration
|
||||||
|
import net.fabricmc.loom.test.LoomTestConstants
|
||||||
|
import net.fabricmc.loom.test.util.GradleProjectTestTrait
|
||||||
|
|
||||||
|
import static org.gradle.testkit.runner.TaskOutcome.SUCCESS
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run this class, passing a working dir as the first argument.
|
||||||
|
* Allow for one warm up run before profiling, follow up runs should not be using the network.
|
||||||
|
*/
|
||||||
|
@Singleton
|
||||||
|
class SimpleBenchmark implements GradleProjectTestTrait {
|
||||||
|
def run(File dir) {
|
||||||
|
// Forces loom to refresh files
|
||||||
|
System.setProperty("loom.refresh", "true")
|
||||||
|
|
||||||
|
def gradle = gradleProject(
|
||||||
|
project: "minimalBase",
|
||||||
|
version: LoomTestConstants.PRE_RELEASE_GRADLE,
|
||||||
|
projectDir: new File(dir, "project"),
|
||||||
|
gradleHomeDir: new File(dir, "gradlehome")
|
||||||
|
)
|
||||||
|
|
||||||
|
gradle.buildGradle << '''
|
||||||
|
dependencies {
|
||||||
|
minecraft "com.mojang:minecraft:1.18.1"
|
||||||
|
mappings "net.fabricmc:yarn:1.18.1+build.17:v2"
|
||||||
|
modImplementation "net.fabricmc.fabric-api:fabric-api:0.45.1+1.18"
|
||||||
|
}
|
||||||
|
'''
|
||||||
|
|
||||||
|
def timeStart = new Date()
|
||||||
|
|
||||||
|
def result = gradle.run(tasks: ["clean", "build"])
|
||||||
|
|
||||||
|
def timeStop = new Date()
|
||||||
|
TimeDuration duration = TimeCategory.minus(timeStop, timeStart)
|
||||||
|
println(duration)
|
||||||
|
|
||||||
|
assert result.task(":build").outcome == SUCCESS
|
||||||
|
|
||||||
|
System.exit(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
static void main(String[] args) {
|
||||||
|
getInstance().run(new File(args[0]))
|
||||||
|
}
|
||||||
|
}
|
|
@ -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.test.unit
|
||||||
|
|
||||||
|
import net.fabricmc.loom.configuration.providers.BundleMetadata
|
||||||
|
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftJarSplitter
|
||||||
|
import spock.lang.Specification
|
||||||
|
|
||||||
|
class MinecraftJarSplitterTest extends Specification {
|
||||||
|
public static final String CLIENT_JAR_URL = "https://launcher.mojang.com/v1/objects/7e46fb47609401970e2818989fa584fd467cd036/client.jar"
|
||||||
|
public static final String SERVER_BUNDLE_JAR_URL = "https://launcher.mojang.com/v1/objects/125e5adf40c659fd3bce3e66e67a16bb49ecc1b9/server.jar"
|
||||||
|
|
||||||
|
public static final File mcJarDir = File.createTempDir()
|
||||||
|
|
||||||
|
def "split jars"() {
|
||||||
|
given:
|
||||||
|
def clientJar = downloadJarIfNotExists(CLIENT_JAR_URL, "client.jar")
|
||||||
|
def serverBundleJar = downloadJarIfNotExists(SERVER_BUNDLE_JAR_URL, "server_bundle.jar")
|
||||||
|
def serverJar = new File(mcJarDir, "server.jar")
|
||||||
|
|
||||||
|
def clientOnlyJar = new File(mcJarDir, "client_only.jar")
|
||||||
|
def commonJar = new File(mcJarDir, "common.jar")
|
||||||
|
when:
|
||||||
|
def serverBundleMetadata = BundleMetadata.fromJar(serverBundleJar.toPath())
|
||||||
|
serverBundleMetadata.versions().find().unpackEntry(serverBundleJar.toPath(), serverJar.toPath())
|
||||||
|
|
||||||
|
clientOnlyJar.delete()
|
||||||
|
commonJar.delete()
|
||||||
|
|
||||||
|
new MinecraftJarSplitter(clientJar.toPath(), serverJar.toPath()).withCloseable {
|
||||||
|
it.split(clientOnlyJar.toPath(), commonJar.toPath())
|
||||||
|
}
|
||||||
|
then:
|
||||||
|
serverBundleMetadata.versions().size() == 1
|
||||||
|
}
|
||||||
|
|
||||||
|
File downloadJarIfNotExists(String url, String name) {
|
||||||
|
File dst = new File(mcJarDir, name)
|
||||||
|
|
||||||
|
if (!dst.exists()) {
|
||||||
|
dst.parentFile.mkdirs()
|
||||||
|
dst << new URL(url).newInputStream()
|
||||||
|
}
|
||||||
|
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
}
|
|
@ -25,7 +25,7 @@
|
||||||
package net.fabricmc.loom.test.unit.layeredmappings
|
package net.fabricmc.loom.test.unit.layeredmappings
|
||||||
|
|
||||||
import groovy.transform.CompileStatic
|
import groovy.transform.CompileStatic
|
||||||
import net.fabricmc.loom.configuration.providers.MinecraftProvider
|
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftProvider
|
||||||
import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingSpec
|
import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingSpec
|
||||||
import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingsProcessor
|
import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingsProcessor
|
||||||
import net.fabricmc.loom.api.mappings.layered.MappingContext
|
import net.fabricmc.loom.api.mappings.layered.MappingContext
|
||||||
|
|
|
@ -211,7 +211,7 @@ trait GradleProjectTestTrait {
|
||||||
}
|
}
|
||||||
|
|
||||||
File getGeneratedSources(String mappings) {
|
File getGeneratedSources(String mappings) {
|
||||||
return new File(getGradleHomeDir(), "caches/fabric-loom/${mappings}/minecraft-mapped-sources.jar")
|
return new File(getGradleHomeDir(), "caches/fabric-loom/${mappings}/minecraft-merged-named-sources.jar")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in a new issue